bpo-31356: Add context manager to temporarily disable GC (GH-4224) · pythoncapi/cpython@72a0d21 · GitHub
Skip to content

Commit 72a0d21

Browse files
pablogsalrhettinger
authored andcommitted
bpo-31356: Add context manager to temporarily disable GC (pythonGH-4224)
1 parent 0cd6bca commit 72a0d21

5 files changed

Lines changed: 208 additions & 1 deletion

File tree

Doc/library/gc.rst

Lines changed: 28 additions & 0 deletions

Include/internal/mem.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ struct _gc_runtime_state {
116116

117117
int enabled;
118118
int debug;
119+
long disabled_threads;
119120
/* linked lists of container objects */
120121
struct gc_generation generations[NUM_GENERATIONS];
121122
PyGC_Head *generation0;

Lib/test/test_gc.py

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
import unittest
22
from test.support import (verbose, refcount_test, run_unittest,
33
strip_python_stderr, cpython_only, start_threads,
4-
temp_dir, requires_type_collecting)
4+
temp_dir, requires_type_collecting,reap_threads)
55
from test.support.script_helper import assert_python_ok, make_script
66

77
import sys
88
import time
99
import gc
1010
import weakref
1111
import threading
12+
import warnings
13+
1214

1315
try:
1416
from _testcapi import with_tp_del
@@ -1007,6 +1009,73 @@ def __del__(self):
10071009
# empty __dict__.
10081010
self.assertEqual(x, None)
10091011

1012+
def test_ensure_disabled(self):
1013+
original_status = gc.isenabled()
1014+
1015+
with gc.ensure_disabled():
1016+
inside_status = gc.isenabled()
1017+
1018+
after_status = gc.isenabled()
1019+
self.assertEqual(original_status, True)
1020+
self.assertEqual(inside_status, False)
1021+
self.assertEqual(after_status, True)
1022+
1023+
def test_ensure_disabled_with_gc_disabled(self):
1024+
gc.disable()
1025+
1026+
original_status = gc.isenabled()
1027+
1028+
with gc.ensure_disabled():
1029+
inside_status = gc.isenabled()
1030+
1031+
after_status = gc.isenabled()
1032+
self.assertEqual(original_status, False)
1033+
self.assertEqual(inside_status, False)
1034+
self.assertEqual(after_status, False)
1035+
1036+
@reap_threads
1037+
def test_ensure_disabled_thread(self):
1038+
1039+
thread_original_status = None
1040+
thread_inside_status = None
1041+
thread_after_status = None
1042+
1043+
def disabling_thread():
1044+
nonlocal thread_original_status
1045+
nonlocal thread_inside_status
1046+
nonlocal thread_after_status
1047+
thread_original_status = gc.isenabled()
1048+
1049+
with gc.ensure_disabled():
1050+
time.sleep(0.01)
1051+
thread_inside_status = gc.isenabled()
1052+
1053+
thread_after_status = gc.isenabled()
1054+
1055+
original_status = gc.isenabled()
1056+
1057+
with warnings.catch_warnings(record=True) as w, gc.ensure_disabled():
1058+
inside_status_before_thread = gc.isenabled()
1059+
thread = threading.Thread(target=disabling_thread)
1060+
thread.start()
1061+
inside_status_after_thread = gc.isenabled()
1062+
1063+
after_status = gc.isenabled()
1064+
thread.join()
1065+
1066+
self.assertEqual(len(w), 1)
1067+
self.assertTrue(issubclass(w[-1].category, RuntimeWarning))
1068+
self.assertEqual("Garbage collector enabled while another thread is "
1069+
"inside gc.ensure_enabled", str(w[-1].message))
1070+
self.assertEqual(original_status, True)
1071+
self.assertEqual(inside_status_before_thread, False)
1072+
self.assertEqual(thread_original_status, False)
1073+
self.assertEqual(thread_inside_status, True)
1074+
self.assertEqual(thread_after_status, False)
1075+
self.assertEqual(inside_status_after_thread, False)
1076+
self.assertEqual(after_status, True)
1077+
1078+
10101079
def test_main():
10111080
enabled = gc.isenabled()
10121081
gc.disable()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Add a new contextmanager to the gc module that temporarily disables the GC
2+
and restores the previous state. The implementation is done in C to assure
3+
atomicity and speed.

Modules/gcmodule.c

Lines changed: 106 additions & 0 deletions

0 commit comments

Comments
 (0)