Skip to content

Commit e9c7772

Browse files
gh-103092: Isolate _ctypes, part 1 (#103893)
Establish global state and port the following types to heap types: - DictRemover_Type - PyCArg_Type - PyCThunk_Type - PyCField_Type - StructParam_Type
1 parent 63842bd commit e9c7772

File tree

7 files changed

+229
-201
lines changed

7 files changed

+229
-201
lines changed

Modules/_ctypes/_ctypes.c

+100-65
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ bytes(cdata)
126126

127127
#include "pycore_long.h" // _PyLong_GetZero()
128128

129+
ctypes_state global_state;
130+
129131
PyObject *PyExc_ArgError = NULL;
130132

131133
/* This dict maps ctypes types to POINTER types */
@@ -150,13 +152,32 @@ typedef struct {
150152
PyObject *dict;
151153
} DictRemoverObject;
152154

155+
static int
156+
_DictRemover_traverse(DictRemoverObject *self, visitproc visit, void *arg)
157+
{
158+
Py_VISIT(Py_TYPE(self));
159+
Py_VISIT(self->key);
160+
Py_VISIT(self->dict);
161+
return 0;
162+
}
163+
164+
static int
165+
_DictRemover_clear(DictRemoverObject *self)
166+
{
167+
Py_CLEAR(self->key);
168+
Py_CLEAR(self->dict);
169+
return 0;
170+
}
171+
153172
static void
154173
_DictRemover_dealloc(PyObject *myself)
155174
{
175+
PyTypeObject *tp = Py_TYPE(myself);
156176
DictRemoverObject *self = (DictRemoverObject *)myself;
157-
Py_XDECREF(self->key);
158-
Py_XDECREF(self->dict);
159-
Py_TYPE(self)->tp_free(myself);
177+
PyObject_GC_UnTrack(myself);
178+
(void)_DictRemover_clear(self);
179+
tp->tp_free(myself);
180+
Py_DECREF(tp);
160181
}
161182

162183
static PyObject *
@@ -173,47 +194,23 @@ _DictRemover_call(PyObject *myself, PyObject *args, PyObject *kw)
173194
Py_RETURN_NONE;
174195
}
175196

176-
static PyTypeObject DictRemover_Type = {
177-
PyVarObject_HEAD_INIT(NULL, 0)
178-
"_ctypes.DictRemover", /* tp_name */
179-
sizeof(DictRemoverObject), /* tp_basicsize */
180-
0, /* tp_itemsize */
181-
_DictRemover_dealloc, /* tp_dealloc */
182-
0, /* tp_vectorcall_offset */
183-
0, /* tp_getattr */
184-
0, /* tp_setattr */
185-
0, /* tp_as_async */
186-
0, /* tp_repr */
187-
0, /* tp_as_number */
188-
0, /* tp_as_sequence */
189-
0, /* tp_as_mapping */
190-
0, /* tp_hash */
191-
_DictRemover_call, /* tp_call */
192-
0, /* tp_str */
193-
0, /* tp_getattro */
194-
0, /* tp_setattro */
195-
0, /* tp_as_buffer */
196-
/* XXX should participate in GC? */
197-
Py_TPFLAGS_DEFAULT, /* tp_flags */
198-
PyDoc_STR("deletes a key from a dictionary"), /* tp_doc */
199-
0, /* tp_traverse */
200-
0, /* tp_clear */
201-
0, /* tp_richcompare */
202-
0, /* tp_weaklistoffset */
203-
0, /* tp_iter */
204-
0, /* tp_iternext */
205-
0, /* tp_methods */
206-
0, /* tp_members */
207-
0, /* tp_getset */
208-
0, /* tp_base */
209-
0, /* tp_dict */
210-
0, /* tp_descr_get */
211-
0, /* tp_descr_set */
212-
0, /* tp_dictoffset */
213-
0, /* tp_init */
214-
0, /* tp_alloc */
215-
0, /* tp_new */
216-
0, /* tp_free */
197+
PyDoc_STRVAR(dictremover_doc, "deletes a key from a dictionary");
198+
199+
static PyType_Slot dictremover_slots[] = {
200+
{Py_tp_dealloc, _DictRemover_dealloc},
201+
{Py_tp_traverse, _DictRemover_traverse},
202+
{Py_tp_clear, _DictRemover_clear},
203+
{Py_tp_call, _DictRemover_call},
204+
{Py_tp_doc, (void *)dictremover_doc},
205+
{0, NULL},
206+
};
207+
208+
static PyType_Spec dictremover_spec = {
209+
.name = "_ctypes.DictRemover",
210+
.basicsize = sizeof(DictRemoverObject),
211+
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
212+
Py_TPFLAGS_IMMUTABLETYPE),
213+
.slots = dictremover_slots,
217214
};
218215

219216
int
@@ -224,7 +221,8 @@ PyDict_SetItemProxy(PyObject *dict, PyObject *key, PyObject *item)
224221
PyObject *proxy;
225222
int result;
226223

227-
obj = _PyObject_CallNoArgs((PyObject *)&DictRemover_Type);
224+
ctypes_state *st = GLOBAL_STATE();
225+
obj = _PyObject_CallNoArgs((PyObject *)st->DictRemover_Type);
228226
if (obj == NULL)
229227
return -1;
230228

@@ -415,23 +413,45 @@ typedef struct {
415413
PyObject *keep; // If set, a reference to the original CDataObject.
416414
} StructParamObject;
417415

416+
static int
417+
StructParam_traverse(StructParamObject *self, visitproc visit, void *arg)
418+
{
419+
Py_VISIT(Py_TYPE(self));
420+
return 0;
421+
}
422+
423+
static int
424+
StructParam_clear(StructParamObject *self)
425+
{
426+
Py_CLEAR(self->keep);
427+
return 0;
428+
}
418429

419430
static void
420431
StructParam_dealloc(PyObject *myself)
421432
{
422433
StructParamObject *self = (StructParamObject *)myself;
423-
Py_XDECREF(self->keep);
434+
PyTypeObject *tp = Py_TYPE(self);
435+
PyObject_GC_UnTrack(myself);
436+
(void)StructParam_clear(self);
424437
PyMem_Free(self->ptr);
425-
Py_TYPE(self)->tp_free(myself);
438+
tp->tp_free(myself);
439+
Py_DECREF(tp);
426440
}
427441

442+
static PyType_Slot structparam_slots[] = {
443+
{Py_tp_traverse, StructParam_traverse},
444+
{Py_tp_clear, StructParam_clear},
445+
{Py_tp_dealloc, StructParam_dealloc},
446+
{0, NULL},
447+
};
428448

429-
static PyTypeObject StructParam_Type = {
430-
PyVarObject_HEAD_INIT(NULL, 0)
431-
.tp_name = "_ctypes.StructParam_Type",
432-
.tp_basicsize = sizeof(StructParamObject),
433-
.tp_dealloc = StructParam_dealloc,
434-
.tp_flags = Py_TPFLAGS_DEFAULT,
449+
static PyType_Spec structparam_spec = {
450+
.name = "_ctypes.StructParam_Type",
451+
.basicsize = sizeof(StructParamObject),
452+
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE |
453+
Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_DISALLOW_INSTANTIATION),
454+
.slots = structparam_slots,
435455
};
436456

437457

@@ -460,7 +480,9 @@ StructUnionType_paramfunc(CDataObject *self)
460480
/* Create a Python object which calls PyMem_Free(ptr) in
461481
its deallocator. The object will be destroyed
462482
at _ctypes_callproc() cleanup. */
463-
obj = (&StructParam_Type)->tp_alloc(&StructParam_Type, 0);
483+
ctypes_state *st = GLOBAL_STATE();
484+
PyTypeObject *tp = st->StructParam_Type;
485+
obj = tp->tp_alloc(tp, 0);
464486
if (obj == NULL) {
465487
PyMem_Free(ptr);
466488
return NULL;
@@ -800,7 +822,8 @@ CDataType_from_param(PyObject *type, PyObject *value)
800822
if (res) {
801823
return Py_NewRef(value);
802824
}
803-
if (PyCArg_CheckExact(value)) {
825+
ctypes_state *st = GLOBAL_STATE();
826+
if (PyCArg_CheckExact(st, value)) {
804827
PyCArgObject *p = (PyCArgObject *)value;
805828
PyObject *ob = p->obj;
806829
const char *ob_name;
@@ -1683,7 +1706,8 @@ c_wchar_p_from_param(PyObject *type, PyObject *value)
16831706
return Py_NewRef(value);
16841707
}
16851708
}
1686-
if (PyCArg_CheckExact(value)) {
1709+
ctypes_state *st = GLOBAL_STATE();
1710+
if (PyCArg_CheckExact(st, value)) {
16871711
/* byref(c_char(...)) */
16881712
PyCArgObject *a = (PyCArgObject *)value;
16891713
StgDictObject *dict = PyObject_stgdict(a->obj);
@@ -1746,7 +1770,8 @@ c_char_p_from_param(PyObject *type, PyObject *value)
17461770
return Py_NewRef(value);
17471771
}
17481772
}
1749-
if (PyCArg_CheckExact(value)) {
1773+
ctypes_state *st = GLOBAL_STATE();
1774+
if (PyCArg_CheckExact(st, value)) {
17501775
/* byref(c_char(...)) */
17511776
PyCArgObject *a = (PyCArgObject *)value;
17521777
StgDictObject *dict = PyObject_stgdict(a->obj);
@@ -1847,7 +1872,8 @@ c_void_p_from_param(PyObject *type, PyObject *value)
18471872
return Py_NewRef(value);
18481873
}
18491874
/* byref(...) */
1850-
if (PyCArg_CheckExact(value)) {
1875+
ctypes_state *st = GLOBAL_STATE();
1876+
if (PyCArg_CheckExact(st, value)) {
18511877
/* byref(c_xxx()) */
18521878
PyCArgObject *a = (PyCArgObject *)value;
18531879
if (a->tag == 'P') {
@@ -5635,12 +5661,22 @@ _ctypes_add_types(PyObject *mod)
56355661
} \
56365662
} while (0)
56375663

5664+
#define CREATE_TYPE(MOD, TP, SPEC) do { \
5665+
PyObject *type = PyType_FromMetaclass(NULL, MOD, SPEC, NULL); \
5666+
if (type == NULL) { \
5667+
return -1; \
5668+
} \
5669+
TP = (PyTypeObject *)type; \
5670+
} while (0)
5671+
5672+
ctypes_state *st = GLOBAL_STATE();
5673+
56385674
/* Note:
56395675
ob_type is the metatype (the 'type'), defaults to PyType_Type,
56405676
tp_base is the base type, defaults to 'object' aka PyBaseObject_Type.
56415677
*/
5642-
TYPE_READY(&PyCArg_Type);
5643-
TYPE_READY(&PyCThunk_Type);
5678+
CREATE_TYPE(mod, st->PyCArg_Type, &carg_spec);
5679+
CREATE_TYPE(mod, st->PyCThunk_Type, &cthunk_spec);
56445680
TYPE_READY(&PyCData_Type);
56455681
/* StgDict is derived from PyDict_Type */
56465682
TYPE_READY_BASE(&PyCStgDict_Type, &PyDict_Type);
@@ -5673,17 +5709,15 @@ _ctypes_add_types(PyObject *mod)
56735709
* Simple classes
56745710
*/
56755711

5676-
/* PyCField_Type is derived from PyBaseObject_Type */
5677-
TYPE_READY(&PyCField_Type);
5712+
CREATE_TYPE(mod, st->PyCField_Type, &cfield_spec);
56785713

56795714
/*************************************************
56805715
*
56815716
* Other stuff
56825717
*/
56835718

5684-
DictRemover_Type.tp_new = PyType_GenericNew;
5685-
TYPE_READY(&DictRemover_Type);
5686-
TYPE_READY(&StructParam_Type);
5719+
CREATE_TYPE(mod, st->DictRemover_Type, &dictremover_spec);
5720+
CREATE_TYPE(mod, st->StructParam_Type, &structparam_spec);
56875721

56885722
#ifdef MS_WIN32
56895723
TYPE_READY_BASE(&PyComError_Type, (PyTypeObject*)PyExc_Exception);
@@ -5692,6 +5726,7 @@ _ctypes_add_types(PyObject *mod)
56925726
#undef TYPE_READY
56935727
#undef TYPE_READY_BASE
56945728
#undef MOD_ADD_TYPE
5729+
#undef CREATE_TYPE
56955730
return 0;
56965731
}
56975732

Modules/_ctypes/callbacks.c

+36-45
Original file line numberDiff line numberDiff line change
@@ -28,23 +28,11 @@
2828

2929
/**************************************************************/
3030

31-
static void
32-
CThunkObject_dealloc(PyObject *myself)
33-
{
34-
CThunkObject *self = (CThunkObject *)myself;
35-
PyObject_GC_UnTrack(self);
36-
Py_XDECREF(self->converters);
37-
Py_XDECREF(self->callable);
38-
Py_XDECREF(self->restype);
39-
if (self->pcl_write)
40-
Py_ffi_closure_free(self->pcl_write);
41-
PyObject_GC_Del(self);
42-
}
43-
4431
static int
4532
CThunkObject_traverse(PyObject *myself, visitproc visit, void *arg)
4633
{
4734
CThunkObject *self = (CThunkObject *)myself;
35+
Py_VISIT(Py_TYPE(self));
4836
Py_VISIT(self->converters);
4937
Py_VISIT(self->callable);
5038
Py_VISIT(self->restype);
@@ -61,36 +49,35 @@ CThunkObject_clear(PyObject *myself)
6149
return 0;
6250
}
6351

64-
PyTypeObject PyCThunk_Type = {
65-
PyVarObject_HEAD_INIT(NULL, 0)
66-
"_ctypes.CThunkObject",
67-
sizeof(CThunkObject), /* tp_basicsize */
68-
sizeof(ffi_type), /* tp_itemsize */
69-
CThunkObject_dealloc, /* tp_dealloc */
70-
0, /* tp_vectorcall_offset */
71-
0, /* tp_getattr */
72-
0, /* tp_setattr */
73-
0, /* tp_as_async */
74-
0, /* tp_repr */
75-
0, /* tp_as_number */
76-
0, /* tp_as_sequence */
77-
0, /* tp_as_mapping */
78-
0, /* tp_hash */
79-
0, /* tp_call */
80-
0, /* tp_str */
81-
0, /* tp_getattro */
82-
0, /* tp_setattro */
83-
0, /* tp_as_buffer */
84-
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
85-
PyDoc_STR("CThunkObject"), /* tp_doc */
86-
CThunkObject_traverse, /* tp_traverse */
87-
CThunkObject_clear, /* tp_clear */
88-
0, /* tp_richcompare */
89-
0, /* tp_weaklistoffset */
90-
0, /* tp_iter */
91-
0, /* tp_iternext */
92-
0, /* tp_methods */
93-
0, /* tp_members */
52+
static void
53+
CThunkObject_dealloc(PyObject *myself)
54+
{
55+
CThunkObject *self = (CThunkObject *)myself;
56+
PyTypeObject *tp = Py_TYPE(myself);
57+
PyObject_GC_UnTrack(self);
58+
(void)CThunkObject_clear(myself);
59+
if (self->pcl_write) {
60+
Py_ffi_closure_free(self->pcl_write);
61+
}
62+
PyObject_GC_Del(self);
63+
Py_DECREF(tp);
64+
}
65+
66+
static PyType_Slot cthunk_slots[] = {
67+
{Py_tp_doc, (void *)PyDoc_STR("CThunkObject")},
68+
{Py_tp_dealloc, CThunkObject_dealloc},
69+
{Py_tp_traverse, CThunkObject_traverse},
70+
{Py_tp_clear, CThunkObject_clear},
71+
{0, NULL},
72+
};
73+
74+
PyType_Spec cthunk_spec = {
75+
.name = "_ctypes.CThunkObject",
76+
.basicsize = sizeof(CThunkObject),
77+
.itemsize = sizeof(ffi_type),
78+
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
79+
Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
80+
.slots = cthunk_slots,
9481
};
9582

9683
/**************************************************************/
@@ -320,7 +307,8 @@ static CThunkObject* CThunkObject_new(Py_ssize_t nargs)
320307
CThunkObject *p;
321308
Py_ssize_t i;
322309

323-
p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nargs);
310+
ctypes_state *st = GLOBAL_STATE();
311+
p = PyObject_GC_NewVar(CThunkObject, st->PyCThunk_Type, nargs);
324312
if (p == NULL) {
325313
return NULL;
326314
}
@@ -357,7 +345,10 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
357345
if (p == NULL)
358346
return NULL;
359347

360-
assert(CThunk_CheckExact((PyObject *)p));
348+
#ifdef Py_DEBUG
349+
ctypes_state *st = GLOBAL_STATE();
350+
assert(CThunk_CheckExact(st, (PyObject *)p));
351+
#endif
361352

362353
p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec);
363354
if (p->pcl_write == NULL) {

0 commit comments

Comments
 (0)