Skip to content

Commit 5d51c56

Browse files
committed
gh-3108: avoid materializing f_locals by using weakrefs to code objects instead
1 parent 2a66a0d commit 5d51c56

File tree

9 files changed

+126
-144
lines changed

9 files changed

+126
-144
lines changed

src/trio/_core/_generated_instrumentation.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@
33
# *************************************************************
44
from __future__ import annotations
55

6-
import sys
76
from typing import TYPE_CHECKING
87

9-
from ._ki import LOCALS_KEY_KI_PROTECTION_ENABLED
8+
from ._ki import enable_ki_protection
109
from ._run import GLOBAL_RUN_CONTEXT
1110

1211
if TYPE_CHECKING:
@@ -15,6 +14,7 @@
1514
__all__ = ["add_instrument", "remove_instrument"]
1615

1716

17+
@enable_ki_protection
1818
def add_instrument(instrument: Instrument) -> None:
1919
"""Start instrumenting the current run loop with the given instrument.
2020
@@ -24,13 +24,13 @@ def add_instrument(instrument: Instrument) -> None:
2424
If ``instrument`` is already active, does nothing.
2525
2626
"""
27-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
2827
try:
2928
return GLOBAL_RUN_CONTEXT.runner.instruments.add_instrument(instrument)
3029
except AttributeError:
3130
raise RuntimeError("must be called from async context") from None
3231

3332

33+
@enable_ki_protection
3434
def remove_instrument(instrument: Instrument) -> None:
3535
"""Stop instrumenting the current run loop with the given instrument.
3636
@@ -44,7 +44,6 @@ def remove_instrument(instrument: Instrument) -> None:
4444
deactivated.
4545
4646
"""
47-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
4847
try:
4948
return GLOBAL_RUN_CONTEXT.runner.instruments.remove_instrument(instrument)
5049
except AttributeError:

src/trio/_core/_generated_io_epoll.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import sys
77
from typing import TYPE_CHECKING
88

9-
from ._ki import LOCALS_KEY_KI_PROTECTION_ENABLED
9+
from ._ki import enable_ki_protection
1010
from ._run import GLOBAL_RUN_CONTEXT
1111

1212
if TYPE_CHECKING:
@@ -18,6 +18,7 @@
1818
__all__ = ["notify_closing", "wait_readable", "wait_writable"]
1919

2020

21+
@enable_ki_protection
2122
async def wait_readable(fd: int | _HasFileNo) -> None:
2223
"""Block until the kernel reports that the given object is readable.
2324
@@ -40,13 +41,13 @@ async def wait_readable(fd: int | _HasFileNo) -> None:
4041
if another task calls :func:`notify_closing` while this
4142
function is still working.
4243
"""
43-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
4444
try:
4545
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_readable(fd)
4646
except AttributeError:
4747
raise RuntimeError("must be called from async context") from None
4848

4949

50+
@enable_ki_protection
5051
async def wait_writable(fd: int | _HasFileNo) -> None:
5152
"""Block until the kernel reports that the given object is writable.
5253
@@ -59,13 +60,13 @@ async def wait_writable(fd: int | _HasFileNo) -> None:
5960
if another task calls :func:`notify_closing` while this
6061
function is still working.
6162
"""
62-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
6363
try:
6464
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_writable(fd)
6565
except AttributeError:
6666
raise RuntimeError("must be called from async context") from None
6767

6868

69+
@enable_ki_protection
6970
def notify_closing(fd: int | _HasFileNo) -> None:
7071
"""Notify waiters of the given object that it will be closed.
7172
@@ -91,7 +92,6 @@ def notify_closing(fd: int | _HasFileNo) -> None:
9192
step, so other tasks won't be able to tell what order they happened
9293
in anyway.
9394
"""
94-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
9595
try:
9696
return GLOBAL_RUN_CONTEXT.runner.io_manager.notify_closing(fd)
9797
except AttributeError:

src/trio/_core/_generated_io_kqueue.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import sys
77
from typing import TYPE_CHECKING, Callable, ContextManager
88

9-
from ._ki import LOCALS_KEY_KI_PROTECTION_ENABLED
9+
from ._ki import enable_ki_protection
1010
from ._run import GLOBAL_RUN_CONTEXT
1111

1212
if TYPE_CHECKING:
@@ -29,18 +29,19 @@
2929
]
3030

3131

32+
@enable_ki_protection
3233
def current_kqueue() -> select.kqueue:
3334
"""TODO: these are implemented, but are currently more of a sketch than
3435
anything real. See `#26
3536
<https://github.com/python-trio/trio/issues/26>`__.
3637
"""
37-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
3838
try:
3939
return GLOBAL_RUN_CONTEXT.runner.io_manager.current_kqueue()
4040
except AttributeError:
4141
raise RuntimeError("must be called from async context") from None
4242

4343

44+
@enable_ki_protection
4445
def monitor_kevent(
4546
ident: int,
4647
filter: int,
@@ -49,13 +50,13 @@ def monitor_kevent(
4950
anything real. See `#26
5051
<https://github.com/python-trio/trio/issues/26>`__.
5152
"""
52-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
5353
try:
5454
return GLOBAL_RUN_CONTEXT.runner.io_manager.monitor_kevent(ident, filter)
5555
except AttributeError:
5656
raise RuntimeError("must be called from async context") from None
5757

5858

59+
@enable_ki_protection
5960
async def wait_kevent(
6061
ident: int,
6162
filter: int,
@@ -65,7 +66,6 @@ async def wait_kevent(
6566
anything real. See `#26
6667
<https://github.com/python-trio/trio/issues/26>`__.
6768
"""
68-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
6969
try:
7070
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_kevent(
7171
ident,
@@ -76,6 +76,7 @@ async def wait_kevent(
7676
raise RuntimeError("must be called from async context") from None
7777

7878

79+
@enable_ki_protection
7980
async def wait_readable(fd: int | _HasFileNo) -> None:
8081
"""Block until the kernel reports that the given object is readable.
8182
@@ -98,13 +99,13 @@ async def wait_readable(fd: int | _HasFileNo) -> None:
9899
if another task calls :func:`notify_closing` while this
99100
function is still working.
100101
"""
101-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
102102
try:
103103
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_readable(fd)
104104
except AttributeError:
105105
raise RuntimeError("must be called from async context") from None
106106

107107

108+
@enable_ki_protection
108109
async def wait_writable(fd: int | _HasFileNo) -> None:
109110
"""Block until the kernel reports that the given object is writable.
110111
@@ -117,13 +118,13 @@ async def wait_writable(fd: int | _HasFileNo) -> None:
117118
if another task calls :func:`notify_closing` while this
118119
function is still working.
119120
"""
120-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
121121
try:
122122
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_writable(fd)
123123
except AttributeError:
124124
raise RuntimeError("must be called from async context") from None
125125

126126

127+
@enable_ki_protection
127128
def notify_closing(fd: int | _HasFileNo) -> None:
128129
"""Notify waiters of the given object that it will be closed.
129130
@@ -149,7 +150,6 @@ def notify_closing(fd: int | _HasFileNo) -> None:
149150
step, so other tasks won't be able to tell what order they happened
150151
in anyway.
151152
"""
152-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
153153
try:
154154
return GLOBAL_RUN_CONTEXT.runner.io_manager.notify_closing(fd)
155155
except AttributeError:

src/trio/_core/_generated_io_windows.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import sys
77
from typing import TYPE_CHECKING, ContextManager
88

9-
from ._ki import LOCALS_KEY_KI_PROTECTION_ENABLED
9+
from ._ki import enable_ki_protection
1010
from ._run import GLOBAL_RUN_CONTEXT
1111

1212
if TYPE_CHECKING:
@@ -32,6 +32,7 @@
3232
]
3333

3434

35+
@enable_ki_protection
3536
async def wait_readable(sock: _HasFileNo | int) -> None:
3637
"""Block until the kernel reports that the given object is readable.
3738
@@ -54,13 +55,13 @@ async def wait_readable(sock: _HasFileNo | int) -> None:
5455
if another task calls :func:`notify_closing` while this
5556
function is still working.
5657
"""
57-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
5858
try:
5959
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_readable(sock)
6060
except AttributeError:
6161
raise RuntimeError("must be called from async context") from None
6262

6363

64+
@enable_ki_protection
6465
async def wait_writable(sock: _HasFileNo | int) -> None:
6566
"""Block until the kernel reports that the given object is writable.
6667
@@ -73,13 +74,13 @@ async def wait_writable(sock: _HasFileNo | int) -> None:
7374
if another task calls :func:`notify_closing` while this
7475
function is still working.
7576
"""
76-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
7777
try:
7878
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_writable(sock)
7979
except AttributeError:
8080
raise RuntimeError("must be called from async context") from None
8181

8282

83+
@enable_ki_protection
8384
def notify_closing(handle: Handle | int | _HasFileNo) -> None:
8485
"""Notify waiters of the given object that it will be closed.
8586
@@ -105,33 +106,32 @@ def notify_closing(handle: Handle | int | _HasFileNo) -> None:
105106
step, so other tasks won't be able to tell what order they happened
106107
in anyway.
107108
"""
108-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
109109
try:
110110
return GLOBAL_RUN_CONTEXT.runner.io_manager.notify_closing(handle)
111111
except AttributeError:
112112
raise RuntimeError("must be called from async context") from None
113113

114114

115+
@enable_ki_protection
115116
def register_with_iocp(handle: int | CData) -> None:
116117
"""TODO: these are implemented, but are currently more of a sketch than
117118
anything real. See `#26
118119
<https://github.com/python-trio/trio/issues/26>`__ and `#52
119120
<https://github.com/python-trio/trio/issues/52>`__.
120121
"""
121-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
122122
try:
123123
return GLOBAL_RUN_CONTEXT.runner.io_manager.register_with_iocp(handle)
124124
except AttributeError:
125125
raise RuntimeError("must be called from async context") from None
126126

127127

128+
@enable_ki_protection
128129
async def wait_overlapped(handle_: int | CData, lpOverlapped: CData | int) -> object:
129130
"""TODO: these are implemented, but are currently more of a sketch than
130131
anything real. See `#26
131132
<https://github.com/python-trio/trio/issues/26>`__ and `#52
132133
<https://github.com/python-trio/trio/issues/52>`__.
133134
"""
134-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
135135
try:
136136
return await GLOBAL_RUN_CONTEXT.runner.io_manager.wait_overlapped(
137137
handle_,
@@ -141,6 +141,7 @@ async def wait_overlapped(handle_: int | CData, lpOverlapped: CData | int) -> ob
141141
raise RuntimeError("must be called from async context") from None
142142

143143

144+
@enable_ki_protection
144145
async def write_overlapped(
145146
handle: int | CData,
146147
data: Buffer,
@@ -151,7 +152,6 @@ async def write_overlapped(
151152
<https://github.com/python-trio/trio/issues/26>`__ and `#52
152153
<https://github.com/python-trio/trio/issues/52>`__.
153154
"""
154-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
155155
try:
156156
return await GLOBAL_RUN_CONTEXT.runner.io_manager.write_overlapped(
157157
handle,
@@ -162,6 +162,7 @@ async def write_overlapped(
162162
raise RuntimeError("must be called from async context") from None
163163

164164

165+
@enable_ki_protection
165166
async def readinto_overlapped(
166167
handle: int | CData,
167168
buffer: Buffer,
@@ -172,7 +173,6 @@ async def readinto_overlapped(
172173
<https://github.com/python-trio/trio/issues/26>`__ and `#52
173174
<https://github.com/python-trio/trio/issues/52>`__.
174175
"""
175-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
176176
try:
177177
return await GLOBAL_RUN_CONTEXT.runner.io_manager.readinto_overlapped(
178178
handle,
@@ -183,26 +183,26 @@ async def readinto_overlapped(
183183
raise RuntimeError("must be called from async context") from None
184184

185185

186+
@enable_ki_protection
186187
def current_iocp() -> int:
187188
"""TODO: these are implemented, but are currently more of a sketch than
188189
anything real. See `#26
189190
<https://github.com/python-trio/trio/issues/26>`__ and `#52
190191
<https://github.com/python-trio/trio/issues/52>`__.
191192
"""
192-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
193193
try:
194194
return GLOBAL_RUN_CONTEXT.runner.io_manager.current_iocp()
195195
except AttributeError:
196196
raise RuntimeError("must be called from async context") from None
197197

198198

199+
@enable_ki_protection
199200
def monitor_completion_key() -> ContextManager[tuple[int, UnboundedQueue[object]]]:
200201
"""TODO: these are implemented, but are currently more of a sketch than
201202
anything real. See `#26
202203
<https://github.com/python-trio/trio/issues/26>`__ and `#52
203204
<https://github.com/python-trio/trio/issues/52>`__.
204205
"""
205-
sys._getframe().f_locals[LOCALS_KEY_KI_PROTECTION_ENABLED] = True
206206
try:
207207
return GLOBAL_RUN_CONTEXT.runner.io_manager.monitor_completion_key()
208208
except AttributeError:

0 commit comments

Comments
 (0)