Skip to content

Commit 3e1fab8

Browse files
encukoumiss-islington
authored andcommitted
pythongh-134160: Add more comments for the xxlimited module (pythonGH-140214)
(cherry picked from commit 18e4a89) Co-authored-by: Petr Viktorin <[email protected]>
1 parent 5ae4612 commit 3e1fab8

File tree

1 file changed

+53
-7
lines changed

1 file changed

+53
-7
lines changed

Modules/xxlimited.c

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@
1414
This module roughly corresponds to::
1515
1616
class Xxo:
17-
"""A class that explicitly stores attributes in an internal dict"""
17+
"""A class that explicitly stores attributes in an internal dict
18+
(to simulate custom attribute handling).
19+
"""
1820
1921
def __init__(self):
2022
# In the C class, "_x_attr" is not accessible from Python code
@@ -85,13 +87,16 @@ typedef struct {
8587
// Instance state
8688
typedef struct {
8789
PyObject_HEAD
88-
PyObject *x_attr; /* Attributes dictionary */
90+
PyObject *x_attr; /* Attributes dictionary.
91+
* May be NULL, which acts as an
92+
* empty dict.
93+
*/
8994
char x_buffer[BUFSIZE]; /* buffer for Py_buffer */
9095
Py_ssize_t x_exports; /* how many buffer are exported */
9196
} XxoObject;
9297

9398
#define XxoObject_CAST(op) ((XxoObject *)(op))
94-
// XXX: no good way to do this yet
99+
// TODO: full support for type-checking was added in 3.14 (Py_tp_token)
95100
// #define XxoObject_Check(v) Py_IS_TYPE(v, Xxo_Type)
96101

97102
static XxoObject *
@@ -112,8 +117,13 @@ newXxoObject(PyObject *module)
112117
return self;
113118
}
114119

115-
/* Xxo finalization */
120+
/* Xxo finalization.
121+
*
122+
* Types that store references to other PyObjects generally need to implement
123+
* the GC slots: traverse, clear, dealloc, and (optionally) finalize.
124+
*/
116125

126+
// traverse: Visit all references from an object, including its type
117127
static int
118128
Xxo_traverse(PyObject *op, visitproc visit, void *arg)
119129
{
@@ -126,6 +136,7 @@ Xxo_traverse(PyObject *op, visitproc visit, void *arg)
126136
return 0;
127137
}
128138

139+
// clear: drop references in order to break all reference cycles
129140
static int
130141
Xxo_clear(PyObject *op)
131142
{
@@ -134,13 +145,16 @@ Xxo_clear(PyObject *op)
134145
return 0;
135146
}
136147

148+
// finalize: like clear, but should leave the object in a consistent state.
149+
// Equivalent to `__del__` in Python.
137150
static void
138151
Xxo_finalize(PyObject *op)
139152
{
140153
XxoObject *self = XxoObject_CAST(op);
141154
Py_CLEAR(self->x_attr);
142155
}
143156

157+
// dealloc: drop all remaining references and free memory
144158
static void
145159
Xxo_dealloc(PyObject *self)
146160
{
@@ -155,6 +169,7 @@ Xxo_dealloc(PyObject *self)
155169

156170
/* Xxo attribute handling */
157171

172+
// Get an attribute.
158173
static PyObject *
159174
Xxo_getattro(PyObject *op, PyObject *name)
160175
{
@@ -168,9 +183,12 @@ Xxo_getattro(PyObject *op, PyObject *name)
168183
return NULL;
169184
}
170185
}
186+
// Fall back to generic implementation (this handles special attributes,
187+
// raising AttributeError, etc.)
171188
return PyObject_GenericGetAttr(op, name);
172189
}
173190

191+
// Set or delete an attribute.
174192
static int
175193
Xxo_setattro(PyObject *op, PyObject *name, PyObject *v)
176194
{
@@ -198,7 +216,9 @@ Xxo_setattro(PyObject *op, PyObject *name, PyObject *v)
198216
}
199217
}
200218

201-
/* Xxo methods */
219+
/* Xxo methods: C functions plus a PyMethodDef array that lists them and
220+
* specifies metadata.
221+
*/
202222

203223
static PyObject *
204224
Xxo_demo(PyObject *op, PyTypeObject *defining_class,
@@ -234,7 +254,10 @@ static PyMethodDef Xxo_methods[] = {
234254
{NULL, NULL} /* sentinel */
235255
};
236256

237-
/* Xxo buffer interface */
257+
/* Xxo buffer interface: C functions later referenced from PyType_Slot array.
258+
* Other interfaces (e.g. for sequence-like or number-like types) are defined
259+
* similarly.
260+
*/
238261

239262
static int
240263
Xxo_getbuffer(PyObject *op, Py_buffer *view, int flags)
@@ -300,6 +323,7 @@ static PyType_Spec Xxo_Type_spec = {
300323
/* Str type definition*/
301324

302325
static PyType_Slot Str_Type_slots[] = {
326+
// slots array intentionally kept empty
303327
{0, 0}, /* sentinel */
304328
};
305329

@@ -400,12 +424,32 @@ xx_modexec(PyObject *m)
400424
}
401425

402426
static PyModuleDef_Slot xx_slots[] = {
427+
428+
/* exec function to initialize the module (called as part of import
429+
* after the object was added to sys.modules)
430+
*/
403431
{Py_mod_exec, xx_modexec},
432+
433+
/* Signal that this module supports being loaded in multiple interpreters
434+
* with separate GILs (global interpreter locks).
435+
* See "Isolating Extension Modules" on how to prepare a module for this:
436+
* https://docs.python.org/3/howto/isolating-extensions.html
437+
*/
404438
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
439+
440+
/* Signal that this module does not rely on the GIL for its own needs.
441+
* Without this slot, free-threaded builds of CPython will enable
442+
* the GIL when this module is loaded.
443+
*/
405444
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
445+
406446
{0, NULL}
407447
};
408448

449+
// Module finalization: modules that hold references in their module state
450+
// need to implement the fullowing GC hooks. They're similar to the ones for
451+
// types (see "Xxo finalization").
452+
409453
static int
410454
xx_traverse(PyObject *module, visitproc visit, void *arg)
411455
{
@@ -444,7 +488,9 @@ static struct PyModuleDef xxmodule = {
444488
};
445489

446490

447-
/* Export function for the module (*must* be called PyInit_xx) */
491+
/* Export function for the module. *Must* be called PyInit_xx; usually it is
492+
* the only non-`static` object in a module definition.
493+
*/
448494

449495
PyMODINIT_FUNC
450496
PyInit_xxlimited(void)

0 commit comments

Comments
 (0)