Skip to content

Commit e54e828

Browse files
gh-132776: Cleanup for XIBufferViewType (gh-132821)
* add notes * rename XIBufferViewObject to xibufferview * move memoryview XIData code to memoryobject.c
1 parent c9f3f5b commit e54e828

8 files changed

+339
-250
lines changed

Include/internal/pycore_interp_structs.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ extern "C" {
99

1010
#include "pycore_ast_state.h" // struct ast_state
1111
#include "pycore_llist.h" // struct llist_node
12+
#include "pycore_memoryobject.h" // struct _memoryobject_state
1213
#include "pycore_opcode_utils.h" // NUM_COMMON_CONSTANTS
1314
#include "pycore_pymath.h" // _PY_SHORT_FLOAT_REPR
1415
#include "pycore_structs.h" // PyHamtObject
@@ -912,9 +913,10 @@ struct _is {
912913
struct _dtoa_state dtoa;
913914
struct _py_func_state func_state;
914915
struct _py_code_state code_state;
915-
916916
struct _Py_dict_state dict_state;
917917
struct _Py_exc_state exc_state;
918+
struct _memoryobject_state memobj_state;
919+
918920
struct _Py_mem_interp_free_queue mem_free_queue;
919921

920922
struct ast_state ast;

Include/internal/pycore_memoryobject.h

+11
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,17 @@ extern "C" {
88
# error "this header requires Py_BUILD_CORE define"
99
#endif
1010

11+
struct _memoryobject_state {
12+
PyTypeObject *XIBufferViewType;
13+
};
14+
15+
extern PyStatus _PyMemoryView_InitTypes(PyInterpreterState *);
16+
extern void _PyMemoryView_FiniTypes(PyInterpreterState *);
17+
18+
// exported for _interpreters module
19+
PyAPI_FUNC(PyTypeObject *) _PyMemoryView_GetXIBuffewViewType(void);
20+
21+
1122
extern PyTypeObject _PyManagedBuffer_Type;
1223

1324
PyObject *

Modules/_interpreters_common.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
_RESOLVE_MODINIT_FUNC_NAME(NAME)
66

77

8+
#ifdef REGISTERS_HEAP_TYPES
89
static int
910
ensure_xid_class(PyTypeObject *cls, xidatafunc getdata)
1011
{
@@ -16,7 +17,6 @@ ensure_xid_class(PyTypeObject *cls, xidatafunc getdata)
1617
return _PyXIData_RegisterClass(&ctx, cls, getdata);
1718
}
1819

19-
#ifdef REGISTERS_HEAP_TYPES
2020
static int
2121
clear_xid_class(PyTypeObject *cls)
2222
{

Modules/_interpretersmodule.c

+8-244
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "pycore_code.h" // _PyCode_HAS_EXECUTORS()
1010
#include "pycore_crossinterp.h" // _PyXIData_t
1111
#include "pycore_interp.h" // _PyInterpreterState_IDIncref()
12+
#include "pycore_memoryobject.h" // _PyMemoryView_GetXIBuffewViewType()
1213
#include "pycore_modsupport.h" // _PyArg_BadArgument()
1314
#include "pycore_namespace.h" // _PyNamespace_New()
1415
#include "pycore_pybuffer.h" // _PyBuffer_ReleaseInInterpreterAndRawFree()
@@ -36,23 +37,6 @@ _get_current_interp(void)
3637
#define look_up_interp _PyInterpreterState_LookUpIDObject
3738

3839

39-
static PyObject *
40-
_get_current_module(void)
41-
{
42-
PyObject *name = PyUnicode_FromString(MODULE_NAME_STR);
43-
if (name == NULL) {
44-
return NULL;
45-
}
46-
PyObject *mod = PyImport_GetModule(name);
47-
Py_DECREF(name);
48-
if (mod == NULL) {
49-
return NULL;
50-
}
51-
assert(mod != Py_None);
52-
return mod;
53-
}
54-
55-
5640
static int
5741
is_running_main(PyInterpreterState *interp)
5842
{
@@ -71,204 +55,10 @@ is_running_main(PyInterpreterState *interp)
7155
}
7256

7357

74-
/* Cross-interpreter Buffer Views *******************************************/
75-
76-
// XXX Release when the original interpreter is destroyed.
77-
78-
typedef struct {
79-
PyObject base;
80-
Py_buffer *view;
81-
int64_t interpid;
82-
} XIBufferViewObject;
83-
84-
#define XIBufferViewObject_CAST(op) ((XIBufferViewObject *)(op))
85-
86-
static PyObject *
87-
xibufferview_from_buffer(PyTypeObject *cls, Py_buffer *view, int64_t interpid)
88-
{
89-
assert(interpid >= 0);
90-
91-
Py_buffer *copied = PyMem_RawMalloc(sizeof(Py_buffer));
92-
if (copied == NULL) {
93-
return NULL;
94-
}
95-
/* This steals the view->obj reference */
96-
*copied = *view;
97-
98-
XIBufferViewObject *self = PyObject_Malloc(sizeof(XIBufferViewObject));
99-
if (self == NULL) {
100-
PyMem_RawFree(copied);
101-
return NULL;
102-
}
103-
PyObject_Init(&self->base, cls);
104-
*self = (XIBufferViewObject){
105-
.base = self->base,
106-
.view = copied,
107-
.interpid = interpid,
108-
};
109-
return (PyObject *)self;
110-
}
111-
112-
static void
113-
xibufferview_dealloc(PyObject *op)
114-
{
115-
XIBufferViewObject *self = XIBufferViewObject_CAST(op);
116-
117-
if (self->view != NULL) {
118-
PyInterpreterState *interp =
119-
_PyInterpreterState_LookUpID(self->interpid);
120-
if (interp == NULL) {
121-
/* The interpreter is no longer alive. */
122-
PyErr_Clear();
123-
PyMem_RawFree(self->view);
124-
}
125-
else {
126-
if (_PyBuffer_ReleaseInInterpreterAndRawFree(interp,
127-
self->view) < 0)
128-
{
129-
// XXX Emit a warning?
130-
PyErr_Clear();
131-
}
132-
}
133-
}
134-
135-
PyTypeObject *tp = Py_TYPE(self);
136-
tp->tp_free(self);
137-
/* "Instances of heap-allocated types hold a reference to their type."
138-
* See: https://docs.python.org/3.11/howto/isolating-extensions.html#garbage-collection-protocol
139-
* See: https://docs.python.org/3.11/c-api/typeobj.html#c.PyTypeObject.tp_traverse
140-
*/
141-
// XXX Why don't we implement Py_TPFLAGS_HAVE_GC, e.g. Py_tp_traverse,
142-
// like we do for _abc._abc_data?
143-
Py_DECREF(tp);
144-
}
145-
146-
static int
147-
xibufferview_getbuf(PyObject *op, Py_buffer *view, int flags)
148-
{
149-
/* Only PyMemoryView_FromObject() should ever call this,
150-
via _memoryview_from_xid() below. */
151-
XIBufferViewObject *self = XIBufferViewObject_CAST(op);
152-
*view = *self->view;
153-
view->obj = op;
154-
// XXX Should we leave it alone?
155-
view->internal = NULL;
156-
return 0;
157-
}
158-
159-
static PyType_Slot XIBufferViewType_slots[] = {
160-
{Py_tp_dealloc, xibufferview_dealloc},
161-
{Py_bf_getbuffer, xibufferview_getbuf},
162-
// We don't bother with Py_bf_releasebuffer since we don't need it.
163-
{0, NULL},
164-
};
165-
166-
static PyType_Spec XIBufferViewType_spec = {
167-
.name = MODULE_NAME_STR ".CrossInterpreterBufferView",
168-
.basicsize = sizeof(XIBufferViewObject),
169-
.flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
170-
Py_TPFLAGS_DISALLOW_INSTANTIATION | Py_TPFLAGS_IMMUTABLETYPE),
171-
.slots = XIBufferViewType_slots,
172-
};
173-
174-
175-
static PyTypeObject * _get_current_xibufferview_type(void);
176-
177-
178-
struct xibuffer {
179-
Py_buffer view;
180-
int used;
181-
};
182-
183-
static PyObject *
184-
_memoryview_from_xid(_PyXIData_t *data)
185-
{
186-
assert(_PyXIData_DATA(data) != NULL);
187-
assert(_PyXIData_OBJ(data) == NULL);
188-
assert(_PyXIData_INTERPID(data) >= 0);
189-
struct xibuffer *view = (struct xibuffer *)_PyXIData_DATA(data);
190-
assert(!view->used);
191-
192-
PyTypeObject *cls = _get_current_xibufferview_type();
193-
if (cls == NULL) {
194-
return NULL;
195-
}
196-
197-
PyObject *obj = xibufferview_from_buffer(
198-
cls, &view->view, _PyXIData_INTERPID(data));
199-
if (obj == NULL) {
200-
return NULL;
201-
}
202-
PyObject *res = PyMemoryView_FromObject(obj);
203-
if (res == NULL) {
204-
Py_DECREF(obj);
205-
return NULL;
206-
}
207-
view->used = 1;
208-
return res;
209-
}
210-
211-
static void
212-
_pybuffer_shared_free(void* data)
213-
{
214-
struct xibuffer *view = (struct xibuffer *)data;
215-
if (!view->used) {
216-
PyBuffer_Release(&view->view);
217-
}
218-
PyMem_RawFree(data);
219-
}
220-
221-
static int
222-
_pybuffer_shared(PyThreadState *tstate, PyObject *obj, _PyXIData_t *data)
223-
{
224-
struct xibuffer *view = PyMem_RawMalloc(sizeof(struct xibuffer));
225-
if (view == NULL) {
226-
return -1;
227-
}
228-
view->used = 0;
229-
if (PyObject_GetBuffer(obj, &view->view, PyBUF_FULL_RO) < 0) {
230-
PyMem_RawFree(view);
231-
return -1;
232-
}
233-
_PyXIData_Init(data, tstate->interp, view, NULL, _memoryview_from_xid);
234-
data->free = _pybuffer_shared_free;
235-
return 0;
236-
}
237-
238-
static int
239-
register_memoryview_xid(PyObject *mod, PyTypeObject **p_state)
240-
{
241-
// XIBufferView
242-
assert(*p_state == NULL);
243-
PyTypeObject *cls = (PyTypeObject *)PyType_FromModuleAndSpec(
244-
mod, &XIBufferViewType_spec, NULL);
245-
if (cls == NULL) {
246-
return -1;
247-
}
248-
if (PyModule_AddType(mod, cls) < 0) {
249-
Py_DECREF(cls);
250-
return -1;
251-
}
252-
*p_state = cls;
253-
254-
// Register XID for the builtin memoryview type.
255-
if (ensure_xid_class(&PyMemoryView_Type, _pybuffer_shared) < 0) {
256-
return -1;
257-
}
258-
// We don't ever bother un-registering memoryview.
259-
260-
return 0;
261-
}
262-
263-
264-
26558
/* module state *************************************************************/
26659

26760
typedef struct {
26861
int _notused;
269-
270-
/* heap types */
271-
PyTypeObject *XIBufferViewType;
27262
} module_state;
27363

27464
static inline module_state *
@@ -280,51 +70,19 @@ get_module_state(PyObject *mod)
28070
return state;
28171
}
28272

283-
static module_state *
284-
_get_current_module_state(void)
285-
{
286-
PyObject *mod = _get_current_module();
287-
if (mod == NULL) {
288-
// XXX import it?
289-
PyErr_SetString(PyExc_RuntimeError,
290-
MODULE_NAME_STR " module not imported yet");
291-
return NULL;
292-
}
293-
module_state *state = get_module_state(mod);
294-
Py_DECREF(mod);
295-
return state;
296-
}
297-
29873
static int
29974
traverse_module_state(module_state *state, visitproc visit, void *arg)
30075
{
301-
/* heap types */
302-
Py_VISIT(state->XIBufferViewType);
303-
30476
return 0;
30577
}
30678

30779
static int
30880
clear_module_state(module_state *state)
30981
{
310-
/* heap types */
311-
Py_CLEAR(state->XIBufferViewType);
312-
31382
return 0;
31483
}
31584

31685

317-
static PyTypeObject *
318-
_get_current_xibufferview_type(void)
319-
{
320-
module_state *state = _get_current_module_state();
321-
if (state == NULL) {
322-
return NULL;
323-
}
324-
return state->XIBufferViewType;
325-
}
326-
327-
32886
/* Python code **************************************************************/
32987

33088
static const char *
@@ -1545,6 +1303,7 @@ module_exec(PyObject *mod)
15451303
{
15461304
PyInterpreterState *interp = PyInterpreterState_Get();
15471305
module_state *state = get_module_state(mod);
1306+
(void)state;
15481307

15491308
_PyXIData_lookup_context_t ctx;
15501309
if (_PyXIData_GetLookupContext(interp, &ctx) < 0) {
@@ -1576,9 +1335,14 @@ module_exec(PyObject *mod)
15761335
goto error;
15771336
}
15781337

1579-
if (register_memoryview_xid(mod, &state->XIBufferViewType) < 0) {
1338+
PyTypeObject *XIBufferViewType = _PyMemoryView_GetXIBuffewViewType();
1339+
if (XIBufferViewType == NULL) {
15801340
goto error;
15811341
}
1342+
if (PyModule_AddType(mod, XIBufferViewType) < 0) {
1343+
Py_DECREF(XIBufferViewType);
1344+
return -1;
1345+
}
15821346

15831347
return 0;
15841348

0 commit comments

Comments
 (0)