Skip to content

Commit 383b32f

Browse files
authored
Revert "bpo-31356: Add context manager to temporarily disable GC GH-5495
This reverts commit 72a0d21. The reverted commit had a few issues so it was unanimously decided to undo it. See the bpo issue for details.
1 parent aa0735f commit 383b32f

File tree

6 files changed

+3
-216
lines changed

6 files changed

+3
-216
lines changed

Doc/library/gc.rst

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -33,34 +33,6 @@ The :mod:`gc` module provides the following functions:
3333
Disable automatic garbage collection.
3434

3535

36-
.. class:: ensure_disabled()
37-
38-
Return a context manager object that disables the garbage collector and reenables the previous
39-
state upon completion of the block. This is basically equivalent to::
40-
41-
from gc import enable, disable, isenabled
42-
43-
@contextmanager
44-
def ensure_disabled():
45-
was_enabled_previously = isenabled()
46-
gc.disable()
47-
yield
48-
if was_enabled_previously:
49-
gc.enable()
50-
51-
And lets you write code like this::
52-
53-
with ensure_disabled():
54-
run_some_timing()
55-
56-
with ensure_disabled():
57-
# do_something_that_has_real_time_guarantees
58-
# such as a pair trade, robotic braking, etc
59-
60-
without needing to explicitly enable and disable the garbage collector yourself.
61-
This context manager is implemented in C to assure atomicity, thread safety and speed.
62-
63-
6436
.. function:: isenabled()
6537

6638
Returns true if automatic collection is enabled.

Include/internal/mem.h

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

117117
int enabled;
118118
int debug;
119-
long disabled_threads;
120119
/* linked lists of container objects */
121120
struct gc_generation generations[NUM_GENERATIONS];
122121
PyGC_Head *generation0;

Lib/test/test_gc.py

Lines changed: 1 addition & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
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,reap_threads)
4+
temp_dir, requires_type_collecting)
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-
1412

1513
try:
1614
from _testcapi import with_tp_del
@@ -1009,73 +1007,6 @@ def __del__(self):
10091007
# empty __dict__.
10101008
self.assertEqual(x, None)
10111009

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-
10791010
def test_main():
10801011
enabled = gc.isenabled()
10811012
gc.disable()

Misc/NEWS.d/3.7.0b1.rst

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -196,17 +196,6 @@ by Sanyam Khurana.
196196

197197
..
198198
199-
.. bpo: 31356
200-
.. date: 2017-11-02-00-34-42
201-
.. nonce: 54Lb8U
202-
.. section: Core and Builtins
203-
204-
Add a new contextmanager to the gc module that temporarily disables the GC
205-
and restores the previous state. The implementation is done in C to assure
206-
atomicity and speed.
207-
208-
..
209-
210199
.. bpo: 31179
211200
.. date: 2017-08-10-17-32-48
212201
.. nonce: XcgLYI
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Remove the new API added in bpo-31356 (gc.ensure_disabled() context
2+
manager).

Modules/gcmodule.c

Lines changed: 0 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,10 +1067,6 @@ static PyObject *
10671067
gc_enable_impl(PyObject *module)
10681068
/*[clinic end generated code: output=45a427e9dce9155c input=81ac4940ca579707]*/
10691069
{
1070-
if(_PyRuntime.gc.disabled_threads){
1071-
PyErr_WarnEx(PyExc_RuntimeWarning, "Garbage collector enabled while another "
1072-
"thread is inside gc.ensure_enabled",1);
1073-
}
10741070
_PyRuntime.gc.enabled = 1;
10751071
Py_RETURN_NONE;
10761072
}
@@ -1512,102 +1508,6 @@ static PyMethodDef GcMethods[] = {
15121508
{NULL, NULL} /* Sentinel */
15131509
};
15141510

1515-
typedef struct {
1516-
PyObject_HEAD
1517-
int previous_gc_state;
1518-
} ensure_disabled_object;
1519-
1520-
1521-
static void
1522-
ensure_disabled_object_dealloc(ensure_disabled_object *m_obj)
1523-
{
1524-
Py_TYPE(m_obj)->tp_free((PyObject*)m_obj);
1525-
}
1526-
1527-
static PyObject *
1528-
ensure_disabled__enter__method(ensure_disabled_object *self, PyObject *args)
1529-
{
1530-
PyGILState_STATE gstate = PyGILState_Ensure();
1531-
++_PyRuntime.gc.disabled_threads;
1532-
self->previous_gc_state = _PyRuntime.gc.enabled;
1533-
gc_disable_impl(NULL);
1534-
PyGILState_Release(gstate);
1535-
Py_RETURN_NONE;
1536-
}
1537-
1538-
static PyObject *
1539-
ensure_disabled__exit__method(ensure_disabled_object *self, PyObject *args)
1540-
{
1541-
PyGILState_STATE gstate = PyGILState_Ensure();
1542-
--_PyRuntime.gc.disabled_threads;
1543-
if(self->previous_gc_state){
1544-
gc_enable_impl(NULL);
1545-
}else{
1546-
gc_disable_impl(NULL);
1547-
}
1548-
PyGILState_Release(gstate);
1549-
Py_RETURN_NONE;
1550-
}
1551-
1552-
1553-
1554-
static struct PyMethodDef ensure_disabled_object_methods[] = {
1555-
{"__enter__", (PyCFunction) ensure_disabled__enter__method, METH_NOARGS},
1556-
{"__exit__", (PyCFunction) ensure_disabled__exit__method, METH_VARARGS},
1557-
{NULL, NULL} /* sentinel */
1558-
};
1559-
1560-
static PyObject *
1561-
new_disabled_obj(PyTypeObject *type, PyObject *args, PyObject *kwdict){
1562-
ensure_disabled_object *self;
1563-
self = (ensure_disabled_object *)type->tp_alloc(type, 0);
1564-
return (PyObject *) self;
1565-
};
1566-
1567-
static PyTypeObject gc_ensure_disabled_type = {
1568-
PyVarObject_HEAD_INIT(NULL, 0)
1569-
"gc.ensure_disabled", /* tp_name */
1570-
sizeof(ensure_disabled_object), /* tp_size */
1571-
0, /* tp_itemsize */
1572-
/* methods */
1573-
(destructor) ensure_disabled_object_dealloc,/* tp_dealloc */
1574-
0, /* tp_print */
1575-
0, /* tp_getattr */
1576-
0, /* tp_setattr */
1577-
0, /* tp_reserved */
1578-
0, /* tp_repr */
1579-
0, /* tp_as_number */
1580-
0, /*tp_as_sequence*/
1581-
0, /*tp_as_mapping*/
1582-
0, /*tp_hash*/
1583-
0, /*tp_call*/
1584-
0, /*tp_str*/
1585-
PyObject_GenericGetAttr, /*tp_getattro*/
1586-
0, /*tp_setattro*/
1587-
0, /*tp_as_buffer*/
1588-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
1589-
0, /*tp_doc*/
1590-
0, /* tp_traverse */
1591-
0, /* tp_clear */
1592-
0, /* tp_richcompare */
1593-
0, /* tp_weaklistoffset */
1594-
0, /* tp_iter */
1595-
0, /* tp_iternext */
1596-
ensure_disabled_object_methods, /* tp_methods */
1597-
0, /* tp_members */
1598-
0, /* tp_getset */
1599-
0, /* tp_base */
1600-
0, /* tp_dict */
1601-
0, /* tp_descr_get */
1602-
0, /* tp_descr_set */
1603-
0, /* tp_dictoffset */
1604-
0, /* tp_init */
1605-
PyType_GenericAlloc, /* tp_alloc */
1606-
new_disabled_obj, /* tp_new */
1607-
PyObject_Del, /* tp_free */
1608-
};
1609-
1610-
16111511
static struct PyModuleDef gcmodule = {
16121512
PyModuleDef_HEAD_INIT,
16131513
"gc", /* m_name */
@@ -1648,12 +1548,6 @@ PyInit_gc(void)
16481548
if (PyModule_AddObject(m, "callbacks", _PyRuntime.gc.callbacks) < 0)
16491549
return NULL;
16501550

1651-
if (PyType_Ready(&gc_ensure_disabled_type) < 0)
1652-
return NULL;
1653-
if (PyModule_AddObject(m, "ensure_disabled", (PyObject*) &gc_ensure_disabled_type) < 0)
1654-
return NULL;
1655-
1656-
16571551
#define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) return NULL
16581552
ADD_INT(DEBUG_STATS);
16591553
ADD_INT(DEBUG_COLLECTABLE);

0 commit comments

Comments
 (0)