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

plugins/python: use PyOS_*Fork stable API functions on 3.7+ #2655

Merged
merged 4 commits into from
Sep 8, 2024
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
python-version: ["2.7", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["2.7", "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
test-suite: [python, deadlocks]
steps:
- name: Add deadnakes ppa
Expand Down
2 changes: 1 addition & 1 deletion core/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -468,8 +468,8 @@ void sanitize_args() {
uwsgi.cores = uwsgi.async;
}

uwsgi.has_threads = 1;
if (uwsgi.threads > 1) {
uwsgi.has_threads = 1;
uwsgi.cores = uwsgi.threads;
}

Expand Down
2 changes: 1 addition & 1 deletion core/uwsgi.c
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"freebind", no_argument, 0, "put socket in freebind mode", uwsgi_opt_true, &uwsgi.freebind, 0},
#endif
{"map-socket", required_argument, 0, "map sockets to specific workers", uwsgi_opt_add_string_list, &uwsgi.map_socket, 0},
{"enable-threads", no_argument, 'T', "enable threads", uwsgi_opt_true, &uwsgi.has_threads, 0},
{"enable-threads", no_argument, 'T', "enable threads (stub option this is true by default)", uwsgi_opt_true, &uwsgi.has_threads, 0},
{"no-threads-wait", no_argument, 0, "do not wait for threads cancellation on quit/reload", uwsgi_opt_true, &uwsgi.no_threads_wait, 0},

{"auto-procname", no_argument, 0, "automatically set processes name to something meaningful", uwsgi_opt_true, &uwsgi.auto_procname, 0},
Expand Down
36 changes: 25 additions & 11 deletions plugins/python/python_plugin.c
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,7 @@ void uwsgi_python_post_fork() {
// reset python signal flags so child processes can trap signals
// Necessary if uwsgi fork hooks not called to update interpreter state
if (!up.call_uwsgi_fork_hooks && up.call_osafterfork) {
#ifdef HAS_NOT_PyOS_AfterFork_Child
#ifdef HAS_NOT_PYOS_FORK_STABLE_API
PyOS_AfterFork();
#else
PyOS_AfterFork_Child();
Expand Down Expand Up @@ -1368,11 +1368,10 @@ void uwsgi_python_pre_uwsgi_fork() {
// Acquire the gil and import lock before forking in order to avoid
// deadlocks in workers
UWSGI_GET_GIL
#if defined UWSGI_PY312
PyInterpreterState *interp = PyInterpreterState_Get();
_PyImport_AcquireLock(interp);
#else
#ifdef HAS_NOT_PYOS_FORK_STABLE_API
_PyImport_AcquireLock();
#else
PyOS_BeforeFork();
#endif
}
}
Expand All @@ -1385,17 +1384,16 @@ void uwsgi_python_post_uwsgi_fork(int step) {
if (uwsgi.has_threads) {
if (step == 0) {
// Release locks within master process
#if defined UWSGI_PY312
PyInterpreterState *interp = PyInterpreterState_Get();
_PyImport_ReleaseLock(interp);
#else
#ifdef HAS_NOT_PYOS_FORK_STABLE_API
_PyImport_ReleaseLock();
#else
PyOS_AfterFork_Parent();
#endif
UWSGI_RELEASE_GIL
}
else {
// Ensure thread state and locks are cleaned up in child process
#ifdef HAS_NOT_PyOS_AfterFork_Child
#ifdef HAS_NOT_PYOS_FORK_STABLE_API
PyOS_AfterFork();
#else
PyOS_AfterFork_Child();
Expand Down Expand Up @@ -1664,7 +1662,11 @@ void uwsgi_python_suspend(struct wsgi_request *wsgi_req) {
#ifdef UWSGI_PY312
up.current_c_recursion_remaining[wsgi_req->async_id] = tstate->c_recursion_remaining;
up.current_py_recursion_remaining[wsgi_req->async_id] = tstate->py_recursion_remaining;
#ifdef UWSGI_PY313
up.current_frame[wsgi_req->async_id] = tstate->current_frame;
#else
up.current_frame[wsgi_req->async_id] = tstate->cframe;
#endif
#elif defined UWSGI_PY311
up.current_recursion_remaining[wsgi_req->async_id] = tstate->recursion_remaining;
up.current_frame[wsgi_req->async_id] = tstate->cframe;
Expand All @@ -1677,7 +1679,11 @@ void uwsgi_python_suspend(struct wsgi_request *wsgi_req) {
#ifdef UWSGI_PY312
up.current_main_c_recursion_remaining = tstate->c_recursion_remaining;
up.current_main_py_recursion_remaining = tstate->py_recursion_remaining;
#ifdef UWSGI_PY313
up.current_main_frame = tstate->current_frame;
#else
up.current_main_frame = tstate->cframe;
#endif
#elif defined UWSGI_PY311
up.current_main_recursion_remaining = tstate->recursion_remaining;
up.current_main_frame = tstate->cframe;
Expand Down Expand Up @@ -1917,7 +1923,11 @@ void uwsgi_python_resume(struct wsgi_request *wsgi_req) {
#ifdef UWSGI_PY312
tstate->c_recursion_remaining = up.current_c_recursion_remaining[wsgi_req->async_id];
tstate->py_recursion_remaining = up.current_py_recursion_remaining[wsgi_req->async_id];
#ifdef UWSGI_PY313
tstate->current_frame = up.current_frame[wsgi_req->async_id];
#else
tstate->cframe = up.current_frame[wsgi_req->async_id];
#endif
#elif defined UWSGI_PY311
tstate->recursion_remaining = up.current_recursion_remaining[wsgi_req->async_id];
tstate->cframe = up.current_frame[wsgi_req->async_id];
Expand All @@ -1930,7 +1940,11 @@ void uwsgi_python_resume(struct wsgi_request *wsgi_req) {
#ifdef UWSGI_PY312
tstate->c_recursion_remaining = up.current_main_c_recursion_remaining;
tstate->py_recursion_remaining = up.current_main_py_recursion_remaining;
#ifdef UWSGI_PY313
tstate->current_frame = up.current_main_frame;
#else
tstate->cframe = up.current_main_frame;
#endif
#elif defined UWSGI_PY311
tstate->recursion_remaining = up.current_main_recursion_remaining;
tstate->cframe = up.current_main_frame;
Expand Down Expand Up @@ -2164,7 +2178,7 @@ static int uwsgi_python_worker() {
// ensure signals can be used again from python
// Necessary if fork hooks have been not used to update interpreter state
if (!up.call_osafterfork && !up.call_uwsgi_fork_hooks)
#ifdef HAS_NOT_PyOS_AfterFork_Child
#ifdef HAS_NOT_PYOS_FORK_STABLE_API
PyOS_AfterFork();
#else
PyOS_AfterFork_Child();
Expand Down
20 changes: 14 additions & 6 deletions plugins/python/uwsgi_python.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
# define UWSGI_PY312
#endif

#if (PY_VERSION_HEX >= 0x030d0000)
# define UWSGI_PY313
#endif

#if PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 7
#define HAS_NOT_PyMemoryView_FromBuffer
#endif
Expand All @@ -41,12 +45,8 @@
#define HAS_NO_ERRORS_IN_PyFile_FromFd
#endif

#if PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7
#define HAS_NOT_PyOS_AfterFork_Child
#endif

#if PY_MAJOR_VERSION < 3
#define HAS_NOT_PyOS_AfterFork_Child
#if (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 7) || PY_MAJOR_VERSION < 3
#define HAS_NOT_PYOS_FORK_STABLE_API
#endif

#if PY_MAJOR_VERSION > 2
Expand Down Expand Up @@ -189,11 +189,19 @@ struct uwsgi_python {
#ifdef UWSGI_PY312
int *current_c_recursion_remaining;
int *current_py_recursion_remaining;
#ifdef UWSGI_PY313
struct _PyInterpreterFrame **current_frame;
#else
_PyCFrame **current_frame;
#endif

int current_main_c_recursion_remaining;
int current_main_py_recursion_remaining;
#ifdef UWSGI_PY313
struct _PyInterpreterFrame *current_main_frame;
#else
_PyCFrame *current_main_frame;
#endif
#elif defined UWSGI_PY311
int *current_recursion_remaining;
_PyCFrame **current_frame;
Expand Down