Skip to content

Commit

Permalink
Switch KI protection default from "unprotected" to "protected"
Browse files Browse the repository at this point in the history
This is mostly motivated by wanting to allow guest-mode (gh-1551) to
use our KI handling, where the host loop will presumably not be using
any of our KI protection markers. But I figured I'd split it out into
a separate PR rather than mix changes to the tricky KI code together
with changes to the tricky core run loop.

No newsfragment because I don't think this change is observable by
users.
  • Loading branch information
njsmith committed Jun 1, 2020
1 parent e7d0571 commit 8d9effc
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 10 deletions.
14 changes: 9 additions & 5 deletions docs/source/reference-lowlevel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
2 changes: 1 addition & 1 deletion trio/_core/_ki.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down
1 change: 0 additions & 1 deletion trio/_core/_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 10 additions & 3 deletions trio/_core/tests/test_ki.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand All @@ -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():
Expand Down

0 comments on commit 8d9effc

Please sign in to comment.