Skip to content

Commit

Permalink
set capi-struct pointer to interp state
Browse files Browse the repository at this point in the history
  • Loading branch information
neonene committed Apr 27, 2024
1 parent 51aefc5 commit 4c1325e
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 6 deletions.
25 changes: 19 additions & 6 deletions Include/datetime.h
Expand Up @@ -155,7 +155,7 @@ typedef struct


/* Define structure for C API. */
typedef struct {
typedef struct _pydatetime_capi {
/* type objects */
PyTypeObject *DateType;
PyTypeObject *DateTimeType;
Expand All @@ -182,7 +182,8 @@ typedef struct {
PyObject *(*DateTime_FromDateAndTimeAndFold)(int, int, int, int, int, int, int,
PyObject*, int, PyTypeObject*);
PyObject *(*Time_FromTimeAndFold)(int, int, int, int, PyObject*, int, PyTypeObject*);

struct _pydatetime_capi *(*_get_capi_by_interp)(void);
void (*_set_capi_by_interp)(struct _pydatetime_capi *);
} PyDateTime_CAPI;

#define PyDateTime_CAPSULE_NAME "datetime.datetime_CAPI"
Expand All @@ -194,10 +195,22 @@ typedef struct {
* */
#ifndef _PY_DATETIME_IMPL
/* Define global variable for the C API and a macro for setting it. */
static PyDateTime_CAPI *PyDateTimeAPI = NULL;

#define PyDateTime_IMPORT \
PyDateTimeAPI = (PyDateTime_CAPI *)PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)
static PyDateTime_CAPI *
_get_pydatetime_capi_dummy(void)
{
return NULL;
}
static PyDateTime_CAPI *(*_get_pydatetime_capi)(void) = _get_pydatetime_capi_dummy;
#define PyDateTimeAPI _get_pydatetime_capi()

static inline void pydatetime_import(void) {
PyDateTime_CAPI *capi = PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0);
if (capi) {
capi->_set_capi_by_interp(capi);
_get_pydatetime_capi = capi->_get_capi_by_interp;
}
}
#define PyDateTime_IMPORT pydatetime_import()

/* Macro for access to the UTC singleton */
#define PyDateTime_TimeZone_UTC PyDateTimeAPI->TimeZone_UTC
Expand Down
1 change: 1 addition & 0 deletions Include/internal/pycore_interp.h
Expand Up @@ -236,6 +236,7 @@ struct _is {
// more comments.
struct _obmalloc_state *obmalloc;

void *datetime_capi;
PyObject *audit_hooks;
PyType_WatchCallback type_watchers[TYPE_MAX_WATCHERS];
PyCode_WatchCallback code_watchers[CODE_MAX_WATCHERS];
Expand Down
16 changes: 16 additions & 0 deletions Lib/test/test_capi/test_misc.py
Expand Up @@ -2282,6 +2282,22 @@ def test_module_state_shared_in_global(self):
subinterp_attr_id = os.read(r, 100)
self.assertEqual(main_attr_id, subinterp_attr_id)

@unittest.skipIf(_testmultiphase is None, "test requires _testmultiphase module")
def test_datetime_capi_client(self):
script = textwrap.dedent("""
import importlib.machinery
import importlib.util
fullname = '_test_datetime_capi_client'
origin = importlib.util.find_spec('_testmultiphase').origin
loader = importlib.machinery.ExtensionFileLoader(fullname, origin)
spec = importlib.util.spec_from_loader(fullname, loader)
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
""")
exec(script)
ret = support.run_in_subinterp(script)
self.assertEqual(ret, 0)


@requires_subinterpreters
class InterpreterConfigTests(unittest.TestCase):
Expand Down
15 changes: 15 additions & 0 deletions Modules/_datetimemodule.c
Expand Up @@ -63,6 +63,18 @@ static datetime_state _datetime_global_state;

#define STATIC_STATE() (&_datetime_global_state)

void
set_datetime_capi_by_interp(PyDateTime_CAPI *capi)
{
_PyInterpreterState_GET()->datetime_capi = capi;
}

PyDateTime_CAPI *
get_datetime_capi_by_interp(void)
{
return (PyDateTime_CAPI *)_PyInterpreterState_GET()->datetime_capi;
}

/* We require that C int be at least 32 bits, and use int virtually
* everywhere. In just a few cases we use a temp long, where a Python
* API returns a C long. In such cases, we have to ensure that the
Expand Down Expand Up @@ -6736,12 +6748,15 @@ get_datetime_capi(void)
datetime_state *st = STATIC_STATE();
assert(st->utc != NULL);
capi->TimeZone_UTC = st->utc; // borrowed ref
capi->_set_capi_by_interp = set_datetime_capi_by_interp;
capi->_get_capi_by_interp = get_datetime_capi_by_interp;
return capi;
}

static void
datetime_destructor(PyObject *op)
{
set_datetime_capi_by_interp(NULL);
void *ptr = PyCapsule_GetPointer(op, PyDateTime_CAPSULE_NAME);
PyMem_Free(ptr);
}
Expand Down
35 changes: 35 additions & 0 deletions Modules/_testmultiphase.c
Expand Up @@ -952,3 +952,38 @@ PyInit__test_shared_gil_only(void)
{
return PyModuleDef_Init(&shared_gil_only_def);
}


#include "datetime.h"

static int
datetime_capi_client_exec(PyObject *m)
{
_get_pydatetime_capi = _get_pydatetime_capi_dummy;
if (PyDateTimeAPI != NULL) {
return -1;
}
PyDateTime_IMPORT;
if (PyDateTimeAPI == NULL) {
return -1;
}
if (PyDateTimeAPI != PyCapsule_Import(PyDateTime_CAPSULE_NAME, 0)) {
return -1;
}
return 0;
}

static PyModuleDef_Slot datetime_capi_client_slots[] = {
{Py_mod_exec, datetime_capi_client_exec},
{Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED},
{0, NULL},
};

static PyModuleDef datetime_capi_client_def = TEST_MODULE_DEF(
"_testmultiphase_datetime_capi_client", datetime_capi_client_slots, NULL);

PyMODINIT_FUNC
PyInit__test_datetime_capi_client(void)
{
return PyModuleDef_Init(&datetime_capi_client_def);
}

0 comments on commit 4c1325e

Please sign in to comment.