diff --git a/core/master_utils.c b/core/master_utils.c index c3bfa6b51..a9ccee1a2 100644 --- a/core/master_utils.c +++ b/core/master_utils.c @@ -747,9 +747,22 @@ int uwsgi_respawn_worker(int wid) { pthread_mutex_lock(&uwsgi.threaded_logger_lock); } + + for (i = 0; i < 256; i++) { + if (uwsgi.p[i]->pre_uwsgi_fork) { + uwsgi.p[i]->pre_uwsgi_fork(); + } + } + pid_t pid = uwsgi_fork(uwsgi.workers[wid].name); if (pid == 0) { + for (i = 0; i < 256; i++) { + if (uwsgi.p[i]->post_uwsgi_fork) { + uwsgi.p[i]->post_uwsgi_fork(1); + } + } + signal(SIGWINCH, worker_wakeup); signal(SIGTSTP, worker_wakeup); uwsgi.mywid = wid; @@ -792,16 +805,6 @@ int uwsgi_respawn_worker(int wid) { uwsgi.my_signal_socket = uwsgi.workers[wid].signal_pipe[1]; - if (uwsgi.master_process) { - if ((uwsgi.workers[uwsgi.mywid].respawn_count || uwsgi.status.is_cheap)) { - for (i = 0; i < 256; i++) { - if (uwsgi.p[i]->master_fixup) { - uwsgi.p[i]->master_fixup(1); - } - } - } - } - if (uwsgi.threaded_logger) { pthread_mutex_unlock(&uwsgi.threaded_logger_lock); } @@ -812,6 +815,12 @@ int uwsgi_respawn_worker(int wid) { uwsgi_error("fork()"); } else { + for (i = 0; i < 256; i++) { + if (uwsgi.p[i]->post_uwsgi_fork) { + uwsgi.p[i]->post_uwsgi_fork(0); + } + } + // the pid is set only in the master, as the worker should never use it uwsgi.workers[wid].pid = pid; diff --git a/core/mule.c b/core/mule.c index 12a29c616..e93f6a98c 100644 --- a/core/mule.c +++ b/core/mule.c @@ -69,12 +69,6 @@ void uwsgi_mule(int id) { uwsgi_close_all_sockets(); - for (i = 0; i < 256; i++) { - if (uwsgi.p[i]->master_fixup) { - uwsgi.p[i]->master_fixup(1); - } - } - for (i = 0; i < 256; i++) { if (uwsgi.p[i]->post_fork) { uwsgi.p[i]->post_fork(); diff --git a/core/uwsgi.c b/core/uwsgi.c index a47fdde97..bbf273a7b 100755 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -3338,14 +3338,6 @@ int uwsgi_start(void *v_argv) { } } - // master fixup - for (i = 0; i < 256; i++) { - if (uwsgi.p[i]->master_fixup) { - uwsgi.p[i]->master_fixup(0); - } - } - - struct uwsgi_spooler *uspool = uwsgi.spoolers; while (uspool) { diff --git a/plugins/python/python_plugin.c b/plugins/python/python_plugin.c index 79f29d43c..c6194879e 100644 --- a/plugins/python/python_plugin.c +++ b/plugins/python/python_plugin.c @@ -428,17 +428,14 @@ void uwsgi_python_atexit() { void uwsgi_python_post_fork() { - if (uwsgi.i_am_a_spooler) { + // Need to acquire the gil when no master process is used as first worker + // will not have been forked like others + if (!uwsgi.master_process && uwsgi.mywid == 1) { UWSGI_GET_GIL - } + } - // reset python signal flags so child processes can trap signals - if (up.call_osafterfork) { -#ifdef HAS_NOT_PyOS_AfterFork_Child - PyOS_AfterFork(); -#else - PyOS_AfterFork_Child(); -#endif + if (uwsgi.i_am_a_spooler) { + UWSGI_GET_GIL } uwsgi_python_reset_random_seed(); @@ -1129,6 +1126,10 @@ void uwsgi_python_preinit_apps() { up.loaders[LOADER_CALLABLE] = uwsgi_callable_loader; up.loaders[LOADER_STRING_CALLABLE] = uwsgi_string_callable_loader; + // GIL was released in previous initialization steps but init_pyargv expects + // the GIL to be acquired + UWSGI_GET_GIL + init_pyargv(); init_uwsgi_embedded_module(); @@ -1174,14 +1175,13 @@ void uwsgi_python_preinit_apps() { upli = upli->next; } + // Release the GIL before moving on forward with initialization + UWSGI_RELEASE_GIL + } void uwsgi_python_init_apps() { - - // lazy ? - if (uwsgi.mywid > 0) { - UWSGI_GET_GIL; - } + UWSGI_GET_GIL; // prepare for stack suspend/resume if (uwsgi.async > 0) { @@ -1290,32 +1290,35 @@ void uwsgi_python_init_apps() { Py_INCREF(up.after_req_hook_args); } } - // lazy ? - if (uwsgi.mywid > 0) { - UWSGI_RELEASE_GIL; - } + UWSGI_RELEASE_GIL; } -void uwsgi_python_master_fixup(int step) { - static int master_fixed = 0; - static int worker_fixed = 0; +void uwsgi_python_pre_uwsgi_fork() { + if (uwsgi.has_threads) { + // Acquire the gil and import lock before forking in order to avoid + // deadlocks in workers + UWSGI_GET_GIL + _PyImport_AcquireLock(); + } +} - if (!uwsgi.master_process) return; +void uwsgi_python_post_uwsgi_fork(int step) { if (uwsgi.has_threads) { if (step == 0) { - if (!master_fixed) { - UWSGI_RELEASE_GIL; - master_fixed = 1; - } - } + // Release locks within master process + _PyImport_ReleaseLock(); + UWSGI_RELEASE_GIL + } else { - if (!worker_fixed) { - UWSGI_GET_GIL; - worker_fixed = 1; - } + // Ensure thread state and locks are cleaned up in child process +#ifdef HAS_NOT_PyOS_AfterFork_Child + PyOS_AfterFork(); +#else + PyOS_AfterFork_Child(); +#endif } } } @@ -1349,7 +1352,8 @@ void uwsgi_python_enable_threads() { up.reset_ts = threaded_reset_ts; } - + // Release the newly created gil from call to PyEval_InitThreads above + UWSGI_RELEASE_GIL uwsgi_log("python threads support enabled\n"); @@ -2043,13 +2047,6 @@ static int uwsgi_python_worker() { if (!up.worker_override) return 0; UWSGI_GET_GIL; - // ensure signals can be used again from python - if (!up.call_osafterfork) -#ifdef HAS_NOT_PyOS_AfterFork_Child - PyOS_AfterFork(); -#else - PyOS_AfterFork_Child(); -#endif FILE *pyfile = fopen(up.worker_override, "r"); if (!pyfile) { uwsgi_error_open(up.worker_override); @@ -2081,6 +2078,10 @@ struct uwsgi_plugin python_plugin = { .alias = "python", .modifier1 = 0, .init = uwsgi_python_init, + + .pre_uwsgi_fork = uwsgi_python_pre_uwsgi_fork, + .post_uwsgi_fork = uwsgi_python_post_uwsgi_fork, + .post_fork = uwsgi_python_post_fork, .options = uwsgi_python_options, .request = uwsgi_request_wsgi, @@ -2090,7 +2091,6 @@ struct uwsgi_plugin python_plugin = { .init_apps = uwsgi_python_init_apps, .fixup = uwsgi_python_fixup, - .master_fixup = uwsgi_python_master_fixup, .master_cycle = uwsgi_python_master_cycle, .mount_app = uwsgi_python_mount_app, diff --git a/plugins/python/uwsgi_python.h b/plugins/python/uwsgi_python.h index aca1f83b7..983d5c30e 100644 --- a/plugins/python/uwsgi_python.h +++ b/plugins/python/uwsgi_python.h @@ -1,5 +1,6 @@ #include #include +#include #include diff --git a/uwsgi.h b/uwsgi.h index 2b32cad79..f142538ff 100755 --- a/uwsgi.h +++ b/uwsgi.h @@ -1039,6 +1039,8 @@ struct uwsgi_plugin { void *data; void (*on_load) (void); int (*init) (void); + void (*pre_uwsgi_fork) (void); + void (*post_uwsgi_fork) (int); void (*post_init) (void); void (*post_fork) (void); struct uwsgi_option *options;