summaryrefslogtreecommitdiffstats
path: root/Modules/_ctypes
diff options
context:
space:
mode:
authorErlend E. Aasland <erlend.aasland@protonmail.com>2023-04-27 12:57:54 (GMT)
committerGitHub <noreply@github.com>2023-04-27 12:57:54 (GMT)
commite9c777208f83b9a78fcef1eb3c56e209e739ffc1 (patch)
tree87efa9e4e56262157356fe8bde75a9c0faa8fc88 /Modules/_ctypes
parent63842bd90793c693f56bd8aad710b5267d41cf6d (diff)
downloadcpython-e9c777208f83b9a78fcef1eb3c56e209e739ffc1.zip
cpython-e9c777208f83b9a78fcef1eb3c56e209e739ffc1.tar.gz
cpython-e9c777208f83b9a78fcef1eb3c56e209e739ffc1.tar.bz2
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
Diffstat (limited to 'Modules/_ctypes')
-rw-r--r--Modules/_ctypes/_ctypes.c165
-rw-r--r--Modules/_ctypes/callbacks.c81
-rw-r--r--Modules/_ctypes/callproc.c74
-rw-r--r--Modules/_ctypes/cfield.c67
-rw-r--r--Modules/_ctypes/ctypes.h23
-rw-r--r--Modules/_ctypes/stgdict.c12
6 files changed, 227 insertions, 195 deletions
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 6f92ca0..c7ed6bd 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -126,6 +126,8 @@ bytes(cdata)
#include "pycore_long.h" // _PyLong_GetZero()
+ctypes_state global_state;
+
PyObject *PyExc_ArgError = NULL;
/* This dict maps ctypes types to POINTER types */
@@ -150,13 +152,32 @@ typedef struct {
PyObject *dict;
} DictRemoverObject;
+static int
+_DictRemover_traverse(DictRemoverObject *self, visitproc visit, void *arg)
+{
+ Py_VISIT(Py_TYPE(self));
+ Py_VISIT(self->key);
+ Py_VISIT(self->dict);
+ return 0;
+}
+
+static int
+_DictRemover_clear(DictRemoverObject *self)
+{
+ Py_CLEAR(self->key);
+ Py_CLEAR(self->dict);
+ return 0;
+}
+
static void
_DictRemover_dealloc(PyObject *myself)
{
+ PyTypeObject *tp = Py_TYPE(myself);
DictRemoverObject *self = (DictRemoverObject *)myself;
- Py_XDECREF(self->key);
- Py_XDECREF(self->dict);
- Py_TYPE(self)->tp_free(myself);
+ PyObject_GC_UnTrack(myself);
+ (void)_DictRemover_clear(self);
+ tp->tp_free(myself);
+ Py_DECREF(tp);
}
static PyObject *
@@ -173,47 +194,23 @@ _DictRemover_call(PyObject *myself, PyObject *args, PyObject *kw)
Py_RETURN_NONE;
}
-static PyTypeObject DictRemover_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.DictRemover", /* tp_name */
- sizeof(DictRemoverObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- _DictRemover_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- _DictRemover_call, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
-/* XXX should participate in GC? */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- PyDoc_STR("deletes a key from a dictionary"), /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- 0, /* tp_free */
+PyDoc_STRVAR(dictremover_doc, "deletes a key from a dictionary");
+
+static PyType_Slot dictremover_slots[] = {
+ {Py_tp_dealloc, _DictRemover_dealloc},
+ {Py_tp_traverse, _DictRemover_traverse},
+ {Py_tp_clear, _DictRemover_clear},
+ {Py_tp_call, _DictRemover_call},
+ {Py_tp_doc, (void *)dictremover_doc},
+ {0, NULL},
+};
+
+static PyType_Spec dictremover_spec = {
+ .name = "_ctypes.DictRemover",
+ .basicsize = sizeof(DictRemoverObject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = dictremover_slots,
};
int
@@ -224,7 +221,8 @@ PyDict_SetItemProxy(PyObject *dict, PyObject *key, PyObject *item)
PyObject *proxy;
int result;
- obj = _PyObject_CallNoArgs((PyObject *)&DictRemover_Type);
+ ctypes_state *st = GLOBAL_STATE();
+ obj = _PyObject_CallNoArgs((PyObject *)st->DictRemover_Type);
if (obj == NULL)
return -1;
@@ -415,23 +413,45 @@ typedef struct {
PyObject *keep; // If set, a reference to the original CDataObject.
} StructParamObject;
+static int
+StructParam_traverse(StructParamObject *self, visitproc visit, void *arg)
+{
+ Py_VISIT(Py_TYPE(self));
+ return 0;
+}
+
+static int
+StructParam_clear(StructParamObject *self)
+{
+ Py_CLEAR(self->keep);
+ return 0;
+}
static void
StructParam_dealloc(PyObject *myself)
{
StructParamObject *self = (StructParamObject *)myself;
- Py_XDECREF(self->keep);
+ PyTypeObject *tp = Py_TYPE(self);
+ PyObject_GC_UnTrack(myself);
+ (void)StructParam_clear(self);
PyMem_Free(self->ptr);
- Py_TYPE(self)->tp_free(myself);
+ tp->tp_free(myself);
+ Py_DECREF(tp);
}
+static PyType_Slot structparam_slots[] = {
+ {Py_tp_traverse, StructParam_traverse},
+ {Py_tp_clear, StructParam_clear},
+ {Py_tp_dealloc, StructParam_dealloc},
+ {0, NULL},
+};
-static PyTypeObject StructParam_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- .tp_name = "_ctypes.StructParam_Type",
- .tp_basicsize = sizeof(StructParamObject),
- .tp_dealloc = StructParam_dealloc,
- .tp_flags = Py_TPFLAGS_DEFAULT,
+static PyType_Spec structparam_spec = {
+ .name = "_ctypes.StructParam_Type",
+ .basicsize = sizeof(StructParamObject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE |
+ Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_DISALLOW_INSTANTIATION),
+ .slots = structparam_slots,
};
@@ -460,7 +480,9 @@ StructUnionType_paramfunc(CDataObject *self)
/* Create a Python object which calls PyMem_Free(ptr) in
its deallocator. The object will be destroyed
at _ctypes_callproc() cleanup. */
- obj = (&StructParam_Type)->tp_alloc(&StructParam_Type, 0);
+ ctypes_state *st = GLOBAL_STATE();
+ PyTypeObject *tp = st->StructParam_Type;
+ obj = tp->tp_alloc(tp, 0);
if (obj == NULL) {
PyMem_Free(ptr);
return NULL;
@@ -800,7 +822,8 @@ CDataType_from_param(PyObject *type, PyObject *value)
if (res) {
return Py_NewRef(value);
}
- if (PyCArg_CheckExact(value)) {
+ ctypes_state *st = GLOBAL_STATE();
+ if (PyCArg_CheckExact(st, value)) {
PyCArgObject *p = (PyCArgObject *)value;
PyObject *ob = p->obj;
const char *ob_name;
@@ -1683,7 +1706,8 @@ c_wchar_p_from_param(PyObject *type, PyObject *value)
return Py_NewRef(value);
}
}
- if (PyCArg_CheckExact(value)) {
+ ctypes_state *st = GLOBAL_STATE();
+ if (PyCArg_CheckExact(st, value)) {
/* byref(c_char(...)) */
PyCArgObject *a = (PyCArgObject *)value;
StgDictObject *dict = PyObject_stgdict(a->obj);
@@ -1746,7 +1770,8 @@ c_char_p_from_param(PyObject *type, PyObject *value)
return Py_NewRef(value);
}
}
- if (PyCArg_CheckExact(value)) {
+ ctypes_state *st = GLOBAL_STATE();
+ if (PyCArg_CheckExact(st, value)) {
/* byref(c_char(...)) */
PyCArgObject *a = (PyCArgObject *)value;
StgDictObject *dict = PyObject_stgdict(a->obj);
@@ -1847,7 +1872,8 @@ c_void_p_from_param(PyObject *type, PyObject *value)
return Py_NewRef(value);
}
/* byref(...) */
- if (PyCArg_CheckExact(value)) {
+ ctypes_state *st = GLOBAL_STATE();
+ if (PyCArg_CheckExact(st, value)) {
/* byref(c_xxx()) */
PyCArgObject *a = (PyCArgObject *)value;
if (a->tag == 'P') {
@@ -5635,12 +5661,22 @@ _ctypes_add_types(PyObject *mod)
} \
} while (0)
+#define CREATE_TYPE(MOD, TP, SPEC) do { \
+ PyObject *type = PyType_FromMetaclass(NULL, MOD, SPEC, NULL); \
+ if (type == NULL) { \
+ return -1; \
+ } \
+ TP = (PyTypeObject *)type; \
+} while (0)
+
+ ctypes_state *st = GLOBAL_STATE();
+
/* Note:
ob_type is the metatype (the 'type'), defaults to PyType_Type,
tp_base is the base type, defaults to 'object' aka PyBaseObject_Type.
*/
- TYPE_READY(&PyCArg_Type);
- TYPE_READY(&PyCThunk_Type);
+ CREATE_TYPE(mod, st->PyCArg_Type, &carg_spec);
+ CREATE_TYPE(mod, st->PyCThunk_Type, &cthunk_spec);
TYPE_READY(&PyCData_Type);
/* StgDict is derived from PyDict_Type */
TYPE_READY_BASE(&PyCStgDict_Type, &PyDict_Type);
@@ -5673,17 +5709,15 @@ _ctypes_add_types(PyObject *mod)
* Simple classes
*/
- /* PyCField_Type is derived from PyBaseObject_Type */
- TYPE_READY(&PyCField_Type);
+ CREATE_TYPE(mod, st->PyCField_Type, &cfield_spec);
/*************************************************
*
* Other stuff
*/
- DictRemover_Type.tp_new = PyType_GenericNew;
- TYPE_READY(&DictRemover_Type);
- TYPE_READY(&StructParam_Type);
+ CREATE_TYPE(mod, st->DictRemover_Type, &dictremover_spec);
+ CREATE_TYPE(mod, st->StructParam_Type, &structparam_spec);
#ifdef MS_WIN32
TYPE_READY_BASE(&PyComError_Type, (PyTypeObject*)PyExc_Exception);
@@ -5692,6 +5726,7 @@ _ctypes_add_types(PyObject *mod)
#undef TYPE_READY
#undef TYPE_READY_BASE
#undef MOD_ADD_TYPE
+#undef CREATE_TYPE
return 0;
}
diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c
index bc87500..8e694ba 100644
--- a/Modules/_ctypes/callbacks.c
+++ b/Modules/_ctypes/callbacks.c
@@ -28,23 +28,11 @@
/**************************************************************/
-static void
-CThunkObject_dealloc(PyObject *myself)
-{
- CThunkObject *self = (CThunkObject *)myself;
- PyObject_GC_UnTrack(self);
- Py_XDECREF(self->converters);
- Py_XDECREF(self->callable);
- Py_XDECREF(self->restype);
- if (self->pcl_write)
- Py_ffi_closure_free(self->pcl_write);
- PyObject_GC_Del(self);
-}
-
static int
CThunkObject_traverse(PyObject *myself, visitproc visit, void *arg)
{
CThunkObject *self = (CThunkObject *)myself;
+ Py_VISIT(Py_TYPE(self));
Py_VISIT(self->converters);
Py_VISIT(self->callable);
Py_VISIT(self->restype);
@@ -61,36 +49,35 @@ CThunkObject_clear(PyObject *myself)
return 0;
}
-PyTypeObject PyCThunk_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.CThunkObject",
- sizeof(CThunkObject), /* tp_basicsize */
- sizeof(ffi_type), /* tp_itemsize */
- CThunkObject_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- PyDoc_STR("CThunkObject"), /* tp_doc */
- CThunkObject_traverse, /* tp_traverse */
- CThunkObject_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
+static void
+CThunkObject_dealloc(PyObject *myself)
+{
+ CThunkObject *self = (CThunkObject *)myself;
+ PyTypeObject *tp = Py_TYPE(myself);
+ PyObject_GC_UnTrack(self);
+ (void)CThunkObject_clear(myself);
+ if (self->pcl_write) {
+ Py_ffi_closure_free(self->pcl_write);
+ }
+ PyObject_GC_Del(self);
+ Py_DECREF(tp);
+}
+
+static PyType_Slot cthunk_slots[] = {
+ {Py_tp_doc, (void *)PyDoc_STR("CThunkObject")},
+ {Py_tp_dealloc, CThunkObject_dealloc},
+ {Py_tp_traverse, CThunkObject_traverse},
+ {Py_tp_clear, CThunkObject_clear},
+ {0, NULL},
+};
+
+PyType_Spec cthunk_spec = {
+ .name = "_ctypes.CThunkObject",
+ .basicsize = sizeof(CThunkObject),
+ .itemsize = sizeof(ffi_type),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
+ .slots = cthunk_slots,
};
/**************************************************************/
@@ -320,7 +307,8 @@ static CThunkObject* CThunkObject_new(Py_ssize_t nargs)
CThunkObject *p;
Py_ssize_t i;
- p = PyObject_GC_NewVar(CThunkObject, &PyCThunk_Type, nargs);
+ ctypes_state *st = GLOBAL_STATE();
+ p = PyObject_GC_NewVar(CThunkObject, st->PyCThunk_Type, nargs);
if (p == NULL) {
return NULL;
}
@@ -357,7 +345,10 @@ CThunkObject *_ctypes_alloc_callback(PyObject *callable,
if (p == NULL)
return NULL;
- assert(CThunk_CheckExact((PyObject *)p));
+#ifdef Py_DEBUG
+ ctypes_state *st = GLOBAL_STATE();
+ assert(CThunk_CheckExact(st, (PyObject *)p));
+#endif
p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec);
if (p->pcl_write == NULL) {
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index 4438727..93bc784 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -469,21 +469,41 @@ PyCArgObject *
PyCArgObject_new(void)
{
PyCArgObject *p;
- p = PyObject_New(PyCArgObject, &PyCArg_Type);
+ ctypes_state *st = GLOBAL_STATE();
+ p = PyObject_GC_New(PyCArgObject, st->PyCArg_Type);
if (p == NULL)
return NULL;
p->pffi_type = NULL;
p->tag = '\0';
p->obj = NULL;
memset(&p->value, 0, sizeof(p->value));
+ PyObject_GC_Track(p);
return p;
}
+static int
+PyCArg_traverse(PyCArgObject *self, visitproc visit, void *arg)
+{
+ Py_VISIT(Py_TYPE(self));
+ Py_VISIT(self->obj);
+ return 0;
+}
+
+static int
+PyCArg_clear(PyCArgObject *self)
+{
+ Py_CLEAR(self->obj);
+ return 0;
+}
+
static void
PyCArg_dealloc(PyCArgObject *self)
{
- Py_XDECREF(self->obj);
- PyObject_Free(self);
+ PyTypeObject *tp = Py_TYPE(self);
+ PyObject_GC_UnTrack(self);
+ (void)PyCArg_clear(self);
+ tp->tp_free((PyObject *)self);
+ Py_DECREF(tp);
}
static int
@@ -567,36 +587,21 @@ static PyMemberDef PyCArgType_members[] = {
{ NULL },
};
-PyTypeObject PyCArg_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "CArgObject",
- sizeof(PyCArgObject),
- 0,
- (destructor)PyCArg_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)PyCArg_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT, /* tp_flags */
- 0, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- PyCArgType_members, /* tp_members */
+static PyType_Slot carg_slots[] = {
+ {Py_tp_dealloc, PyCArg_dealloc},
+ {Py_tp_traverse, PyCArg_traverse},
+ {Py_tp_clear, PyCArg_clear},
+ {Py_tp_repr, PyCArg_repr},
+ {Py_tp_members, PyCArgType_members},
+ {0, NULL},
+};
+
+PyType_Spec carg_spec = {
+ .name = "_ctypes.CArgObject",
+ .basicsize = sizeof(PyCArgObject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
+ .slots = carg_slots,
};
/****************************************************************/
@@ -669,7 +674,8 @@ static int ConvParam(PyObject *obj, Py_ssize_t index, struct argument *pa)
return 0;
}
- if (PyCArg_CheckExact(obj)) {
+ ctypes_state *st = GLOBAL_STATE();
+ if (PyCArg_CheckExact(st, obj)) {
PyCArgObject *carg = (PyCArgObject *)obj;
pa->ffi_type = carg->pffi_type;
pa->keep = Py_NewRef(obj);
diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c
index 796a1be..128506a 100644
--- a/Modules/_ctypes/cfield.c
+++ b/Modules/_ctypes/cfield.c
@@ -61,7 +61,9 @@ PyCField_FromDesc(PyObject *desc, Py_ssize_t index,
#define CONT_BITFIELD 2
#define EXPAND_BITFIELD 3
- self = (CFieldObject *)PyCField_Type.tp_alloc((PyTypeObject *)&PyCField_Type, 0);
+ ctypes_state *st = GLOBAL_STATE();
+ PyTypeObject *tp = st->PyCField_Type;
+ self = (CFieldObject *)tp->tp_alloc(tp, 0);
if (self == NULL)
return NULL;
dict = PyType_stgdict(desc);
@@ -256,6 +258,7 @@ static PyGetSetDef PyCField_getset[] = {
static int
PyCField_traverse(CFieldObject *self, visitproc visit, void *arg)
{
+ Py_VISIT(Py_TYPE(self));
Py_VISIT(self->proto);
return 0;
}
@@ -270,9 +273,11 @@ PyCField_clear(CFieldObject *self)
static void
PyCField_dealloc(PyObject *self)
{
+ PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
- PyCField_clear((CFieldObject *)self);
+ (void)PyCField_clear((CFieldObject *)self);
Py_TYPE(self)->tp_free((PyObject *)self);
+ Py_DECREF(tp);
}
static PyObject *
@@ -296,46 +301,24 @@ PyCField_repr(CFieldObject *self)
return result;
}
-PyTypeObject PyCField_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.CField", /* tp_name */
- sizeof(CFieldObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- PyCField_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)PyCField_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- PyDoc_STR("Structure/Union member"), /* tp_doc */
- (traverseproc)PyCField_traverse, /* tp_traverse */
- (inquiry)PyCField_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- PyCField_getset, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- (descrgetfunc)PyCField_get, /* tp_descr_get */
- (descrsetfunc)PyCField_set, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
- 0, /* tp_free */
+static PyType_Slot cfield_slots[] = {
+ {Py_tp_dealloc, PyCField_dealloc},
+ {Py_tp_repr, PyCField_repr},
+ {Py_tp_doc, (void *)PyDoc_STR("Structure/Union member")},
+ {Py_tp_traverse, PyCField_traverse},
+ {Py_tp_clear, PyCField_clear},
+ {Py_tp_getset, PyCField_getset},
+ {Py_tp_descr_get, PyCField_get},
+ {Py_tp_descr_set, PyCField_set},
+ {0, NULL},
+};
+
+PyType_Spec cfield_spec = {
+ .name = "_ctypes.CField",
+ .basicsize = sizeof(CFieldObject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
+ .slots = cfield_slots,
};
diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h
index a7029b6..252d9da 100644
--- a/Modules/_ctypes/ctypes.h
+++ b/Modules/_ctypes/ctypes.h
@@ -32,6 +32,22 @@
#endif
#endif
+typedef struct {
+ PyTypeObject *DictRemover_Type;
+ PyTypeObject *PyCArg_Type;
+ PyTypeObject *PyCField_Type;
+ PyTypeObject *PyCThunk_Type;
+ PyTypeObject *StructParam_Type;
+} ctypes_state;
+
+extern ctypes_state global_state;
+
+#define GLOBAL_STATE() (&global_state)
+
+extern PyType_Spec carg_spec;
+extern PyType_Spec cfield_spec;
+extern PyType_Spec cthunk_spec;
+
typedef struct tagPyCArgObject PyCArgObject;
typedef struct tagCDataObject CDataObject;
typedef PyObject *(* GETFUNC)(void *, Py_ssize_t size);
@@ -88,8 +104,7 @@ typedef struct {
ffi_type *ffi_restype;
ffi_type *atypes[1];
} CThunkObject;
-extern PyTypeObject PyCThunk_Type;
-#define CThunk_CheckExact(v) Py_IS_TYPE(v, &PyCThunk_Type)
+#define CThunk_CheckExact(st, v) Py_IS_TYPE(v, st->PyCThunk_Type)
typedef struct {
/* First part identical to tagCDataObject */
@@ -141,7 +156,6 @@ extern PyTypeObject PyCSimpleType_Type;
#define PyCSimpleTypeObject_CheckExact(v) Py_IS_TYPE(v, &PyCSimpleType_Type)
#define PyCSimpleTypeObject_Check(v) PyObject_TypeCheck(v, &PyCSimpleType_Type)
-extern PyTypeObject PyCField_Type;
extern struct fielddesc *_ctypes_get_fielddesc(const char *fmt);
@@ -334,8 +348,7 @@ struct tagPyCArgObject {
Py_ssize_t size; /* for the 'V' tag */
};
-extern PyTypeObject PyCArg_Type;
-#define PyCArg_CheckExact(v) Py_IS_TYPE(v, &PyCArg_Type)
+#define PyCArg_CheckExact(st, v) Py_IS_TYPE(v, st->PyCArg_Type)
extern PyCArgObject *PyCArgObject_new(void);
extern PyObject *
diff --git a/Modules/_ctypes/stgdict.c b/Modules/_ctypes/stgdict.c
index 83a5275..b1b2bac 100644
--- a/Modules/_ctypes/stgdict.c
+++ b/Modules/_ctypes/stgdict.c
@@ -225,6 +225,8 @@ MakeFields(PyObject *type, CFieldObject *descr,
if (fieldlist == NULL)
return -1;
+ ctypes_state *st = GLOBAL_STATE();
+ PyTypeObject *cfield_tp = st->PyCField_Type;
for (i = 0; i < PySequence_Fast_GET_SIZE(fieldlist); ++i) {
PyObject *pair = PySequence_Fast_GET_ITEM(fieldlist, i); /* borrowed */
PyObject *fname, *ftype, *bits;
@@ -240,7 +242,7 @@ MakeFields(PyObject *type, CFieldObject *descr,
Py_DECREF(fieldlist);
return -1;
}
- if (!Py_IS_TYPE(fdescr, &PyCField_Type)) {
+ if (!Py_IS_TYPE(fdescr, cfield_tp)) {
PyErr_SetString(PyExc_TypeError, "unexpected type");
Py_DECREF(fdescr);
Py_DECREF(fieldlist);
@@ -257,13 +259,13 @@ MakeFields(PyObject *type, CFieldObject *descr,
}
continue;
}
- new_descr = (CFieldObject *)PyCField_Type.tp_alloc((PyTypeObject *)&PyCField_Type, 0);
+ new_descr = (CFieldObject *)cfield_tp->tp_alloc(cfield_tp, 0);
if (new_descr == NULL) {
Py_DECREF(fdescr);
Py_DECREF(fieldlist);
return -1;
}
- assert(Py_IS_TYPE(new_descr, &PyCField_Type));
+ assert(Py_IS_TYPE(new_descr, cfield_tp));
new_descr->size = fdescr->size;
new_descr->offset = fdescr->offset + offset;
new_descr->index = fdescr->index + index;
@@ -304,6 +306,8 @@ MakeAnonFields(PyObject *type)
if (anon_names == NULL)
return -1;
+ ctypes_state *st = GLOBAL_STATE();
+ PyTypeObject *cfield_tp = st->PyCField_Type;
for (i = 0; i < PySequence_Fast_GET_SIZE(anon_names); ++i) {
PyObject *fname = PySequence_Fast_GET_ITEM(anon_names, i); /* borrowed */
CFieldObject *descr = (CFieldObject *)PyObject_GetAttr(type, fname);
@@ -311,7 +315,7 @@ MakeAnonFields(PyObject *type)
Py_DECREF(anon_names);
return -1;
}
- if (!Py_IS_TYPE(descr, &PyCField_Type)) {
+ if (!Py_IS_TYPE(descr, cfield_tp)) {
PyErr_Format(PyExc_AttributeError,
"'%U' is specified in _anonymous_ but not in "
"_fields_",