From 4e2ceded9a60bad12baa78721a8cf02d28a246a4 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sun, 14 Apr 2024 22:35:26 +0900 Subject: [PATCH 01/10] globals-to-fix.tsv --- Tools/c-analyzer/cpython/globals-to-fix.tsv | 2 -- 1 file changed, 2 deletions(-) diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 65f94e50e1bd7d..6a62773e8ffc1e 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -447,7 +447,6 @@ Modules/_tkinter.c - trbInCmd - ## other Include/datetime.h - PyDateTimeAPI - Modules/_ctypes/cfield.c _ctypes_get_fielddesc initialized - -Modules/_ctypes/malloc_closure.c - _pagesize - Modules/_cursesmodule.c - initialised - Modules/_cursesmodule.c - initialised_setupterm - Modules/_cursesmodule.c - initialisedcolors - @@ -461,7 +460,6 @@ Modules/readline.c - libedit_history_start - ## state Modules/_ctypes/cfield.c - formattable - -Modules/_ctypes/malloc_closure.c - free_list - Modules/_curses_panel.c - lop - Modules/_ssl/debughelpers.c _PySSL_keylog_callback lock - Modules/_tkinter.c - quitMainLoop - From 9abc28c634b383171fddc4e0030e6c3ea1d8cfb8 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sun, 14 Apr 2024 22:38:08 +0900 Subject: [PATCH 02/10] introduce _PyType_GetModule() --- Include/internal/pycore_typeobject.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index 09c4501c38c935..cd031d030daf9b 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -136,6 +136,17 @@ _PyStaticType_GET_WEAKREFS_LISTPTR(static_builtin_state *state) return &state->tp_weaklist; } +/* Like PyType_GetModule, but skips verification + * that type is a heap type */ +static inline PyObject * +_PyType_GetModule(PyTypeObject *type) +{ + assert(PyType_Check(type)); + assert(type->tp_flags & Py_TPFLAGS_HEAPTYPE); + PyHeapTypeObject *et = (PyHeapTypeObject *)type; + return et->ht_module; +} + /* Like PyType_GetModuleState, but skips verification * that type is a heap type with an associated module */ static inline void * From 5767566d9358c6e70bd3e23acb21ba714408d22f Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sun, 14 Apr 2024 23:01:31 +0900 Subject: [PATCH 03/10] move free_list to module state --- Modules/_ctypes/_ctypes.c | 2 + Modules/_ctypes/callbacks.c | 8 ++- Modules/_ctypes/callproc.c | 10 +++- Modules/_ctypes/ctypes.h | 28 +++++++++-- Modules/_ctypes/malloc_closure.c | 86 ++++++++++++++++++++++---------- 5 files changed, 101 insertions(+), 33 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 3cb0b24668eb2a..9969c65f5b8d2a 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -5936,6 +5936,8 @@ module_clear(PyObject *module) { Py_CLEAR(st->PyComError_Type); #endif Py_CLEAR(st->PyCType_Type); + clear_malloc_closure_free_list(st); + memset(&st->malloc_closure, 0, sizeof(malloc_closure_state)); return 0; } diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index 7b9f6437c7d55f..5cf7f0af80279f 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -56,7 +56,11 @@ CThunkObject_dealloc(PyObject *myself) PyObject_GC_UnTrack(self); (void)CThunkObject_clear(myself); if (self->pcl_write) { - Py_ffi_closure_free(self->pcl_write); + PyObject *module = _PyType_GetModule(tp); + if (module) { + ctypes_state *st = _PyModule_GetState(module); + Py_ffi_closure_free(st, self->pcl_write); + } } PyObject_GC_Del(self); Py_DECREF(tp); @@ -364,7 +368,7 @@ CThunkObject *_ctypes_alloc_callback(ctypes_state *st, assert(CThunk_CheckExact(st, (PyObject *)p)); - p->pcl_write = Py_ffi_closure_alloc(sizeof(ffi_closure), &p->pcl_exec); + p->pcl_write = Py_ffi_closure_alloc(st, sizeof(ffi_closure), &p->pcl_exec); if (p->pcl_write == NULL) { PyErr_NoMemory(); goto error; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index cbed2f32caa6c4..ecab2992b0d9e7 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -2063,7 +2063,12 @@ buffer_info(PyObject *self, PyObject *arg) return Py_BuildValue("siN", info->format, info->ndim, shape); } - +static PyObject * +get_malloc_closure_narenas(PyObject *self, PyObject *args) +{ + ctypes_state *st = get_module_state(self); + return PyLong_FromSsize_t(st->malloc_closure.narenas); +} PyMethodDef _ctypes_module_methods[] = { {"get_errno", get_errno, METH_NOARGS}, @@ -2099,6 +2104,9 @@ PyMethodDef _ctypes_module_methods[] = { {"PyObj_FromPtr", My_PyObj_FromPtr, METH_VARARGS }, {"Py_INCREF", My_Py_INCREF, METH_O }, {"Py_DECREF", My_Py_DECREF, METH_O }, +#ifdef Py_DEBUG + {"_get_ffi_closure_containers_count", get_malloc_closure_narenas, METH_NOARGS}, +#endif {NULL, NULL} /* Sentinel */ }; diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 20c68134be2804..71b17918fece58 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -39,6 +39,24 @@ #include // for IUnknown interface #endif +typedef union _tagITEM { + ffi_closure closure; + union _tagITEM *next; +} malloc_closure_item; + +typedef struct _tag_arena { + struct _tag_arena *prev_arena; + malloc_closure_item items[1]; +} malloc_closure_arena; + +typedef struct { + int pagesize; + malloc_closure_item *free_list; + malloc_closure_arena *last_arena; + Py_ssize_t arena_size; + Py_ssize_t narenas; +} malloc_closure_state; + typedef struct { PyTypeObject *DictRemover_Type; PyTypeObject *PyCArg_Type; @@ -71,6 +89,7 @@ typedef struct { PyObject *error_object_name; // callproc.c PyObject *PyExc_ArgError; PyObject *swapped_suffix; + malloc_closure_state malloc_closure; } ctypes_state; @@ -450,12 +469,13 @@ extern int _ctypes_simple_instance(ctypes_state *st, PyObject *obj); PyObject *_ctypes_get_errobj(ctypes_state *st, int **pspace); #ifdef USING_MALLOC_CLOSURE_DOT_C -void Py_ffi_closure_free(void *p); -void *Py_ffi_closure_alloc(size_t size, void** codeloc); +void Py_ffi_closure_free(ctypes_state *st, void *p); +void *Py_ffi_closure_alloc(ctypes_state *st, size_t size, void** codeloc); #else -#define Py_ffi_closure_free ffi_closure_free -#define Py_ffi_closure_alloc ffi_closure_alloc +#define Py_ffi_closure_free(st, p) ffi_closure_free(p) +#define Py_ffi_closure_alloc(st, size, codeloc) ffi_closure_alloc(size, codeloc) #endif +void clear_malloc_closure_free_list(ctypes_state *st); /**************************************************************** diff --git a/Modules/_ctypes/malloc_closure.c b/Modules/_ctypes/malloc_closure.c index bb4f8f21bd3f77..30f68a4cb7c48f 100644 --- a/Modules/_ctypes/malloc_closure.c +++ b/Modules/_ctypes/malloc_closure.c @@ -27,18 +27,15 @@ /******************************************************************/ -typedef union _tagITEM { - ffi_closure closure; - union _tagITEM *next; -} ITEM; +typedef malloc_closure_item ITEM; +typedef malloc_closure_arena ARENA; -static ITEM *free_list; -static int _pagesize; - -static void more_core(void) +static void +more_core(malloc_closure_state *st) { ITEM *item; int count, i; + int _pagesize = st->pagesize; /* determine the pagesize */ #ifdef MS_WIN32 @@ -56,45 +53,74 @@ static void more_core(void) #endif } #endif + st->pagesize = _pagesize; /* calculate the number of nodes to allocate */ - count = BLOCKSIZE / sizeof(ITEM); + count = (BLOCKSIZE - sizeof(ARENA *)) / sizeof(ITEM); + if (count <= 0) { + return; + } + st->arena_size = sizeof(ARENA *) + count * sizeof(ITEM); /* allocate a memory block */ #ifdef MS_WIN32 - item = (ITEM *)VirtualAlloc(NULL, - count * sizeof(ITEM), + ARENA *arena = (ARENA *)VirtualAlloc(NULL, + st->arena_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE); - if (item == NULL) + if (arena == NULL) return; #else - item = (ITEM *)mmap(NULL, - count * sizeof(ITEM), + ARENA *arena = (ARENA *)mmap(NULL, + st->arena_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (item == (void *)MAP_FAILED) + if (arena == (void *)MAP_FAILED) return; #endif + arena->prev_arena = st->last_arena; + st->last_arena = arena; + ++st->narenas; + item = arena->items; + #ifdef MALLOC_CLOSURE_DEBUG printf("block at %p allocated (%d bytes), %d ITEMs\n", item, count * (int)sizeof(ITEM), count); #endif /* put them into the free list */ for (i = 0; i < count; ++i) { - item->next = free_list; - free_list = item; + item->next = st->free_list; + st->free_list = item; ++item; } } +void +clear_malloc_closure_free_list(ctypes_state *state) +{ + malloc_closure_state *st = &state->malloc_closure; + while (st->narenas > 0) { + ARENA *arena = st->last_arena; + assert(arena != NULL); + st->last_arena = arena->prev_arena; +#ifdef MS_WIN32 + VirtualFree(arena, 0, MEM_RELEASE); +#else + munmap(arena, st->arena_size); +#endif + st->narenas--; + } + assert(st->last_arena == NULL); +} + /******************************************************************/ /* put the item back into the free list */ -void Py_ffi_closure_free(void *p) +void +Py_ffi_closure_free(ctypes_state *state, void *p) { #ifdef HAVE_FFI_CLOSURE_ALLOC #ifdef USING_APPLE_OS_LIBFFI @@ -110,13 +136,18 @@ void Py_ffi_closure_free(void *p) } #endif #endif + malloc_closure_state *st = &state->malloc_closure; + if (st->narenas <= 0) { + return; + } ITEM *item = (ITEM *)p; - item->next = free_list; - free_list = item; + item->next = st->free_list; + st->free_list = item; } /* return one item from the free list, allocating more if needed */ -void *Py_ffi_closure_alloc(size_t size, void** codeloc) +void * +Py_ffi_closure_alloc(ctypes_state *state, size_t size, void** codeloc) { #ifdef HAVE_FFI_CLOSURE_ALLOC #ifdef USING_APPLE_OS_LIBFFI @@ -132,12 +163,15 @@ void *Py_ffi_closure_alloc(size_t size, void** codeloc) #endif #endif ITEM *item; - if (!free_list) - more_core(); - if (!free_list) + malloc_closure_state *st = &state->malloc_closure; + if (!st->free_list) { + more_core(st); + } + if (!st->free_list) { return NULL; - item = free_list; - free_list = item->next; + } + item = st->free_list; + st->free_list = item->next; #ifdef _M_ARM // set Thumb bit so that blx is called correctly *codeloc = (ITEM*)((uintptr_t)item | 1); From 026f023d6f30edf11ac3fd3acd0723945c772e76 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Sun, 14 Apr 2024 23:03:44 +0900 Subject: [PATCH 04/10] add a test --- Lib/test/test_ctypes/test_refcounts.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Lib/test/test_ctypes/test_refcounts.py b/Lib/test/test_ctypes/test_refcounts.py index 012722d8486218..0e347043ff6f4e 100644 --- a/Lib/test/test_ctypes/test_refcounts.py +++ b/Lib/test/test_ctypes/test_refcounts.py @@ -123,6 +123,19 @@ def test_finalize(self): ) script_helper.assert_python_ok("-c", script) + @unittest.skipUnless(support.Py_DEBUG, 'a method requires Py_DEBUG') + def test_many_closures_per_module(self): + # check if mmap() and munmap() get called multiple times + script = ( + "import ctypes, _ctypes;" + "pyfunc = lambda: 0;" + "cfunc_type = ctypes.CFUNCTYPE(ctypes.c_int);" + "cfuncs = [cfunc_type(pyfunc) for i in range(500)];" + "n_containers = _ctypes._get_ffi_closure_containers_count();" + "exit(n_containers and n_containers < 2)" + ) + script_helper.assert_python_ok("-c", script) + if __name__ == '__main__': unittest.main() From 3430e51d45a250d029b1cbba6edfa8a0817e340b Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Mon, 15 Apr 2024 02:50:00 +0900 Subject: [PATCH 05/10] check USING_MALLOC_CLOSURE_DOT_C --- Modules/_ctypes/_ctypes.c | 2 ++ Modules/_ctypes/callbacks.c | 6 +----- Modules/_ctypes/callproc.c | 6 ++++++ Modules/_ctypes/ctypes.h | 10 +++++++--- Modules/_ctypes/malloc_closure.c | 8 +++++++- 5 files changed, 23 insertions(+), 9 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 9969c65f5b8d2a..5be6fa6d4ef391 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -5936,8 +5936,10 @@ module_clear(PyObject *module) { Py_CLEAR(st->PyComError_Type); #endif Py_CLEAR(st->PyCType_Type); +#ifdef USING_MALLOC_CLOSURE_DOT_C clear_malloc_closure_free_list(st); memset(&st->malloc_closure, 0, sizeof(malloc_closure_state)); +#endif return 0; } diff --git a/Modules/_ctypes/callbacks.c b/Modules/_ctypes/callbacks.c index 5cf7f0af80279f..6ca51f4c33f6e0 100644 --- a/Modules/_ctypes/callbacks.c +++ b/Modules/_ctypes/callbacks.c @@ -56,11 +56,7 @@ CThunkObject_dealloc(PyObject *myself) PyObject_GC_UnTrack(self); (void)CThunkObject_clear(myself); if (self->pcl_write) { - PyObject *module = _PyType_GetModule(tp); - if (module) { - ctypes_state *st = _PyModule_GetState(module); - Py_ffi_closure_free(st, self->pcl_write); - } + Py_ffi_closure_free(tp, self->pcl_write); } PyObject_GC_Del(self); Py_DECREF(tp); diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index ecab2992b0d9e7..c63ac5764b9617 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -2063,12 +2063,18 @@ buffer_info(PyObject *self, PyObject *arg) return Py_BuildValue("siN", info->format, info->ndim, shape); } +#ifdef Py_DEBUG static PyObject * get_malloc_closure_narenas(PyObject *self, PyObject *args) { +#ifdef USING_MALLOC_CLOSURE_DOT_C ctypes_state *st = get_module_state(self); return PyLong_FromSsize_t(st->malloc_closure.narenas); +#else + return PyLong_FromLong(0); +#endif } +#endif PyMethodDef _ctypes_module_methods[] = { {"get_errno", get_errno, METH_NOARGS}, diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 71b17918fece58..27331c4645d0bb 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -39,6 +39,7 @@ #include // for IUnknown interface #endif +#ifdef USING_MALLOC_CLOSURE_DOT_C typedef union _tagITEM { ffi_closure closure; union _tagITEM *next; @@ -56,6 +57,7 @@ typedef struct { Py_ssize_t arena_size; Py_ssize_t narenas; } malloc_closure_state; +#endif typedef struct { PyTypeObject *DictRemover_Type; @@ -89,7 +91,9 @@ typedef struct { PyObject *error_object_name; // callproc.c PyObject *PyExc_ArgError; PyObject *swapped_suffix; +#ifdef USING_MALLOC_CLOSURE_DOT_C malloc_closure_state malloc_closure; +#endif } ctypes_state; @@ -469,13 +473,13 @@ extern int _ctypes_simple_instance(ctypes_state *st, PyObject *obj); PyObject *_ctypes_get_errobj(ctypes_state *st, int **pspace); #ifdef USING_MALLOC_CLOSURE_DOT_C -void Py_ffi_closure_free(ctypes_state *st, void *p); +void Py_ffi_closure_free(PyTypeObject *thunk_tp, void *p); void *Py_ffi_closure_alloc(ctypes_state *st, size_t size, void** codeloc); +void clear_malloc_closure_free_list(ctypes_state *st); #else -#define Py_ffi_closure_free(st, p) ffi_closure_free(p) +#define Py_ffi_closure_free(tp, p) ffi_closure_free(p) #define Py_ffi_closure_alloc(st, size, codeloc) ffi_closure_alloc(size, codeloc) #endif -void clear_malloc_closure_free_list(ctypes_state *st); /**************************************************************** diff --git a/Modules/_ctypes/malloc_closure.c b/Modules/_ctypes/malloc_closure.c index 30f68a4cb7c48f..c954d899ed2720 100644 --- a/Modules/_ctypes/malloc_closure.c +++ b/Modules/_ctypes/malloc_closure.c @@ -120,7 +120,7 @@ clear_malloc_closure_free_list(ctypes_state *state) /* put the item back into the free list */ void -Py_ffi_closure_free(ctypes_state *state, void *p) +Py_ffi_closure_free(PyTypeObject *thunk_tp, void *p) { #ifdef HAVE_FFI_CLOSURE_ALLOC #ifdef USING_APPLE_OS_LIBFFI @@ -136,6 +136,12 @@ Py_ffi_closure_free(ctypes_state *state, void *p) } #endif #endif + PyObject *module = _PyType_GetModule(thunk_tp); + if (module == NULL) { + return; + } + ctypes_state *state = get_module_state(module); + malloc_closure_state *st = &state->malloc_closure; if (st->narenas <= 0) { return; From 5e84ff3353eef5246542fcb181d1d1b7e179e461 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Mon, 15 Apr 2024 04:19:43 +0900 Subject: [PATCH 06/10] tune a test --- Lib/test/test_ctypes/test_refcounts.py | 4 ++-- Modules/_ctypes/callproc.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_ctypes/test_refcounts.py b/Lib/test/test_ctypes/test_refcounts.py index 0e347043ff6f4e..84fbba919335a2 100644 --- a/Lib/test/test_ctypes/test_refcounts.py +++ b/Lib/test/test_ctypes/test_refcounts.py @@ -123,7 +123,6 @@ def test_finalize(self): ) script_helper.assert_python_ok("-c", script) - @unittest.skipUnless(support.Py_DEBUG, 'a method requires Py_DEBUG') def test_many_closures_per_module(self): # check if mmap() and munmap() get called multiple times script = ( @@ -131,7 +130,8 @@ def test_many_closures_per_module(self): "pyfunc = lambda: 0;" "cfunc_type = ctypes.CFUNCTYPE(ctypes.c_int);" "cfuncs = [cfunc_type(pyfunc) for i in range(500)];" - "n_containers = _ctypes._get_ffi_closure_containers_count();" + "f = getattr(_ctypes, '_get_ffi_closure_containers_count', None);" + "n_containers = f and f();" "exit(n_containers and n_containers < 2)" ) script_helper.assert_python_ok("-c", script) diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index c63ac5764b9617..354f068c5a55a0 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -2071,7 +2071,7 @@ get_malloc_closure_narenas(PyObject *self, PyObject *args) ctypes_state *st = get_module_state(self); return PyLong_FromSsize_t(st->malloc_closure.narenas); #else - return PyLong_FromLong(0); + Py_RETURN_NONE; #endif } #endif From 5f6e6a992d644e4b58c169998b64d696cf0f21a3 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Mon, 15 Apr 2024 13:37:18 +0900 Subject: [PATCH 07/10] hide the test method in CType_Type --- Lib/test/test_ctypes/test_refcounts.py | 6 +++--- Modules/_ctypes/_ctypes.c | 22 ++++++++++++++++++++++ Modules/_ctypes/callproc.c | 16 ---------------- Modules/_ctypes/clinic/_ctypes.c.h | 24 +++++++++++++++++++++++- 4 files changed, 48 insertions(+), 20 deletions(-) diff --git a/Lib/test/test_ctypes/test_refcounts.py b/Lib/test/test_ctypes/test_refcounts.py index 84fbba919335a2..54a2ac9d1194d3 100644 --- a/Lib/test/test_ctypes/test_refcounts.py +++ b/Lib/test/test_ctypes/test_refcounts.py @@ -126,12 +126,12 @@ def test_finalize(self): def test_many_closures_per_module(self): # check if mmap() and munmap() get called multiple times script = ( - "import ctypes, _ctypes;" + "import ctypes;" "pyfunc = lambda: 0;" "cfunc_type = ctypes.CFUNCTYPE(ctypes.c_int);" "cfuncs = [cfunc_type(pyfunc) for i in range(500)];" - "f = getattr(_ctypes, '_get_ffi_closure_containers_count', None);" - "n_containers = f and f();" + "ctype_type = ctypes.Union.__class__.__base__;" + "n_containers = ctype_type.get_ffi_closure_containers_count();" "exit(n_containers and n_containers < 2)" ) script_helper.assert_python_ok("-c", script) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 5be6fa6d4ef391..d5cd866003af69 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -558,12 +558,34 @@ _ctypes_CType_Type___sizeof___impl(PyObject *self, PyTypeObject *cls) return PyLong_FromSsize_t(size); } +/*[clinic input] +@classmethod +_ctypes.CType_Type.get_ffi_closure_containers_count + + cls: defining_class + / +[clinic start generated code]*/ + +static PyObject * +_ctypes_CType_Type_get_ffi_closure_containers_count_impl(PyTypeObject *type, + PyTypeObject *cls) +/*[clinic end generated code: output=619f776a42f7c3aa input=285058c2f984defc]*/ +{ +#ifdef USING_MALLOC_CLOSURE_DOT_C + ctypes_state *st = get_module_state_by_class(cls); + return PyLong_FromSsize_t(st->malloc_closure.narenas); +#else + Py_RETURN_NONE; +#endif +} + static PyObject * CType_Type_repeat(PyObject *self, Py_ssize_t length); static PyMethodDef ctype_methods[] = { _CTYPES_CTYPE_TYPE___SIZEOF___METHODDEF + _CTYPES_CTYPE_TYPE_GET_FFI_CLOSURE_CONTAINERS_COUNT_METHODDEF {0}, }; diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 354f068c5a55a0..934cee30033f92 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -2063,19 +2063,6 @@ buffer_info(PyObject *self, PyObject *arg) return Py_BuildValue("siN", info->format, info->ndim, shape); } -#ifdef Py_DEBUG -static PyObject * -get_malloc_closure_narenas(PyObject *self, PyObject *args) -{ -#ifdef USING_MALLOC_CLOSURE_DOT_C - ctypes_state *st = get_module_state(self); - return PyLong_FromSsize_t(st->malloc_closure.narenas); -#else - Py_RETURN_NONE; -#endif -} -#endif - PyMethodDef _ctypes_module_methods[] = { {"get_errno", get_errno, METH_NOARGS}, {"set_errno", set_errno, METH_VARARGS}, @@ -2110,9 +2097,6 @@ PyMethodDef _ctypes_module_methods[] = { {"PyObj_FromPtr", My_PyObj_FromPtr, METH_VARARGS }, {"Py_INCREF", My_Py_INCREF, METH_O }, {"Py_DECREF", My_Py_DECREF, METH_O }, -#ifdef Py_DEBUG - {"_get_ffi_closure_containers_count", get_malloc_closure_narenas, METH_NOARGS}, -#endif {NULL, NULL} /* Sentinel */ }; diff --git a/Modules/_ctypes/clinic/_ctypes.c.h b/Modules/_ctypes/clinic/_ctypes.c.h index 98a84cc14f4386..49b774921f01a0 100644 --- a/Modules/_ctypes/clinic/_ctypes.c.h +++ b/Modules/_ctypes/clinic/_ctypes.c.h @@ -27,6 +27,28 @@ _ctypes_CType_Type___sizeof__(PyObject *self, PyTypeObject *cls, PyObject *const return _ctypes_CType_Type___sizeof___impl(self, cls); } +PyDoc_STRVAR(_ctypes_CType_Type_get_ffi_closure_containers_count__doc__, +"get_ffi_closure_containers_count($type, /)\n" +"--\n" +"\n"); + +#define _CTYPES_CTYPE_TYPE_GET_FFI_CLOSURE_CONTAINERS_COUNT_METHODDEF \ + {"get_ffi_closure_containers_count", _PyCFunction_CAST(_ctypes_CType_Type_get_ffi_closure_containers_count), METH_METHOD|METH_FASTCALL|METH_KEYWORDS|METH_CLASS, _ctypes_CType_Type_get_ffi_closure_containers_count__doc__}, + +static PyObject * +_ctypes_CType_Type_get_ffi_closure_containers_count_impl(PyTypeObject *type, + PyTypeObject *cls); + +static PyObject * +_ctypes_CType_Type_get_ffi_closure_containers_count(PyTypeObject *type, PyTypeObject *cls, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) +{ + if (nargs || (kwnames && PyTuple_GET_SIZE(kwnames))) { + PyErr_SetString(PyExc_TypeError, "get_ffi_closure_containers_count() takes no arguments"); + return NULL; + } + return _ctypes_CType_Type_get_ffi_closure_containers_count_impl(type, cls); +} + PyDoc_STRVAR(CDataType_from_address__doc__, "from_address($self, value, /)\n" "--\n" @@ -607,4 +629,4 @@ Simple_from_outparm(PyObject *self, PyTypeObject *cls, PyObject *const *args, Py } return Simple_from_outparm_impl(self, cls); } -/*[clinic end generated code: output=9c6539a3559e6088 input=a9049054013a1b77]*/ +/*[clinic end generated code: output=21ed02205e81ab88 input=a9049054013a1b77]*/ From 0cd1e3755fd09e146a8b86fbf83e8bcda1b53dbc Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:30:08 +0900 Subject: [PATCH 08/10] restore blank lines --- Modules/_ctypes/callproc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c index 934cee30033f92..cbed2f32caa6c4 100644 --- a/Modules/_ctypes/callproc.c +++ b/Modules/_ctypes/callproc.c @@ -2063,6 +2063,8 @@ buffer_info(PyObject *self, PyObject *arg) return Py_BuildValue("siN", info->format, info->ndim, shape); } + + PyMethodDef _ctypes_module_methods[] = { {"get_errno", get_errno, METH_NOARGS}, {"set_errno", set_errno, METH_VARARGS}, From af4d4a12e03e220b7e874fb4e41c12850b2133c0 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Mon, 15 Apr 2024 14:45:33 +0900 Subject: [PATCH 09/10] correct _PyType_GetModule comment --- Include/internal/pycore_typeobject.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h index cd031d030daf9b..eb38d3b6f3fde6 100644 --- a/Include/internal/pycore_typeobject.h +++ b/Include/internal/pycore_typeobject.h @@ -137,7 +137,7 @@ _PyStaticType_GET_WEAKREFS_LISTPTR(static_builtin_state *state) } /* Like PyType_GetModule, but skips verification - * that type is a heap type */ + * that type is a heap type with an associated module */ static inline PyObject * _PyType_GetModule(PyTypeObject *type) { From e16feb90fe1a2a95aa83abc221e2342e3233bab1 Mon Sep 17 00:00:00 2001 From: neonene <53406459+neonene@users.noreply.github.com> Date: Mon, 15 Apr 2024 16:50:14 +0900 Subject: [PATCH 10/10] reduce USING_MALLOC_CLOSURE_DOT_C checks --- Modules/_ctypes/_ctypes.c | 6 ------ Modules/_ctypes/ctypes.h | 5 +---- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index d5cd866003af69..3d9dbc536be699 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -571,12 +571,8 @@ _ctypes_CType_Type_get_ffi_closure_containers_count_impl(PyTypeObject *type, PyTypeObject *cls) /*[clinic end generated code: output=619f776a42f7c3aa input=285058c2f984defc]*/ { -#ifdef USING_MALLOC_CLOSURE_DOT_C ctypes_state *st = get_module_state_by_class(cls); return PyLong_FromSsize_t(st->malloc_closure.narenas); -#else - Py_RETURN_NONE; -#endif } static PyObject * @@ -5958,10 +5954,8 @@ module_clear(PyObject *module) { Py_CLEAR(st->PyComError_Type); #endif Py_CLEAR(st->PyCType_Type); -#ifdef USING_MALLOC_CLOSURE_DOT_C clear_malloc_closure_free_list(st); memset(&st->malloc_closure, 0, sizeof(malloc_closure_state)); -#endif return 0; } diff --git a/Modules/_ctypes/ctypes.h b/Modules/_ctypes/ctypes.h index 27331c4645d0bb..02e05622fd920b 100644 --- a/Modules/_ctypes/ctypes.h +++ b/Modules/_ctypes/ctypes.h @@ -39,7 +39,6 @@ #include // for IUnknown interface #endif -#ifdef USING_MALLOC_CLOSURE_DOT_C typedef union _tagITEM { ffi_closure closure; union _tagITEM *next; @@ -57,7 +56,6 @@ typedef struct { Py_ssize_t arena_size; Py_ssize_t narenas; } malloc_closure_state; -#endif typedef struct { PyTypeObject *DictRemover_Type; @@ -91,9 +89,7 @@ typedef struct { PyObject *error_object_name; // callproc.c PyObject *PyExc_ArgError; PyObject *swapped_suffix; -#ifdef USING_MALLOC_CLOSURE_DOT_C malloc_closure_state malloc_closure; -#endif } ctypes_state; @@ -479,6 +475,7 @@ void clear_malloc_closure_free_list(ctypes_state *st); #else #define Py_ffi_closure_free(tp, p) ffi_closure_free(p) #define Py_ffi_closure_alloc(st, size, codeloc) ffi_closure_alloc(size, codeloc) +#define clear_malloc_closure_free_list(st) ((void)0) #endif