diff --git a/docs/source/reference-lowlevel.rst b/docs/source/reference-lowlevel.rst index b196cd0b43..ef25e6cce4 100644 --- a/docs/source/reference-lowlevel.rst +++ b/docs/source/reference-lowlevel.rst @@ -295,11 +295,15 @@ delivered). So that's great, but – how do we know whether we're in one of the sensitive parts of the program or not? -This is determined on a function-by-function basis. By default, a -function is protected if its caller is, and not if its caller isn't; -this is helpful because it means you only need to override the -defaults at places where you transition from protected code to -unprotected code or vice-versa. +This is determined on a function-by-function basis. By default: + +- The top-level function in regular user tasks is unprotected. +- The top-level function in system tasks is protected. +- If a function doesn't specify otherwise, then it inherits the + protection state of its caller. + +This means you only need to override the defaults at places where you +transition from protected code to unprotected code or vice-versa. These transitions are accomplished using two function decorators: diff --git a/trio/_core/_ki.py b/trio/_core/_ki.py index d5aa63f5d9..ec22ff5fb6 100644 --- a/trio/_core/_ki.py +++ b/trio/_core/_ki.py @@ -90,7 +90,7 @@ def ki_protection_enabled(frame): if frame.f_code.co_name == "__del__": return True frame = frame.f_back - return False + return True def currently_ki_protected(): diff --git a/trio/_core/_run.py b/trio/_core/_run.py index 4de4e9a2bf..b6c5e19647 100644 --- a/trio/_core/_run.py +++ b/trio/_core/_run.py @@ -1678,7 +1678,6 @@ def run( system_context=system_context, ) GLOBAL_RUN_CONTEXT.runner = runner - locals()[LOCALS_KEY_KI_PROTECTION_ENABLED] = True # KI handling goes outside the core try/except/finally to avoid a window # where KeyboardInterrupt would be allowed and converted into an diff --git a/trio/_core/tests/test_ki.py b/trio/_core/tests/test_ki.py index 51b60aebbf..0e4db4af49 100644 --- a/trio/_core/tests/test_ki.py +++ b/trio/_core/tests/test_ki.py @@ -222,8 +222,8 @@ async def agen_unprotected3(): # Test the case where there's no magic local anywhere in the call stack -def test_ki_enabled_out_of_context(): - assert not _core.currently_ki_protected() +def test_ki_disabled_out_of_context(): + assert _core.currently_ki_protected() def test_ki_disabled_in_del(): @@ -234,8 +234,15 @@ def __del__(): assert _core.currently_ki_protected() assert nestedfunction() + @_core.disable_ki_protection + def outerfunction(): + assert not _core.currently_ki_protected() + assert not nestedfunction() + __del__() + __del__() - assert not nestedfunction() + outerfunction() + assert nestedfunction() def test_ki_protection_works():