From 4ad26580905eb9a32c379cc0dd95026969722658 Mon Sep 17 00:00:00 2001 From: Unbit Date: Wed, 18 Sep 2013 11:08:56 +0200 Subject: [PATCH] added master fifo --- core/fifo.c | 83 +++++++++++++++++++++++++++ core/init.c | 5 ++ core/logging.c | 130 +++++++++++++++++++++++-------------------- core/master.c | 35 +++++++++--- core/master_events.c | 4 ++ core/master_utils.c | 59 +++++++++++++++----- core/socket.c | 1 + core/uwsgi.c | 4 +- uwsgi.h | 16 ++++++ uwsgiconfig.py | 2 +- 10 files changed, 254 insertions(+), 85 deletions(-) create mode 100644 core/fifo.c diff --git a/core/fifo.c b/core/fifo.c new file mode 100644 index 00000000..04d7197f --- /dev/null +++ b/core/fifo.c @@ -0,0 +1,83 @@ +#include + +extern struct uwsgi_server uwsgi; + +/* + + the --master-fifo option create a unix named pipe (fifo) you can use to send management + commands to the master: + + echo r > myfifo + +*/ + +// this var can be accessed by plugins and hooks +void (*uwsgi_fifo_table[256])(int); + +/* + +this is called as soon as possibile allowing plugins (or hooks) to override it + +*/ +void uwsgi_master_fifo_prepare() { + int i; + for(i=0;i<256;i++) { + uwsgi_fifo_table[i] = NULL; + } + + uwsgi_fifo_table['b'] = uwsgi_rebind_unix_sockets; + uwsgi_fifo_table['c'] = uwsgi_chain_reload; + uwsgi_fifo_table['f'] = uwsgi_refork_master; + uwsgi_fifo_table['l'] = uwsgi_log_reopen; + uwsgi_fifo_table['L'] = uwsgi_log_rotate; + uwsgi_fifo_table['p'] = suspend_resume_them_all; + uwsgi_fifo_table['Q'] = kill_them_all; + uwsgi_fifo_table['r'] = grace_them_all; + uwsgi_fifo_table['R'] = reap_them_all; + uwsgi_fifo_table['s'] = stats; + uwsgi_fifo_table['w'] = uwsgi_reload_workers; + +} + +int uwsgi_master_fifo(char *path) { + + unlink(path); + + if (mkfifo(path, S_IRUSR|S_IWUSR)) { + uwsgi_error("uwsgi_master_fifo()/mkfifo()"); + exit(1); + } + + int fd = open(path, O_RDONLY|O_NONBLOCK); + if (fd < 0) { + uwsgi_error("uwsgi_master_fifo()/open()"); + exit(1); + } + + uwsgi_socket_nb(fd); + + return fd; +} + +int uwsgi_master_fifo_manage(int fd) { + char cmd; + ssize_t rlen = read(fd, &cmd, 1); + if (rlen < 0) { + if (uwsgi_is_again()) return 0; + uwsgi_error("uwsgi_master_fifo_manage()/read()"); + exit(1); + } + // fifo destroyed, recreate it + else if (rlen == 0) { + close(fd); + uwsgi.master_fifo_fd = uwsgi_master_fifo(uwsgi.master_fifo); + event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd); + return 0; + } + + if (uwsgi_fifo_table[(int) cmd]) { + uwsgi_fifo_table[(int) cmd](0); + } + + return 0; +} diff --git a/core/init.c b/core/init.c index 8146a210..2d9875fd 100644 --- a/core/init.c +++ b/core/init.c @@ -172,6 +172,11 @@ void uwsgi_init_default() { // 1 MB default limit uwsgi.chunked_input_limit = 1024*1024; + + // clear reforked status + uwsgi.master_is_reforked = 0; + + uwsgi_master_fifo_prepare(); } void uwsgi_setup_reload() { diff --git a/core/logging.c b/core/logging.c index e888d32e..2dc92072 100644 --- a/core/logging.c +++ b/core/logging.c @@ -488,7 +488,6 @@ void uwsgi_logvar_add(struct wsgi_request *wsgi_req, char *key, uint8_t keylen, void uwsgi_check_logrotate(void) { - char message[1024]; int need_rotation = 0; int need_reopen = 0; @@ -512,70 +511,81 @@ void uwsgi_check_logrotate(void) { } if (need_rotation) { - - char *rot_name = uwsgi.log_backupname; - int need_free = 0; - if (rot_name == NULL) { - char *ts_str = uwsgi_num2str((int) uwsgi_now()); - rot_name = uwsgi_concat3(uwsgi.logfile, ".", ts_str); - free(ts_str); - need_free = 1; - } - int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering rotation to %s...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize, rot_name); - if (ret > 0) { - if (write(uwsgi.original_log_fd, message, ret) != ret) { - // very probably this will never be printed - uwsgi_error("write()"); - } - } - if (rename(uwsgi.logfile, rot_name) == 0) { - // reopen logfile dup'it and eventually gracefully reload workers; - int fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); - if (fd < 0) { - uwsgi_error_open(uwsgi.logfile); - grace_them_all(0); - } - else { - if (dup2(fd, uwsgi.original_log_fd) < 0) { - uwsgi_error("dup2()"); - grace_them_all(0); - } - close(fd); - } - } - else { - uwsgi_error("unable to rotate log: rename()"); - } - if (need_free) - free(rot_name); + uwsgi_log_rotate(); } else if (need_reopen) { - int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering log-reopen...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize); - if (ret > 0) { - if (write(uwsgi.original_log_fd, message, ret) != ret) { - // very probably this will never be printed - uwsgi_error("write()"); - } - } - - // reopen logfile; - close(uwsgi.original_log_fd); - uwsgi.original_log_fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP); - if (uwsgi.original_log_fd < 0) { - uwsgi_error_open(uwsgi.logfile); - grace_them_all(0); - } - ret = snprintf(message, 1024, "[%d] %s reopened.\n", (int) uwsgi_now(), uwsgi.logfile); - if (ret > 0) { - if (write(uwsgi.original_log_fd, message, ret) != ret) { - // very probably this will never be printed - uwsgi_error("write()"); - } - } - uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR); + uwsgi_log_reopen(); } } +void uwsgi_log_rotate() { + char message[1024]; + if (!uwsgi.logfile) return; + char *rot_name = uwsgi.log_backupname; + int need_free = 0; + if (rot_name == NULL) { + char *ts_str = uwsgi_num2str((int) uwsgi_now()); + rot_name = uwsgi_concat3(uwsgi.logfile, ".", ts_str); + free(ts_str); + need_free = 1; + } + int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering rotation to %s...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize, rot_name); + if (ret > 0) { + if (write(uwsgi.original_log_fd, message, ret) != ret) { + // very probably this will never be printed + uwsgi_error("write()"); + } + } + if (rename(uwsgi.logfile, rot_name) == 0) { + // reopen logfile dup'it and eventually gracefully reload workers; + int fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP); + if (fd < 0) { + uwsgi_error_open(uwsgi.logfile); + grace_them_all(0); + } + else { + if (dup2(fd, uwsgi.original_log_fd) < 0) { + uwsgi_error("dup2()"); + grace_them_all(0); + } + close(fd); + } + } + else { + uwsgi_error("unable to rotate log: rename()"); + } + if (need_free) + free(rot_name); +} + +void uwsgi_log_reopen() { + char message[1024]; + if (!uwsgi.logfile) return; + int ret = snprintf(message, 1024, "[%d] logsize: %llu, triggering log-reopen...\n", (int) uwsgi_now(), (unsigned long long) uwsgi.shared->logsize); + if (ret > 0) { + if (write(uwsgi.original_log_fd, message, ret) != ret) { + // very probably this will never be printed + uwsgi_error("write()"); + } + } + + // reopen logfile; + close(uwsgi.original_log_fd); + uwsgi.original_log_fd = open(uwsgi.logfile, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR | S_IRGRP); + if (uwsgi.original_log_fd < 0) { + uwsgi_error_open(uwsgi.logfile); + grace_them_all(0); + } + ret = snprintf(message, 1024, "[%d] %s reopened.\n", (int) uwsgi_now(), uwsgi.logfile); + if (ret > 0) { + if (write(uwsgi.original_log_fd, message, ret) != ret) { + // very probably this will never be printed + uwsgi_error("write()"); + } + } + uwsgi.shared->logsize = lseek(uwsgi.original_log_fd, 0, SEEK_CUR); +} + void log_request(struct wsgi_request *wsgi_req) { diff --git a/core/master.c b/core/master.c index f3451e99..83954207 100644 --- a/core/master.c +++ b/core/master.c @@ -306,7 +306,6 @@ int master_loop(char **argv, char **environ) { struct uwsgi_rb_timer *min_timeout; struct uwsgi_rbtree *rb_timers = uwsgi_init_rb_timer(); - if (uwsgi.procname_master) { uwsgi_set_processname(uwsgi.procname_master); } @@ -346,6 +345,11 @@ int master_loop(char **argv, char **environ) { #endif event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_signal_pipe[0]); + if (uwsgi.master_fifo) { + uwsgi.master_fifo_fd = uwsgi_master_fifo(uwsgi.master_fifo); + event_queue_add_fd_read(uwsgi.master_queue, uwsgi.master_fifo_fd); + } + if (uwsgi.spoolers) { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->spooler_signal_pipe[0]); } @@ -766,13 +770,7 @@ int master_loop(char **argv, char **environ) { touched = uwsgi_check_touches(uwsgi.touch_workers_reload); if (touched) { uwsgi_log_verbose("*** %s has been touched... workers reload !!! ***\n", touched); - uwsgi_block_signal(SIGHUP); - for(i=1;i<=uwsgi.numproc;i++) { - if (uwsgi.workers[i].pid > 0) { - uwsgi_curse(i, SIGHUP); - } - } - uwsgi_unblock_signal(SIGHUP); + uwsgi_reload_workers(); continue; } touched = uwsgi_check_touches(uwsgi.touch_chain_reload); @@ -964,3 +962,24 @@ next: // never here } + +void uwsgi_reload_workers() { + int i; + uwsgi_block_signal(SIGHUP); + for(i=1;i<=uwsgi.numproc;i++) { + if (uwsgi.workers[i].pid > 0) { + uwsgi_curse(i, SIGHUP); + } + } + uwsgi_unblock_signal(SIGHUP); +} + +void uwsgi_chain_reload() { + if (!uwsgi.status.chain_reloading) { + uwsgi_log_verbose("chain reload starting...\n"); + uwsgi.status.chain_reloading = 1; + } + else { + uwsgi_log_verbose("chain reload already running...\n"); + } +} diff --git a/core/master_events.c b/core/master_events.c index 00ac30ca..e4b78e8e 100644 --- a/core/master_events.c +++ b/core/master_events.c @@ -18,6 +18,10 @@ int uwsgi_master_manage_events(int interesting_fd) { } } + if (uwsgi.master_fifo_fd > -1 && interesting_fd == uwsgi.master_fifo_fd) { + return uwsgi_master_fifo_manage(uwsgi.master_fifo_fd); + } + // stats server ? if (uwsgi.stats && uwsgi.stats_fd > -1) { if (interesting_fd == uwsgi.stats_fd) { diff --git a/core/master_utils.c b/core/master_utils.c index 045c6968..5a9ff0f2 100644 --- a/core/master_utils.c +++ b/core/master_utils.c @@ -353,23 +353,30 @@ void uwsgi_reload(char **argv) { int i; int waitpid_status; - // call a series of waitpid to ensure all processes (gateways, mules and daemons) are dead - for (i = 0; i < (ushared->gateways_cnt + uwsgi.daemons_cnt + uwsgi.mules_cnt); i++) { - waitpid(WAIT_ANY, &waitpid_status, WNOHANG); + if (!uwsgi.master_is_reforked) { + + // call a series of waitpid to ensure all processes (gateways, mules and daemons) are dead + for (i = 0; i < (ushared->gateways_cnt + uwsgi.daemons_cnt + uwsgi.mules_cnt); i++) { + waitpid(WAIT_ANY, &waitpid_status, WNOHANG); + } + + // call master cleanup hooks + uwsgi_master_cleanup_hooks(); + + // call atexit user exec + uwsgi_exec_atexit(); + + if (uwsgi.exit_on_reload) { + uwsgi_log("uWSGI: GAME OVER (insert coin)\n"); + exit(0); + } + + uwsgi_log("binary reloading uWSGI...\n"); + } + else { + uwsgi_log("fork()'ing uWSGI...\n"); } - // call master cleanup hooks - uwsgi_master_cleanup_hooks(); - - // call atexit user exec - uwsgi_exec_atexit(); - - if (uwsgi.exit_on_reload) { - uwsgi_log("uWSGI: GAME OVER (insert coin)\n"); - exit(0); - } - - uwsgi_log("binary reloading uWSGI...\n"); uwsgi_log("chdir() to %s\n", uwsgi.cwd); if (chdir(uwsgi.cwd)) { uwsgi_error("chdir()"); @@ -556,6 +563,7 @@ void uwsgi_fixup_fds(int wid, int muleid, struct uwsgi_gateway *ug) { } } + if (uwsgi.master_fifo_fd > -1) close(uwsgi.master_fifo_fd); } @@ -1512,3 +1520,24 @@ void uwsgi_add_reload_fds() { add_reload_fds(uwsgi.reload_on_fd, "graceful"); add_reload_fds(uwsgi.brutal_reload_on_fd, "brutal"); } + +void uwsgi_refork_master() { + pid_t pid = fork(); + if (pid < 0) { + uwsgi_error("uwsgi_refork_master()/fork()"); + return; + } + + if (pid > 0) { + uwsgi_log_verbose("new master copy spawned with pid %d\n", (int) pid); + return; + } + + // detach from the old master + setsid(); + + uwsgi.master_is_reforked = 1; + uwsgi_reload(uwsgi.argv); + // never here + exit(1); +} diff --git a/core/socket.c b/core/socket.c index 322234ef..0016aea4 100644 --- a/core/socket.c +++ b/core/socket.c @@ -1983,3 +1983,4 @@ int uwsgi_accept(int server_fd) { } + diff --git a/core/uwsgi.c b/core/uwsgi.c index ab888081..cc061ff9 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -462,7 +462,7 @@ static struct uwsgi_option uwsgi_base_options[] = { {"fs-brutal-reload", required_argument, 0, "brutal reload when the specified filesystem object is modified", uwsgi_opt_add_string_list, &uwsgi.fs_brutal_reload, UWSGI_OPT_MASTER}, {"fs-signal", required_argument, 0, "raise a uwsgi signal when the specified filesystem object is modified (syntax: file signal)", uwsgi_opt_add_string_list, &uwsgi.fs_signal, UWSGI_OPT_MASTER}, - {"propagate-touch", no_argument, 0, "over-engineering option for system with flaky signal mamagement", uwsgi_opt_true, &uwsgi.propagate_touch, 0}, + {"propagate-touch", no_argument, 0, "over-engineering option for system with flaky signal management", uwsgi_opt_true, &uwsgi.propagate_touch, 0}, {"limit-post", required_argument, 0, "limit request body", uwsgi_opt_set_64bit, &uwsgi.limit_post, 0}, {"no-orphans", no_argument, 0, "automatically kill workers if master dies (can be dangerous for availability)", uwsgi_opt_true, &uwsgi.no_orphans, 0}, {"prio", required_argument, 0, "set processes/threads priority", uwsgi_opt_set_rawint, &uwsgi.prio, 0}, @@ -495,6 +495,8 @@ static struct uwsgi_option uwsgi_base_options[] = { {"multicast-ttl", required_argument, 0, "set multicast ttl", uwsgi_opt_set_int, &uwsgi.multicast_ttl, 0}, {"multicast-loop", required_argument, 0, "set multicast loop (default 1)", uwsgi_opt_set_int, &uwsgi.multicast_loop, 0}, + {"master-fifo", required_argument, 0, "enable the master fifo", uwsgi_opt_set_str, &uwsgi.master_fifo, UWSGI_OPT_MASTER}, + #ifdef UWSGI_SSL {"legion", required_argument, 0, "became a member of a legion", uwsgi_opt_legion, NULL, UWSGI_OPT_MASTER}, {"legion-mcast", required_argument, 0, "became a member of a legion (shortcut for multicast)", uwsgi_opt_legion_mcast, NULL, UWSGI_OPT_MASTER}, diff --git a/uwsgi.h b/uwsgi.h index c54b4586..4fa5a17c 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -1686,6 +1686,11 @@ struct uwsgi_server { int drop_after_init; int drop_after_apps; + int master_is_reforked; + + char *master_fifo; + int master_fifo_fd; + // kill the stack on SIGTERM (instead of brutal reloading) int die_on_term; @@ -4309,6 +4314,17 @@ void uwsgi_log_encoders_register_embedded(void); void uwsgi_register_log_encoder(char *, char *(*)(struct uwsgi_log_encoder *, char *, size_t, size_t *)); int uwsgi_accept(int); +void suspend_resume_them_all(int); + +void uwsgi_master_fifo_prepare(); +int uwsgi_master_fifo(char *); +int uwsgi_master_fifo_manage(int); + +void uwsgi_log_rotate(); +void uwsgi_log_reopen(); +void uwsgi_reload_workers(); +void uwsgi_chain_reload(); +void uwsgi_refork_master(); #ifdef __cplusplus } diff --git a/uwsgiconfig.py b/uwsgiconfig.py index 849d8301..bd92bdb6 100644 --- a/uwsgiconfig.py +++ b/uwsgiconfig.py @@ -507,7 +507,7 @@ class uConf(object): self.config.readfp(open_profile(filename)) self.gcc_list = ['core/utils', 'core/protocol', 'core/socket', 'core/logging', 'core/master', 'core/master_utils', 'core/emperor', - 'core/notify', 'core/mule', 'core/subscription', 'core/stats', 'core/sendfile', 'core/async', 'core/master_checks', + 'core/notify', 'core/mule', 'core/subscription', 'core/stats', 'core/sendfile', 'core/async', 'core/master_checks', 'core/fifo', 'core/offload', 'core/io', 'core/static', 'core/websockets', 'core/spooler', 'core/snmp', 'core/exceptions', 'core/config', 'core/setup_utils', 'core/clock', 'core/init', 'core/buffer', 'core/reader', 'core/writer', 'core/alarm', 'core/cron', 'core/hooks', 'core/plugins', 'core/lock', 'core/cache', 'core/daemons', 'core/errors', 'core/hash', 'core/master_events', 'core/chunked',