Skip to content

[3.12] gh-119213: Fix getargs.c to store state in InterpreterState... #119194

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

Closed
wants to merge 4 commits 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
6 changes: 6 additions & 0 deletions Include/internal/pycore_interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ struct _Py_long_state {
int max_str_digits;
};

struct _getargs_runtime_state {
struct _PyArg_Parser *static_parsers;
};


/* cross-interpreter data registry */

Expand Down Expand Up @@ -230,6 +234,8 @@ struct _is {

/* the initial PyInterpreterState.threads.head */
PyThreadState _initial_thread;

struct _getargs_runtime_state getargs;
};


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 @@ -62,7 +62,8 @@ extern void _PyAST_Fini(PyInterpreterState *interp);
extern void _PyAtExit_Fini(PyInterpreterState *interp);
extern void _PyThread_FiniType(PyInterpreterState *interp);
extern void _Py_Deepfreeze_Fini(void);
extern void _PyArg_Fini(void);
extern void _PyArg_InitState(PyInterpreterState *interp);
extern void _PyArg_Fini(PyInterpreterState *interp);
extern void _Py_FinalizeAllocatedBlocks(_PyRuntimeState *);

extern PyStatus _PyGILState_Init(PyInterpreterState *interp);
Expand Down
7 changes: 5 additions & 2 deletions Include/internal/pycore_runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ extern "C" {
#include "pycore_typeobject.h" // struct types_runtime_state
#include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_ids

struct _getargs_runtime_state {
/* The following struct is moved to interpreter state in 3.13+.
We're keeping it here for ABI compat.
See also: https://github.com/python/cpython/pull/119194. */
struct _UNUSED_getargs_runtime_state {
PyThread_type_lock mutex;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think having a lock isn't necessary in 3.12 as we're muving this struct to InterpreterState. Local state modification will be protected by the GIL.

struct _PyArg_Parser *static_parsers;
};
Expand Down Expand Up @@ -135,7 +138,7 @@ typedef struct pyruntimestate {
struct _import_runtime_state imports;
struct _ceval_runtime_state ceval;
struct _gilstate_runtime_state gilstate;
struct _getargs_runtime_state getargs;
struct _UNUSED_getargs_runtime_state _UNUSED_gilstate;
struct _fileutils_state fileutils;
struct _faulthandler_runtime_state faulthandler;
struct _tracemalloc_runtime_state tracemalloc;
Expand Down
27 changes: 13 additions & 14 deletions Python/getargs.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "Python.h"
#include "pycore_tuple.h" // _PyTuple_ITEMS()
#include "pycore_pylifecycle.h" // _PyArg_Fini
#include "pycore_interp.h" // _getargs_runtime_state

#include <ctype.h>
#include <float.h>
Expand Down Expand Up @@ -2021,8 +2022,9 @@ _parser_init(struct _PyArg_Parser *parser)
parser->initialized = owned ? 1 : -1;

assert(parser->next == NULL);
parser->next = _PyRuntime.getargs.static_parsers;
_PyRuntime.getargs.static_parsers = parser;
PyInterpreterState *interp = PyInterpreterState_Get();
parser->next = interp->getargs.static_parsers;
interp->getargs.static_parsers = parser;
return 1;
}

Expand All @@ -2035,16 +2037,7 @@ parser_init(struct _PyArg_Parser *parser)
assert(parser->kwtuple != NULL);
return 1;
}
PyThread_acquire_lock(_PyRuntime.getargs.mutex, WAIT_LOCK);
// Check again if another thread initialized the parser
// while we were waiting for the lock.
if (*((volatile int *)&parser->initialized)) {
assert(parser->kwtuple != NULL);
PyThread_release_lock(_PyRuntime.getargs.mutex);
return 1;
}
int ret = _parser_init(parser);
PyThread_release_lock(_PyRuntime.getargs.mutex);
return ret;
}

Expand Down Expand Up @@ -2943,16 +2936,22 @@ _PyArg_NoKwnames(const char *funcname, PyObject *kwnames)
}

void
_PyArg_Fini(void)
_PyArg_InitState(PyInterpreterState *interp)
{
interp->getargs.static_parsers = NULL;
}

void
_PyArg_Fini(PyInterpreterState *interp)
{
struct _PyArg_Parser *tmp, *s = _PyRuntime.getargs.static_parsers;
struct _PyArg_Parser *tmp, *s = interp->getargs.static_parsers;
while (s) {
tmp = s->next;
s->next = NULL;
parser_clear(s);
s = tmp;
}
_PyRuntime.getargs.static_parsers = NULL;
interp->getargs.static_parsers = NULL;
}

#ifdef __cplusplus
Expand Down
3 changes: 2 additions & 1 deletion Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -848,6 +848,8 @@ pycore_interp_init(PyThreadState *tstate)
return _PyStatus_ERR("can't initialize warnings");
}

_PyArg_InitState(interp);

status = _PyAtExit_Init(interp);
if (_PyStatus_EXCEPTION(status)) {
return status;
Expand Down Expand Up @@ -1751,7 +1753,6 @@ finalize_interp_clear(PyThreadState *tstate)

if (is_main_interp) {
_Py_HashRandomization_Fini();
_PyArg_Fini();
_Py_ClearFileSystemEncoding();
_Py_Deepfreeze_Fini();
_PyPerfTrampoline_Fini();
Expand Down
5 changes: 3 additions & 2 deletions Python/pystate.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,12 +380,11 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime);
_Py_COMP_DIAG_POP

#define NUMLOCKS 9
#define NUMLOCKS 8
#define LOCKS_INIT(runtime) \
{ \
&(runtime)->interpreters.mutex, \
&(runtime)->xidregistry.mutex, \
&(runtime)->getargs.mutex, \
&(runtime)->unicode_state.ids.lock, \
&(runtime)->imports.extensions.mutex, \
&(runtime)->ceval.pending_mainthread.lock, \
Expand Down Expand Up @@ -887,6 +886,8 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
_PyWarnings_Fini(interp);
_PyAtExit_Fini(interp);

_PyArg_Fini(interp);

// All Python types must be destroyed before the last GC collection. Python
// types create a reference cycle to themselves in their in their
// PyTypeObject.tp_mro member (the tuple contains the type).
Expand Down
Loading