From 22629fd89e470b5fcf5f962a71a2c4726dee8929 Mon Sep 17 00:00:00 2001 From: Kenta Murata Date: Fri, 24 May 2024 14:11:22 +0900 Subject: [PATCH] Ensure GIL state in pycall_pyptr_free This needs because this function may be called from GC sweeper on non-main threads. --- ext/pycall/libpython.c | 4 ++++ ext/pycall/pycall.c | 10 +++++++++- ext/pycall/pycall_internal.h | 9 +++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ext/pycall/libpython.c b/ext/pycall/libpython.c index 19406b6..48ca1d2 100644 --- a/ext/pycall/libpython.c +++ b/ext/pycall/libpython.c @@ -217,6 +217,10 @@ pycall_init_libpython_api_table(VALUE libpython_handle) INIT_API_TABLE_ENTRY2(PyUnicode_DecodeUTF8, PyUnicodeUCS2_DecodeUTF8, required); INIT_API_TABLE_ENTRY2(PyUnicode_FromFormatV, PyUnicodeUCS2_FromFormatV, required); } + + INIT_API_TABLE_ENTRY(PyGILState_Check, required); + INIT_API_TABLE_ENTRY(PyGILState_Ensure, required); + INIT_API_TABLE_ENTRY(PyGILState_Release, required); } void diff --git a/ext/pycall/pycall.c b/ext/pycall/pycall.c index 8bae130..2c7d56e 100644 --- a/ext/pycall/pycall.c +++ b/ext/pycall/pycall.c @@ -139,7 +139,15 @@ pycall_pyptr_free(void *ptr) fprintf(stderr, "zero refcnt object %p of type %s\n", pyobj, Py_TYPE(pyobj)->tp_name); } #endif /* PYCALL_DEBUG_DUMP_REFCNT */ - pycall_Py_DecRef(pyobj); + + if (Py_API(PyGILState_Check())) { + pycall_Py_DecRef(pyobj); + } + else { + PyGILState_STATE gstate = Py_API(PyGILState_Ensure)(); + pycall_Py_DecRef(pyobj); + Py_API(PyGILState_Release)(gstate); + } } static size_t _PySys_GetSizeOf(PyObject *); diff --git a/ext/pycall/pycall_internal.h b/ext/pycall/pycall_internal.h index 598e983..4a7a06c 100644 --- a/ext/pycall/pycall_internal.h +++ b/ext/pycall/pycall_internal.h @@ -519,6 +519,11 @@ PyObject * PyRuby_New(VALUE ruby_object); /* ==== thread support ==== */ +typedef enum { + PyGILState_LOCKED, + PyGILState_UNLOCKED +} PyGILState_STATE; + #if defined(PYCALL_THREAD_WIN32) typedef DWORD pycall_tls_key; #elif defined(PYCALL_THREAD_PTHREAD) @@ -669,6 +674,10 @@ typedef struct { PyObject * (* PyUnicode_AsUTF8String)(PyObject *); PyObject * (* PyUnicode_DecodeUTF8)(char const*, Py_ssize_t, char const *); PyObject * (* PyUnicode_FromFormatV)(char const*, ...); + + int (* PyGILState_Check)(void); + PyGILState_STATE (* PyGILState_Ensure)(void); + void (* PyGILState_Release)(PyGILState_STATE); } pycall_libpython_api_table_t; pycall_libpython_api_table_t *pycall_libpython_api_table(void);