def critical(self):
        """Context manager that temporarily makes the caller critical.

        Testbenches and processes may be *background* or *critical*, where critical ones prevent
        :meth:`Simulator.run` from finishing. Processes are always created background, while
        testbenches are created critical by default, but may also be created background.
        This context manager makes the caller critical for the span of the :py:`with` statement.

        This may be useful in cases where an operation (for example, a bus transaction) takes
        multiple clock cycles to complete, and must be completed after starting, but the testbench
        or process performing it never finishes, always waiting for the next operation to arrive.
        In this case, the caller would elevate itself to become critical only for the duration of
        the operation itself using this context manager, for example: ::

            async def testbench_bus_transaction(ctx):
                # On every cycle, check whether the bus has an active transaction...
                async for clk_edge, rst_active, bus_active_value in ctx.tick().sample(bus.active):
                    if bus_active_value: # ... if it does...
                        with ctx.critical(): # ... make this testbench critical...
                            addr_value = ctx.get(bus.r_addr)
                            ctx.set(bus.r_data, ...) # ... perform the access...
                            await ctx.tick()
                            ctx.set(bus.done, 1)
                            await ctx.tick()
                            ctx.set(bus.done, 0) # ... and complete the transaction later.
                        # The `run()` method could return at this point, but not before.
        """
        try:
            old_critical, self._process.critical = self._process.critical, True
            yield
        finally:
            self._process.critical = old_critical
Context manager that temporarily makes the caller critical.

        Testbenches and processes may be *background* or *critical*, where critical ones prevent
        :meth:`Simulator.run` from finishing. Processes are always created background, while
        testbenches are created critical by default, but may also be created background.
        This context manager makes the caller critical for the span of the :py:`with` statement.

        This may be useful in cases where an operation (for example, a bus transaction) takes
        multiple clock cycles to complete, and must be completed after starting, but the testbench
        or process performing it never finishes, always waiting for the next operation to arrive.
        In this case, the caller would elevate itself to become critical only for the duration of
        the operation itself using this context manager, for example: ::

            async def testbench_bus_transaction(ctx):
                # On every cycle, check whether the bus has an active transaction...
                async for clk_edge, rst_active, bus_active_value in ctx.tick().sample(bus.active):
                    if bus_active_value: # ... if it does...
                        with ctx.critical(): # ... make this testbench critical...
                            addr_value = ctx.get(bus.r_addr)
                            ctx.set(bus.r_data, ...) # ... perform the access...
                            await ctx.tick()
                            ctx.set(bus.done, 1)
                            await ctx.tick()
                            ctx.set(bus.done, 0) # ... and complete the transaction later.
                        # The `run()` method could return at this point, but not before.
        
amaranth/sim/_async.py