There are two main mechanisms to halt execution flow in a frame:
Pausing is generally only used for nested event loops (ie. synchronous print). All other types of halting should use freezing.
There are 4 lifecycle states defined:
Top level documents are frozen via PageMsg_SetPageFrozen message. This will freeze and entire frame tree.
Individual frames may be frozen via SetLifecycleState freezing only an individual frame. Subframes will need to be frozen independently with a separate IPC.
Frame freezing can also be initiated by the [Page Scheduler][#Page Scheduler] under certain conditions.
The Page Scheduler also generates frozen state transitions.
Note: These state transitions do not work correctly for OOPIFs because the information is not propagated to the entire frame tree.
It is desirable to move all of these transitions to the browser side.
In order to freeze a worker/worklet an implementation will pauses execution of all [pausable task queues][# Task Queues] and tne enters a nested event loop. Only the none pausable tasks will execute in the nested event loop. Explicitly the Internal Worker task queue will be used to resume the worker.
To freeze workers the Workers themselves are ExecutionContextLifecycleStateObservers and they listen to the kFrozen/kResume state of the owning execution context and then propagate that to their own execution context.