Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] bpo-39511: Add Py_GetNone() and Py_GetNoneRef() functions #18301

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion Include/internal/pycore_pylifecycle.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand All @@ -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);
Expand Down
18 changes: 9 additions & 9 deletions Include/object.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
41 changes: 41 additions & 0 deletions Objects/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -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. */

Expand Down Expand Up @@ -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);
}
7 changes: 7 additions & 0 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down