bpo-31356: Add context manager to temporarily disable GC (GH-4224) · python/cpython@72a0d21 (original) (raw)
`@@ -1067,6 +1067,10 @@ static PyObject *
`
1067
1067
`gc_enable_impl(PyObject *module)
`
1068
1068
`/[clinic end generated code: output=45a427e9dce9155c input=81ac4940ca579707]/
`
1069
1069
`{
`
``
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
`+
}
`
1070
1074
`_PyRuntime.gc.enabled = 1;
`
1071
1075
`Py_RETURN_NONE;
`
1072
1076
`}
`
`@@ -1508,6 +1512,102 @@ static PyMethodDef GcMethods[] = {
`
1508
1512
` {NULL, NULL} /* Sentinel */
`
1509
1513
`};
`
1510
1514
``
``
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
+
1511
1611
`static struct PyModuleDef gcmodule = {
`
1512
1612
`PyModuleDef_HEAD_INIT,
`
1513
1613
`"gc", /* m_name */
`
`@@ -1548,6 +1648,12 @@ PyInit_gc(void)
`
1548
1648
`if (PyModule_AddObject(m, "callbacks", _PyRuntime.gc.callbacks) < 0)
`
1549
1649
`return NULL;
`
1550
1650
``
``
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
+
1551
1657
`#define ADD_INT(NAME) if (PyModule_AddIntConstant(m, #NAME, NAME) < 0) return NULL
`
1552
1658
`ADD_INT(DEBUG_STATS);
`
1553
1659
`ADD_INT(DEBUG_COLLECTABLE);
`