Skip to content

Commit

Permalink
Merge pull request #2655 from xrmx/drop-pyimport-private-for-modern-p…
Browse files Browse the repository at this point in the history
…ython

plugins/python: use PyOS_*Fork stable API functions on 3.7+
  • Loading branch information
xrmx authored Sep 8, 2024
2 parents 03338ed + d6211dc commit 2397c96
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 20 deletions.
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

0 comments on commit 2397c96

Please sign in to comment.