Skip to content

Commit da8b793

Browse files
authored
Merge pull request #71 from DiamondLightSource/py3.11_fixes
Clean up the created threadstate
2 parents 4c75587 + e83c115 commit da8b793

File tree

3 files changed

+35
-1
lines changed

3 files changed

+35
-1
lines changed

context/_coroutine.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,11 @@ static void *coroutine_wrapper(void *action_, void *arg_)
107107
Py_DECREF(arg);
108108

109109

110-
#if PY_VERSION_HEX < 0x30B0000
110+
#if PY_VERSION_HEX >= 0x30B0000
111+
new_threadstate = PyThreadState_Swap(thread_state);
112+
PyThreadState_Clear(new_threadstate);
113+
PyThreadState_Delete(new_threadstate);
114+
#else
111115
/* Some of the stuff we've initialised can leak through, so far I've only
112116
* seen exc_type still set at this point, but maybe other fields can also
113117
* leak. Avoid a memory leak by making sure we're not holding onto these.

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ dev = [
3939
"sphinx-design",
4040
"tox-direct",
4141
"types-mock",
42+
"psutil",
4243
]
4344

4445
[project.scripts]

tests/test_cothread.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import multiprocessing as mp
44
import time
55

6+
import psutil
7+
68
# Add cothread onto file and import
79
import sys
810
import os
@@ -169,6 +171,33 @@ def target():
169171
after = time.time()
170172
assert float(after - before) > TIMEOUT
171173

174+
def test_threadstate_memory_leak():
175+
"""Test that the memory leak reported in issue #70 is fixed and does not
176+
reoccur"""
177+
178+
process = psutil.Process()
179+
180+
vms_start = process.memory_info().vms
181+
182+
def test():
183+
pass
184+
185+
# Arbitrary large number of spawns. On my machine with the memory leak
186+
# active,this results in a leak of approximately 2GiB.
187+
for i in range(500000):
188+
cothread.Spawn(test)
189+
cothread.Yield()
190+
191+
vms_end = process.memory_info().vms
192+
193+
print(f"VMS start {vms_start} end {vms_end} diff {vms_end-vms_start}")
194+
195+
memory_increase = vms_end - vms_start
196+
197+
# With the memory leak fixed, the memory increase on my machine is only
198+
# 16384 bytes. Added an order of magnitude for future safety.
199+
assert memory_increase < 200000
200+
172201

173202
if __name__ == '__main__':
174203
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)