diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 4f811023f7a043..7b484922dc5222 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -158,6 +158,9 @@ struct _is { struct _ceval_state ceval; struct _gc_runtime_state gc; + /* per interpreter singletons (strong reference) */ + PyObject *none; + PyObject *modules; PyObject *modules_by_index; PyObject *sysdict; diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index 3e3657339a4a49..6475c2ae18954a 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -54,7 +54,7 @@ extern PyStatus _PyTypes_Init(void); extern PyStatus _PyTypes_InitSlotDefs(void); extern PyStatus _PyImportZip_Init(PyThreadState *tstate); extern PyStatus _PyGC_Init(PyThreadState *tstate); - +extern PyStatus _Py_InitSingletons(PyThreadState *tstate); /* Various internal finalizers */ @@ -74,6 +74,7 @@ extern void _PyExc_Fini(void); extern void _PyImport_Fini(void); extern void _PyImport_Fini2(void); extern void _PyGC_Fini(PyThreadState *tstate); +extern void _Py_FiniSingletons(PyThreadState *tstate); extern void _PyType_Fini(void); extern void _Py_HashRandomization_Fini(void); extern void _PyUnicode_Fini(PyThreadState *tstate); diff --git a/Include/object.h b/Include/object.h index 537567040f9871..0dcf3ea58c9743 100644 --- a/Include/object.h +++ b/Include/object.h @@ -526,17 +526,17 @@ they can have object code that is not dependent on Python compilation flags. PyAPI_FUNC(void) Py_IncRef(PyObject *); PyAPI_FUNC(void) Py_DecRef(PyObject *); -/* -_Py_NoneStruct is an object of undefined type which can be used in contexts -where NULL (nil) is not suitable (since NULL often means 'error'). +// Get a borrowed reference to the None singleton. +PyAPI_DATA(PyObject*) Py_GetNone(void); -Don't forget to apply Py_INCREF() when returning this value!!! -*/ -PyAPI_DATA(PyObject) _Py_NoneStruct; /* Don't use this directly */ -#define Py_None (&_Py_NoneStruct) +// Get a strong reference to the None singleton. +PyAPI_DATA(PyObject*) Py_GetNoneRef(void); + +// Macro for backward compatibility. +#define Py_None Py_GetNone() -/* Macro for returning Py_None from a function */ -#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None +/* Macro for returning a new strong reference to None from a function */ +#define Py_RETURN_NONE return Py_GetNoneRef() /* Py_NotImplemented is a singleton used to signal that an operation is diff --git a/Objects/object.c b/Objects/object.c index 10cbd1b7c16f59..1ff0ae2aa40407 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1628,6 +1628,30 @@ PyObject _Py_NoneStruct = { 1, &_PyNone_Type }; + +PyObject* +Py_GetNone(void) +{ + PyInterpreterState *interp = _PyInterpreterState_GET(); + /* The GIL must be held to call Py_GetNone() */ + assert(interp != NULL); + PyObject *none = interp->none; + /* Py_GetNone() must not be called before _Py_InitSingletons(), + nor after _Py_FiniSingletons() */ + assert(none != NULL); + return none; +} + + +PyObject* +Py_GetNoneRef(void) +{ + PyObject *none = Py_GetNone(); + Py_INCREF(none); + return none; +} + + /* NotImplemented is an object that can be used to signal that an operation is not implemented for the given type combination. */ @@ -2220,3 +2244,20 @@ PyObject_GET_WEAKREFS_LISTPTR(PyObject *op) #ifdef __cplusplus } #endif + + +PyStatus +_Py_InitSingletons(PyThreadState *tstate) +{ + PyObject *none = &_Py_NoneStruct; + Py_INCREF(none); + tstate->interp->none = none; + return _PyStatus_OK(); +} + + +void +_Py_FiniSingletons(PyThreadState *tstate) +{ + Py_CLEAR(tstate->interp->none); +} diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index f2f7d585c8000d..170bec1f53c38f 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -580,6 +580,11 @@ pycore_init_types(PyThreadState *tstate) PyStatus status; int is_main_interp = _Py_IsMainInterpreter(tstate); + status = _Py_InitSingletons(tstate); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + status = _PyGC_Init(tstate); if (_PyStatus_EXCEPTION(status)) { return status; @@ -1323,6 +1328,8 @@ finalize_interp_delete(PyThreadState *tstate) created GIL, which ensures that Py_Initialize / Py_FinalizeEx can be called multiple times. */ + _Py_FiniSingletons(tstate); + PyInterpreterState_Delete(tstate->interp); }