first big (really bug) master refactoring

This commit is contained in:
Unbit
2013-02-12 18:42:36 +01:00
parent 7d8aa98766
commit 79dccaac9c
10 changed files with 730 additions and 725 deletions
+56
View File
@@ -1289,3 +1289,59 @@ next:
return -1;
}
static void *logger_thread_loop(void *noarg) {
struct pollfd logpoll[2];
// block all signals
sigset_t smask;
sigfillset(&smask);
pthread_sigmask(SIG_BLOCK, &smask, NULL);
logpoll[0].events = POLLIN;
logpoll[0].fd = uwsgi.shared->worker_log_pipe[0];
int logpolls = 1;
if (uwsgi.req_log_master) {
logpoll[1].events = POLLIN;
logpoll[1].fd = uwsgi.shared->worker_req_log_pipe[0];
}
for (;;) {
int ret = poll(logpoll, logpolls, -1);
if (ret > 0) {
if (logpoll[0].revents & POLLIN) {
pthread_mutex_lock(&uwsgi.threaded_logger_lock);
uwsgi_master_log();
pthread_mutex_unlock(&uwsgi.threaded_logger_lock);
}
else if (logpolls > 1 && logpoll[1].revents & POLLIN) {
pthread_mutex_lock(&uwsgi.threaded_logger_lock);
uwsgi_master_req_log();
pthread_mutex_unlock(&uwsgi.threaded_logger_lock);
}
}
}
return NULL;
}
void uwsgi_threaded_logger_spawn() {
pthread_t logger_thread;
if (pthread_create(&logger_thread, NULL, logger_thread_loop, NULL)) {
uwsgi_error("pthread_create()");
uwsgi_log("falling back to non-threaded logger...\n");
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_log_pipe[0]);
if (uwsgi.req_log_master) {
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_req_log_pipe[0]);
}
uwsgi.threaded_logger = 0;
}
}
+72 -547
View File
@@ -31,19 +31,6 @@ void uwsgi_unblock_signal(int signum) {
}
}
void uwsgi_master_manage_snmp(int snmp_fd) {
struct sockaddr_in udp_client;
socklen_t udp_len = sizeof(udp_client);
ssize_t rlen = recvfrom(snmp_fd, uwsgi.wsgi_req->buffer, uwsgi.buffer_size, 0, (struct sockaddr *) &udp_client, &udp_len);
if (rlen < 0) {
uwsgi_error("recvfrom()");
}
else if (rlen > 0) {
manage_snmp(snmp_fd, (uint8_t *) uwsgi.wsgi_req->buffer, rlen, &udp_client);
}
}
void uwsgi_master_manage_udp(int udp_fd) {
struct sockaddr_in udp_client;
char udp_client_addr[16];
@@ -98,7 +85,7 @@ void uwsgi_master_manage_emperor() {
// remove me
if (byte == 0) {
close(uwsgi.emperor_fd);
if (!uwsgi.to_hell)
if (!uwsgi.status.brutally_reloading)
kill_them_all(0);
}
// reload me
@@ -113,7 +100,7 @@ void uwsgi_master_manage_emperor() {
else {
uwsgi_log("lost connection with my emperor !!!\n");
close(uwsgi.emperor_fd);
if (!uwsgi.to_hell)
if (!uwsgi.status.brutally_reloading)
kill_them_all(0);
sleep(2);
exit(1);
@@ -176,45 +163,28 @@ void suspend_resume_them_all(int signum) {
}
int uwsgi_master_check_mercy() {
void uwsgi_master_check_mercy() {
int i, waitpid_status;
if (uwsgi.master_mercy) {
if (uwsgi.master_mercy < uwsgi_now()) {
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid > 0) {
if (uwsgi.lazy && uwsgi.workers[i].destroy == 0)
continue;
uwsgi_log("worker %d (pid: %d) is taking too much time to die...NO MERCY !!!\n", i, uwsgi.workers[i].pid);
if (!kill(uwsgi.workers[i].pid, SIGKILL)) {
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
uwsgi_error("waitpid()");
}
uwsgi.workers[i].pid = 0;
if (uwsgi.to_hell) {
uwsgi.ready_to_die++;
}
else if (uwsgi.to_heaven) {
uwsgi.ready_to_reload++;
}
else if (uwsgi.to_outworld) {
uwsgi.lazy_respawned++;
if (uwsgi_respawn_worker(i))
return -1;
}
}
else {
uwsgi_error("kill()");
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cursed_at) {
if (uwsgi_now() > uwsgi.workers[i].no_mercy_at) {
uwsgi_log("worker %d (pid: %d) is taking too much time to die...NO MERCY !!!\n", i, uwsgi.workers[i].pid);
if (!kill(uwsgi.workers[i].pid, SIGKILL)) {
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
uwsgi_error("uwsgi_master_check_mercy()/waitpid()");
}
}
else {
uwsgi_error("uwsgi_master_check_mercy()/kill()");
}
uwsgi.workers[i].pid = 0;
uwsgi.workers[i].cursed_at = 0;
uwsgi.workers[i].no_mercy_at = 0;
}
uwsgi.master_mercy = 0;
}
}
return 0;
}
@@ -248,46 +218,6 @@ void expire_rb_timeouts(struct uwsgi_rbtree *tree) {
}
}
void *logger_thread_loop(void *noarg) {
struct pollfd logpoll[2];
// block all signals
sigset_t smask;
sigfillset(&smask);
pthread_sigmask(SIG_BLOCK, &smask, NULL);
logpoll[0].events = POLLIN;
logpoll[0].fd = uwsgi.shared->worker_log_pipe[0];
int logpolls = 1;
if (uwsgi.req_log_master) {
logpoll[1].events = POLLIN;
logpoll[1].fd = uwsgi.shared->worker_req_log_pipe[0];
}
for (;;) {
int ret = poll(logpoll, logpolls, -1);
if (ret > 0) {
if (logpoll[0].revents & POLLIN) {
pthread_mutex_lock(&uwsgi.threaded_logger_lock);
uwsgi_master_log();
pthread_mutex_unlock(&uwsgi.threaded_logger_lock);
}
else if (logpolls > 1 && logpoll[1].revents & POLLIN) {
pthread_mutex_lock(&uwsgi.threaded_logger_lock);
uwsgi_master_req_log();
pthread_mutex_unlock(&uwsgi.threaded_logger_lock);
}
}
}
return NULL;
}
int uwsgi_get_tcp_info(int fd) {
#if defined(__linux__) || defined(__FreeBSD__)
@@ -369,25 +299,13 @@ int get_linux_unbit_SIOBKLGQ(int fd) {
int master_loop(char **argv, char **environ) {
uint64_t tmp_counter;
struct timeval last_respawn;
int last_respawn_rate = 0;
int pid_found = 0;
pid_t diedpid;
int waitpid_status;
uint8_t uwsgi_signal;
time_t last_request_timecheck = 0, now = 0;
uint64_t last_request_count = 0;
pthread_t logger_thread;
int udp_fd = -1;
int snmp_fd = -1;
time_t now = 0;
int i = 0;
int rlen;
@@ -457,15 +375,7 @@ int master_loop(char **argv, char **environ) {
}
}
else {
if (pthread_create(&logger_thread, NULL, logger_thread_loop, NULL)) {
uwsgi_error("pthread_create()");
uwsgi_log("falling back to non-threaded logger...\n");
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_log_pipe[0]);
if (uwsgi.req_log_master) {
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_req_log_pipe[0]);
}
uwsgi.threaded_logger = 0;
}
uwsgi_threaded_logger_spawn();
}
#ifdef UWSGI_ALARM
@@ -519,19 +429,19 @@ int master_loop(char **argv, char **environ) {
}
if (uwsgi.udp_socket) {
udp_fd = bind_to_udp(uwsgi.udp_socket, 0, 0);
if (udp_fd < 0) {
uwsgi.udp_fd = bind_to_udp(uwsgi.udp_socket, 0, 0);
if (uwsgi.udp_fd < 0) {
uwsgi_log("unable to bind to udp socket. SNMP services will be disabled.\n");
}
else {
uwsgi_log("UDP server enabled.\n");
event_queue_add_fd_read(uwsgi.master_queue, udp_fd);
event_queue_add_fd_read(uwsgi.master_queue, uwsgi.udp_fd);
}
}
snmp_fd = uwsgi_setup_snmp();
uwsgi.snmp_fd = uwsgi_setup_snmp();
if (uwsgi.cheap) {
if (uwsgi.status.is_cheap) {
uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1);
for (i = 1; i <= uwsgi.numproc; i++) {
uwsgi.workers[i].cheaped = 1;
@@ -573,8 +483,10 @@ int master_loop(char **argv, char **environ) {
uwsgi_check_touches(uwsgi.touch_reload);
uwsgi_check_touches(uwsgi.touch_logrotate);
uwsgi_check_touches(uwsgi.touch_logreopen);
uwsgi_check_touches(uwsgi.touch_chain_reload);
uwsgi_check_touches(uwsgi.touch_gracefully_stop);
// setup cheaper algos
// setup cheaper algos (can be stacked)
uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare;
if (uwsgi.requested_cheaper_algo) {
uwsgi.cheaper_algo = NULL;
@@ -611,28 +523,27 @@ int master_loop(char **argv, char **environ) {
}
}
uwsgi_daemons_smart_check();
if (uwsgi.to_outworld) {
//uwsgi_log("%d/%d\n", uwsgi.lazy_respawned, uwsgi.numproc);
if (uwsgi.lazy_respawned >= uwsgi.marked_workers || uwsgi.lazy_respawned >= uwsgi.numproc) {
uwsgi.to_outworld = 0;
uwsgi.master_mercy = 0;
uwsgi.lazy_respawned = 0;
}
// check for death
uwsgi_master_check_death();
// check for realod
if (uwsgi_master_check_reload(argv)) {
return -1;
}
// check if some worker is taking too much to die...
uwsgi_master_check_mercy();
if (uwsgi_master_check_mercy())
return 0;
// check for daemons (smart and dumb)
uwsgi_daemons_smart_check();
if (uwsgi.respawn_workers) {
for (i = 1; i <= uwsgi.respawn_workers; i++) {
if (uwsgi.respawn_snapshots) {
for (i = 1; i <= uwsgi.respawn_snapshots; i++) {
if (uwsgi_respawn_worker(i))
return 0;
}
uwsgi.respawn_workers = 0;
uwsgi.respawn_snapshots = 0;
}
if (uwsgi.restore_snapshot) {
@@ -641,51 +552,18 @@ int master_loop(char **argv, char **environ) {
}
// cheaper management
if (uwsgi.cheaper && !uwsgi.cheap && !uwsgi.to_heaven && !uwsgi.to_hell && !uwsgi.to_outworld && !uwsgi.workers[0].suspended) {
if (uwsgi.cheaper && !uwsgi.status.is_cheap && !uwsgi_instance_is_reloading && !uwsgi_instance_is_dying && !uwsgi.workers[0].suspended) {
if (!uwsgi_calc_cheaper())
return 0;
}
if ((uwsgi.cheap || uwsgi.ready_to_die >= uwsgi.marked_workers || uwsgi.ready_to_die >= uwsgi.numproc) && uwsgi.to_hell) {
// 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++) {
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
}
uwsgi_log("goodbye to uWSGI.\n");
exit(0);
}
if ((uwsgi.cheap || uwsgi.ready_to_reload >= uwsgi.marked_workers || uwsgi.ready_to_reload >= uwsgi.numproc) && uwsgi.to_heaven) {
uwsgi_reload(argv);
// never here (unless in shared library mode)
return -1;
}
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].stopped_at > 0 && uwsgi.workers[i].pid > 0 && (uwsgi_now() - uwsgi.workers[i].stopped_at >= uwsgi.worker_reload_mercy)) {
uwsgi_log("worker %d is taking too much time to die (%ds), sending SIGKILL\n",i, (int) (uwsgi_now() - uwsgi.workers[i].stopped_at));
kill(uwsgi.workers[i].pid, SIGKILL);
}
}
// check if someone is dead
diedpid = waitpid(WAIT_ANY, &waitpid_status, WNOHANG);
if (diedpid == -1) {
if (errno == ECHILD) {
// something did not work as expected, just assume all has been cleared
if (uwsgi.to_heaven) {
uwsgi.ready_to_reload = uwsgi.numproc;
continue;
}
else if (uwsgi.to_hell) {
uwsgi.ready_to_die = uwsgi.numproc;
continue;
}
else if (uwsgi.to_outworld) {
uwsgi.lazy_respawned = uwsgi.numproc;
uwsgi_log("*** no workers to reload found ***\n");
continue;
}
uwsgi_master_commit_status();
diedpid = 0;
}
else {
@@ -697,6 +575,7 @@ int master_loop(char **argv, char **environ) {
}
}
// no one died just run all of the standard master tasks
if (diedpid == 0) {
/* all processes ok, doing status scan after N seconds */
@@ -784,181 +663,14 @@ int master_loop(char **argv, char **environ) {
uwsgi_unlock(uwsgi.probe_table_lock);
}
// some event returned
if (rlen > 0) {
if (uwsgi.log_master && !uwsgi.threaded_logger) {
if (interesting_fd == uwsgi.shared->worker_log_pipe[0]) {
uwsgi_master_log();
goto health_cycle;
}
if (uwsgi.req_log_master && interesting_fd == uwsgi.shared->worker_req_log_pipe[0]) {
uwsgi_master_req_log();
goto health_cycle;
}
// if the following function returns -1, a new worker has just spawned
if (uwsgi_master_manage_events(interesting_fd)) {
return 0;
}
if (uwsgi.stats && uwsgi.stats_fd > -1) {
if (interesting_fd == uwsgi.stats_fd) {
uwsgi_send_stats(uwsgi.stats_fd, uwsgi_master_generate_stats);
goto health_cycle;
}
}
if (uwsgi.zerg_server) {
if (interesting_fd == uwsgi.zerg_server_fd) {
uwsgi_manage_zerg(uwsgi.zerg_server_fd, 0, NULL);
goto health_cycle;
}
}
if (uwsgi.has_emperor) {
if (interesting_fd == uwsgi.emperor_fd) {
uwsgi_master_manage_emperor();
goto health_cycle;
}
}
if (uwsgi.cheap) {
int found = 0;
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (interesting_fd == uwsgi_sock->fd) {
found = 1;
uwsgi.cheap = 0;
uwsgi_del_sockets_from_queue(uwsgi.master_queue);
int needed = uwsgi.numproc;
if (uwsgi.cheaper) {
needed = uwsgi.cheaper_count;
}
for (i = 1; i <= needed; i++) {
if (uwsgi_respawn_worker(i))
return 0;
}
break;
}
uwsgi_sock = uwsgi_sock->next;
}
// here is better to continue instead going to health_cycle
if (found)
continue;
}
if (uwsgi.snmp_addr && interesting_fd == snmp_fd) {
uwsgi_master_manage_snmp(snmp_fd);
goto health_cycle;
}
if (uwsgi.udp_socket && interesting_fd == udp_fd) {
uwsgi_master_manage_udp(udp_fd);
goto health_cycle;
}
int next_iteration = 0;
uwsgi_lock(uwsgi.fmon_table_lock);
for (i = 0; i < ushared->files_monitored_cnt; i++) {
if (ushared->files_monitored[i].registered) {
if (interesting_fd == ushared->files_monitored[i].fd) {
struct uwsgi_fmon *uf = event_queue_ack_file_monitor(uwsgi.master_queue, interesting_fd);
// now call the file_monitor handler
if (uf)
uwsgi_route_signal(uf->sig);
break;
}
}
}
uwsgi_unlock(uwsgi.fmon_table_lock);
if (next_iteration)
goto health_cycle;;
next_iteration = 0;
uwsgi_lock(uwsgi.timer_table_lock);
for (i = 0; i < ushared->timers_cnt; i++) {
if (ushared->timers[i].registered) {
if (interesting_fd == ushared->timers[i].fd) {
struct uwsgi_timer *ut = event_queue_ack_timer(interesting_fd);
// now call the file_monitor handler
if (ut)
uwsgi_route_signal(ut->sig);
break;
}
}
}
uwsgi_unlock(uwsgi.timer_table_lock);
if (next_iteration)
goto health_cycle;;
// check for worker signal
if (interesting_fd == uwsgi.shared->worker_signal_pipe[0]) {
rlen = read(interesting_fd, &uwsgi_signal, 1);
if (rlen < 0) {
uwsgi_error("read()");
}
else if (rlen > 0) {
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("received uwsgi signal %d from a worker\n", uwsgi_signal);
#endif
uwsgi_route_signal(uwsgi_signal);
}
else {
uwsgi_log_verbose("lost connection with worker %d\n", i);
close(interesting_fd);
}
goto health_cycle;
}
// check for spooler signal
if (uwsgi.spoolers) {
if (interesting_fd == uwsgi.shared->spooler_signal_pipe[0]) {
rlen = read(interesting_fd, &uwsgi_signal, 1);
if (rlen < 0) {
uwsgi_error("read()");
}
else if (rlen > 0) {
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("received uwsgi signal %d from a spooler\n", uwsgi_signal);
#endif
uwsgi_route_signal(uwsgi_signal);
}
else {
uwsgi_log_verbose("lost connection with the spooler\n");
close(interesting_fd);
}
goto health_cycle;
}
}
// check for mules signal
if (uwsgi.mules_cnt > 0) {
if (interesting_fd == uwsgi.shared->mule_signal_pipe[0]) {
rlen = read(interesting_fd, &uwsgi_signal, 1);
if (rlen < 0) {
uwsgi_error("read()");
}
else if (rlen > 0) {
#ifdef UWSGI_DEBUG
uwsgi_log_verbose("received uwsgi signal %d from a mule\n", uwsgi_signal);
#endif
uwsgi_route_signal(uwsgi_signal);
}
else {
uwsgi_log_verbose("lost connection with a mule\n");
close(interesting_fd);
}
goto health_cycle;
}
}
}
health_cycle:
now = uwsgi_now();
if (now - uwsgi.current_time < 1) {
continue;
@@ -975,66 +687,10 @@ health_cycle:
// recalculate requests counter on race conditions risky configurations
// a bit of inaccuracy is better than locking;)
uwsgi_master_fix_request_counters();
if (uwsgi.numproc > 1) {
tmp_counter = 0;
for (i = 1; i < uwsgi.numproc + 1; i++)
tmp_counter += uwsgi.workers[i].requests;
uwsgi.workers[0].requests = tmp_counter;
}
if (uwsgi.idle > 0 && !uwsgi.cheap) {
uwsgi.current_time = uwsgi_now();
if (!last_request_timecheck)
last_request_timecheck = uwsgi.current_time;
int busy_workers = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
if (uwsgi.workers[i].busy == 1) {
busy_workers = 1;
break;
}
}
}
if (last_request_count != uwsgi.workers[0].requests) {
last_request_timecheck = uwsgi.current_time;
last_request_count = uwsgi.workers[0].requests;
}
// a bit of over-engeneering to avoid clock skews
else if (last_request_timecheck < uwsgi.current_time && (uwsgi.current_time - last_request_timecheck > uwsgi.idle) && !busy_workers) {
uwsgi_log("workers have been inactive for more than %d seconds (%llu-%llu)\n", uwsgi.idle, (unsigned long long) uwsgi.current_time, (unsigned long long) last_request_timecheck);
uwsgi.cheap = 1;
if (uwsgi.die_on_idle) {
if (uwsgi.has_emperor) {
char byte = 22;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("write()");
kill_them_all(0);
}
}
else {
kill_them_all(0);
}
continue;
}
for (i = 1; i <= uwsgi.numproc; i++) {
uwsgi.workers[i].cheaped = 1;
if (uwsgi.workers[i].pid == 0)
continue;
kill(uwsgi.workers[i].pid, SIGKILL);
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
if (errno != ECHILD)
uwsgi_error("waitpid()");
}
}
uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1);
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
last_request_timecheck = 0;
continue;
}
}
// check for idle
uwsgi_master_check_idle();
check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL];
if (!check_interval)
@@ -1057,77 +713,12 @@ health_cycle:
uwsgi_sock = uwsgi_sock->next;
}
for (i = 1; i <= uwsgi.numproc; i++) {
/* first check for harakiri */
if (uwsgi.workers[i].harakiri > 0) {
if (uwsgi.workers[i].harakiri < (time_t) uwsgi.current_time) {
trigger_harakiri(i);
}
}
/* then user-defined harakiri */
if (uwsgi.workers[i].user_harakiri > 0) {
if (uwsgi.workers[i].user_harakiri < (time_t) uwsgi.current_time) {
trigger_harakiri(i);
}
}
// then for evil memory checkers
if (uwsgi.evil_reload_on_as) {
if ((rlim_t) uwsgi.workers[i].vsz_size >= uwsgi.evil_reload_on_as) {
uwsgi_log("*** EVIL RELOAD ON WORKER %d ADDRESS SPACE: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].vsz_size, uwsgi.workers[i].pid);
kill(uwsgi.workers[i].pid, SIGKILL);
uwsgi.workers[i].vsz_size = 0;
}
}
if (uwsgi.evil_reload_on_rss) {
if ((rlim_t) uwsgi.workers[i].rss_size >= uwsgi.evil_reload_on_rss) {
uwsgi_log("*** EVIL RELOAD ON WORKER %d RSS: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].rss_size, uwsgi.workers[i].pid);
kill(uwsgi.workers[i].pid, SIGKILL);
uwsgi.workers[i].rss_size = 0;
}
}
// check if worker was running longer than allowed lifetime
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0) {
uint64_t lifetime = uwsgi_now() - uwsgi.workers[i].last_spawn;
if (lifetime > uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] && uwsgi.workers[i].manage_next_request == 1) {
uwsgi_log("worker %d lifetime reached, it was running for %llu second(s)\n", i, (unsigned long long) lifetime);
uwsgi.workers[i].manage_next_request = 0;
kill(uwsgi.workers[i].pid, SIGWINCH);
}
}
// check if some worker has to die (harakiri, evil checks...)
uwsgi_master_check_workers_deadline();
// need to find a better way
//uwsgi.workers[i].last_running_time = uwsgi.workers[i].running_time;
}
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways_harakiri[i] > 0) {
if (ushared->gateways_harakiri[i] < (time_t) uwsgi.current_time) {
if (ushared->gateways[i].pid > 0) {
kill(ushared->gateways[i].pid, SIGKILL);
}
ushared->gateways_harakiri[i] = 0;
}
}
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].harakiri > 0) {
if (uwsgi.mules[i].harakiri < (time_t) uwsgi.current_time) {
uwsgi_log("*** HARAKIRI ON MULE %d HANDLING SIGNAL %d (pid: %d) ***\n", i + 1, uwsgi.mules[i].signum, uwsgi.mules[i].pid);
kill(uwsgi.mules[i].pid, SIGKILL);
uwsgi.mules[i].harakiri = 0;
}
}
}
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->harakiri > 0 && uspool->harakiri < (time_t) uwsgi.current_time) {
uwsgi_log("*** HARAKIRI ON THE SPOOLER (pid: %d) ***\n", uspool->pid);
kill(uspool->pid, SIGKILL);
uspool->harakiri = 0;
}
uspool = uspool->next;
}
uwsgi_master_check_gateways_deadline();
uwsgi_master_check_mules_deadline();
uwsgi_master_check_spoolers_deadline();
#ifdef __linux__
#ifdef MADV_MERGEABLE
@@ -1138,7 +729,7 @@ health_cycle:
#endif
// resubscribe every 10 cycles by default
if (( (uwsgi.subscriptions || uwsgi.subscriptions2) && ((uwsgi.master_cycles % uwsgi.subscribe_freq) == 0 || uwsgi.master_cycles == 1)) && !uwsgi.to_heaven && !uwsgi.to_hell && !uwsgi.workers[0].suspended) {
if (( (uwsgi.subscriptions || uwsgi.subscriptions2) && ((uwsgi.master_cycles % uwsgi.subscribe_freq) == 0 || uwsgi.master_cycles == 1)) && !uwsgi_instance_is_reloading && !uwsgi_instance_is_dying && !uwsgi.workers[0].suspended) {
uwsgi_subscribe_all(0, 0);
}
@@ -1151,7 +742,7 @@ health_cycle:
}
// check touch_reload
if (!uwsgi.to_heaven && !uwsgi.to_hell) {
if (!uwsgi_instance_is_reloading && !uwsgi_instance_is_dying) {
char *touched = uwsgi_check_touches(uwsgi.touch_reload);
if (touched) {
uwsgi_log("*** %s has been touched... grace them all !!! ***\n", touched);
@@ -1187,64 +778,13 @@ health_cycle:
uwsgi_deadlock_check(diedpid);
// reload gateways and daemons only on normal workflow (+outworld status)
if (!uwsgi.to_heaven && !uwsgi.to_hell) {
/* reload the spooler */
struct uwsgi_spooler *uspool = uwsgi.spoolers;
pid_found = 0;
while (uspool) {
if (uspool->pid > 0 && diedpid == uspool->pid) {
uwsgi_log("OOOPS the spooler is no more...trying respawn...\n");
uspool->respawned++;
uspool->pid = spooler_start(uspool);
pid_found = 1;
break;
}
uspool = uspool->next;
}
if (pid_found)
continue;
if (uwsgi.emperor_pid >= 0) {
uwsgi_log_verbose("!!! Emperor died !!!\n");
uwsgi_emperor_start();
continue;
}
pid_found = 0;
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid == diedpid) {
uwsgi_log("OOOPS mule %d (pid: %d) crippled...trying respawn...\n", i + 1, uwsgi.mules[i].pid);
uwsgi_mule(i + 1);
pid_found = 1;
break;
}
}
if (pid_found)
continue;
/* reload the gateways */
pid_found = 0;
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways[i].pid == diedpid) {
gateway_respawn(i);
pid_found = 1;
break;
}
}
if (pid_found)
continue;
/* reload the daemons */
pid_found = uwsgi_daemon_check_pid_reload(diedpid);
if (pid_found)
continue;
if (!uwsgi_instance_is_reloading && !uwsgi_instance_is_dying) {
if (uwsgi_master_check_emperor_death(diedpid)) continue;
if (uwsgi_master_check_spoolers_death(diedpid)) continue;
if (uwsgi_master_check_mules_death(diedpid)) continue;
if (uwsgi_master_check_gateways_death(diedpid)) continue;
if (uwsgi_master_check_daemons_death(diedpid)) continue;
}
@@ -1302,27 +842,11 @@ next:
// ok a worker died...
if (uwsgi.to_heaven) {
uwsgi.ready_to_reload++;
uwsgi.workers[uwsgi.mywid].pid = 0;
// only to be safe :P
uwsgi.workers[uwsgi.mywid].harakiri = 0;
continue;
}
else if (uwsgi.to_hell) {
uwsgi.ready_to_die++;
uwsgi.workers[uwsgi.mywid].pid = 0;
// only to be safe :P
uwsgi.workers[uwsgi.mywid].harakiri = 0;
continue;
}
else if (uwsgi.to_outworld) {
uwsgi.lazy_respawned++;
uwsgi.workers[uwsgi.mywid].destroy = 0;
uwsgi.workers[uwsgi.mywid].pid = 0;
// only to be safe :P
uwsgi.workers[uwsgi.mywid].harakiri = 0;
}
uwsgi.workers[uwsgi.mywid].pid = 0;
// only to be safe :P
uwsgi.workers[uwsgi.mywid].harakiri = 0;
// if we are stopping workers, just end here
if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_FAILED_APP_CODE) {
uwsgi_log("OOPS ! failed loading app in worker %d (pid %d) :( trying again...\n", uwsgi.mywid, (int) diedpid);
@@ -1344,7 +868,7 @@ next:
uwsgi_log("DAMN ! worker %d (pid: %d) died :( trying respawn ...\n", uwsgi.mywid, (int) diedpid);
}
}
else if (uwsgi.workers[uwsgi.mywid].stopped_at > 0) {
else if (uwsgi.workers[uwsgi.mywid].cursed_at > 0) {
uwsgi_log("worker %d killed successfully (pid: %d)\n", uwsgi.mywid, (int) diedpid);
}
// manage_next_request is zero, but killed by signal...
@@ -1353,11 +877,11 @@ next:
}
if (uwsgi.workers[uwsgi.mywid].cheaped == 1) {
uwsgi.workers[uwsgi.mywid].pid = 0;
uwsgi_log("uWSGI worker %d cheaped.\n", uwsgi.mywid);
uwsgi.workers[uwsgi.mywid].harakiri = 0;
continue;
}
// avoid fork bombing
gettimeofday(&last_respawn, NULL);
if (last_respawn.tv_sec <= uwsgi.respawn_delta + check_interval) {
last_respawn_rate++;
@@ -1376,6 +900,7 @@ next:
gettimeofday(&last_respawn, NULL);
uwsgi.respawn_delta = last_respawn.tv_sec;
// respawn the worker (if needed)
if (uwsgi_respawn_worker(uwsgi.mywid))
return 0;
+250
View File
@@ -0,0 +1,250 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
// check if all of the workers are dead and exit uWSGI
void uwsgi_master_check_death() {
if (uwsgi_instance_is_dying) {
int i;
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi.workers[i].pid > 0) {
return;
}
}
uwsgi_log("goodbye to uWSGI.\n");
exit(0);
}
}
// check if all of the workers are dead, and trigger a reload
int uwsgi_master_check_reload(char **argv) {
if (uwsgi_instance_is_reloading) {
int i;
for(i=1;i<=uwsgi.numproc;i++) {
if (uwsgi.workers[i].pid > 0) {
return 0;
}
}
uwsgi_reload(argv);
// never here (unless in shared library mode)
return -1;
}
return 0;
}
// special function for assuming all of the workers are dead
void uwsgi_master_commit_status() {
int i;
for(i=1;i<=uwsgi.numproc;i++) {
uwsgi.workers[i].pid = 0;
}
}
void uwsgi_master_check_idle() {
static time_t last_request_timecheck = 0;
static uint64_t last_request_count = 0;
int i;
int waitpid_status;
if (!uwsgi.idle || uwsgi.status.is_cheap)
return;
uwsgi.current_time = uwsgi_now();
if (!last_request_timecheck)
last_request_timecheck = uwsgi.current_time;
// security check, stop the check if there are busy workers
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
if (uwsgi.workers[i].busy == 1) {
return;
}
}
}
if (last_request_count != uwsgi.workers[0].requests) {
last_request_timecheck = uwsgi.current_time;
last_request_count = uwsgi.workers[0].requests;
}
// a bit of over-engeneering to avoid clock skews
else if (last_request_timecheck < uwsgi.current_time && (uwsgi.current_time - last_request_timecheck > uwsgi.idle)) {
uwsgi_log("workers have been inactive for more than %d seconds (%llu-%llu)\n", uwsgi.idle, (unsigned long long) uwsgi.current_time, (unsigned long long) last_request_timecheck);
uwsgi.status.is_cheap = 1;
if (uwsgi.die_on_idle) {
if (uwsgi.has_emperor) {
char byte = 22;
if (write(uwsgi.emperor_fd, &byte, 1) != 1) {
uwsgi_error("write()");
kill_them_all(0);
}
}
else {
kill_them_all(0);
}
return;
}
for (i = 1; i <= uwsgi.numproc; i++) {
uwsgi.workers[i].cheaped = 1;
if (uwsgi.workers[i].pid == 0)
continue;
kill(uwsgi.workers[i].pid, SIGKILL);
if (waitpid(uwsgi.workers[i].pid, &waitpid_status, 0) < 0) {
if (errno != ECHILD)
uwsgi_error("uwsgi_master_check_idle()/waitpid()");
}
}
uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1);
uwsgi_log("cheap mode enabled: waiting for socket connection...\n");
last_request_timecheck = 0;
}
}
void uwsgi_master_check_workers_deadline() {
int i;
for (i = 1; i <= uwsgi.numproc; i++) {
/* first check for harakiri */
if (uwsgi.workers[i].harakiri > 0) {
if (uwsgi.workers[i].harakiri < (time_t) uwsgi.current_time) {
trigger_harakiri(i);
}
}
/* then user-defined harakiri */
if (uwsgi.workers[i].user_harakiri > 0) {
if (uwsgi.workers[i].user_harakiri < (time_t) uwsgi.current_time) {
trigger_harakiri(i);
}
}
// then for evil memory checkers
if (uwsgi.evil_reload_on_as) {
if ((rlim_t) uwsgi.workers[i].vsz_size >= uwsgi.evil_reload_on_as) {
uwsgi_log("*** EVIL RELOAD ON WORKER %d ADDRESS SPACE: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].vsz_size, uwsgi.workers[i].pid);
kill(uwsgi.workers[i].pid, SIGKILL);
uwsgi.workers[i].vsz_size = 0;
}
}
if (uwsgi.evil_reload_on_rss) {
if ((rlim_t) uwsgi.workers[i].rss_size >= uwsgi.evil_reload_on_rss) {
uwsgi_log("*** EVIL RELOAD ON WORKER %d RSS: %lld (pid: %d) ***\n", i, (long long) uwsgi.workers[i].rss_size, uwsgi.workers[i].pid);
kill(uwsgi.workers[i].pid, SIGKILL);
uwsgi.workers[i].rss_size = 0;
}
}
// check if worker was running longer than allowed lifetime
if (uwsgi.workers[i].pid > 0 && uwsgi.workers[i].cheaped == 0 && uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] > 0) {
uint64_t lifetime = uwsgi_now() - uwsgi.workers[i].last_spawn;
if (lifetime > uwsgi.shared->options[UWSGI_OPTION_MAX_WORKER_LIFETIME] && uwsgi.workers[i].manage_next_request == 1) {
uwsgi_log("worker %d lifetime reached, it was running for %llu second(s)\n", i, (unsigned long long) lifetime);
uwsgi.workers[i].manage_next_request = 0;
kill(uwsgi.workers[i].pid, SIGWINCH);
}
}
// need to find a better way
//uwsgi.workers[i].last_running_time = uwsgi.workers[i].running_time;
}
}
void uwsgi_master_check_gateways_deadline() {
int i;
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways_harakiri[i] > 0) {
if (ushared->gateways_harakiri[i] < (time_t) uwsgi.current_time) {
if (ushared->gateways[i].pid > 0) {
kill(ushared->gateways[i].pid, SIGKILL);
}
ushared->gateways_harakiri[i] = 0;
}
}
}
}
void uwsgi_master_check_mules_deadline() {
int i;
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].harakiri > 0) {
if (uwsgi.mules[i].harakiri < (time_t) uwsgi.current_time) {
uwsgi_log("*** HARAKIRI ON MULE %d HANDLING SIGNAL %d (pid: %d) ***\n", i + 1, uwsgi.mules[i].signum, uwsgi.mules[i].pid);
kill(uwsgi.mules[i].pid, SIGKILL);
uwsgi.mules[i].harakiri = 0;
}
}
}
}
void uwsgi_master_check_spoolers_deadline() {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->harakiri > 0 && uspool->harakiri < (time_t) uwsgi.current_time) {
uwsgi_log("*** HARAKIRI ON THE SPOOLER (pid: %d) ***\n", uspool->pid);
kill(uspool->pid, SIGKILL);
uspool->harakiri = 0;
}
uspool = uspool->next;
}
}
int uwsgi_master_check_spoolers_death(int diedpid) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->pid > 0 && diedpid == uspool->pid) {
uwsgi_log("OOOPS the spooler is no more...trying respawn...\n");
uspool->respawned++;
uspool->pid = spooler_start(uspool);
return -1;
}
uspool = uspool->next;
}
return 0;
}
int uwsgi_master_check_emperor_death(int diedpid) {
if (uwsgi.emperor_pid >= 0 && diedpid == uwsgi.emperor_pid) {
uwsgi_log_verbose("!!! Emperor died !!!\n");
uwsgi_emperor_start();
return -1;
}
return 0;
}
int uwsgi_master_check_mules_death(int diedpid) {
int i;
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid == diedpid) {
uwsgi_log("OOOPS mule %d (pid: %d) crippled...trying respawn...\n", i + 1, uwsgi.mules[i].pid);
uwsgi_mule(i + 1);
return -1;
}
}
return 0;
}
int uwsgi_master_check_gateways_death(int diedpid) {
int i;
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways[i].pid == diedpid) {
gateway_respawn(i);
return -1;
}
}
return 0;
}
int uwsgi_master_check_daemons_death(int diedpid) {
/* reload the daemons */
if (uwsgi_daemon_check_pid_reload(diedpid)) {
return -1;
}
return 0;
}
+174
View File
@@ -0,0 +1,174 @@
#include <uwsgi.h>
extern struct uwsgi_server uwsgi;
int uwsgi_master_manage_events(int interesting_fd) {
// is a logline ?
if (uwsgi.log_master && !uwsgi.threaded_logger) {
// stderr log ?
if (interesting_fd == uwsgi.shared->worker_log_pipe[0]) {
uwsgi_master_log();
return 0;
}
// req log ?
if (uwsgi.req_log_master && interesting_fd == uwsgi.shared->worker_req_log_pipe[0]) {
uwsgi_master_req_log();
return 0;
}
}
// stats server ?
if (uwsgi.stats && uwsgi.stats_fd > -1) {
if (interesting_fd == uwsgi.stats_fd) {
uwsgi_send_stats(uwsgi.stats_fd, uwsgi_master_generate_stats);
return 0;
}
}
// a zerg connection ?
if (uwsgi.zerg_server) {
if (interesting_fd == uwsgi.zerg_server_fd) {
uwsgi_manage_zerg(uwsgi.zerg_server_fd, 0, NULL);
return 0;
}
}
// emperor event ?
if (uwsgi.has_emperor) {
if (interesting_fd == uwsgi.emperor_fd) {
uwsgi_master_manage_emperor();
return 0;
}
}
// wakeup from cheap mode ?
if (uwsgi.status.is_cheap) {
struct uwsgi_socket *uwsgi_sock = uwsgi.sockets;
while (uwsgi_sock) {
if (interesting_fd == uwsgi_sock->fd) {
uwsgi.status.is_cheap = 0;
uwsgi_del_sockets_from_queue(uwsgi.master_queue);
// how many worker we need to respawn ?
int needed = uwsgi.numproc;
// if in cheaper mode, just respawn the minimal amount
if (uwsgi.cheaper) {
needed = uwsgi.cheaper_count;
}
int i;
for (i = 1; i <= needed; i++) {
if (uwsgi_respawn_worker(i))
return -1;
}
// here we continue instead of returning
break;
}
uwsgi_sock = uwsgi_sock->next;
}
}
// an SNMP request ?
if (uwsgi.snmp_addr && interesting_fd == uwsgi.snmp_fd) {
uwsgi_master_manage_snmp(uwsgi.snmp_fd);
return 0;
}
// a UDP request ?
if (uwsgi.udp_socket && interesting_fd == uwsgi.udp_fd) {
uwsgi_master_manage_udp(uwsgi.udp_fd);
return 0;
}
// check if some file monitor is ready
// no need to lock as we are only getting registered items (and only the master can register them)
int i;
for (i = 0; i < ushared->files_monitored_cnt; i++) {
if (ushared->files_monitored[i].registered) {
if (interesting_fd == ushared->files_monitored[i].fd) {
struct uwsgi_fmon *uf = event_queue_ack_file_monitor(uwsgi.master_queue, interesting_fd);
// now call the file_monitor handler
if (uf)
uwsgi_route_signal(uf->sig);
return 0;
}
}
}
// check if some timer elapsed
// no need to lock again
for (i = 0; i < ushared->timers_cnt; i++) {
if (ushared->timers[i].registered) {
if (interesting_fd == ushared->timers[i].fd) {
struct uwsgi_timer *ut = event_queue_ack_timer(interesting_fd);
// now call the timer handler
if (ut)
uwsgi_route_signal(ut->sig);
return 0;
}
}
}
uint8_t uwsgi_signal;
// check for worker signal
if (interesting_fd == uwsgi.shared->worker_signal_pipe[0]) {
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
if (rlen < 0) {
uwsgi_error("uwsgi_master_manage_events()/read()");
}
else if (rlen > 0) {
uwsgi_route_signal(uwsgi_signal);
}
else {
// TODO restart workers here
uwsgi_log_verbose("lost connection with workers !!!\n");
close(interesting_fd);
}
return 0;
}
// check for spooler signal
if (uwsgi.spoolers) {
if (interesting_fd == uwsgi.shared->spooler_signal_pipe[0]) {
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
if (rlen < 0) {
uwsgi_error("uwsgi_master_manage_events()/read()");
}
else if (rlen > 0) {
uwsgi_route_signal(uwsgi_signal);
}
else {
// TODO restart spoolers here
uwsgi_log_verbose("lost connection with spoolers\n");
close(interesting_fd);
}
return 0;
}
}
// check for mules signal
if (uwsgi.mules_cnt > 0) {
if (interesting_fd == uwsgi.shared->mule_signal_pipe[0]) {
ssize_t rlen = read(interesting_fd, &uwsgi_signal, 1);
if (rlen < 0) {
uwsgi_error("uwsgi_master_manage_events()/read()");
}
else if (rlen > 0) {
uwsgi_route_signal(uwsgi_signal);
}
else {
// TODO respawn mules here
uwsgi_log_verbose("lost connection with mules\n");
close(interesting_fd);
}
// return 0;
}
}
return 0;
}
+76 -4
View File
@@ -5,6 +5,60 @@ extern struct uwsgi_server uwsgi;
void worker_wakeup() {
}
void uwsgi_curse(int wid, int sig) {
uwsgi.workers[wid].cursed_at = uwsgi_now();
if (uwsgi.reload_mercy) {
uwsgi.workers[wid].no_mercy_at = uwsgi.workers[wid].cursed_at + uwsgi.reload_mercy;
}
else {
uwsgi.workers[wid].no_mercy_at = uwsgi.workers[wid].cursed_at + 5;
}
if (sig) {
(void) kill(uwsgi.workers[wid].pid, sig);
}
}
static void uwsgi_signal_spoolers(int signum) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->pid > 0) {
kill(uspool->pid, SIGKILL);
uwsgi_log("killing the spooler with pid %d\n", uspool->pid);
}
uspool = uspool->next;
}
}
void uwsgi_destroy_processes() {
int i;
uwsgi_signal_spoolers(SIGKILL);
if (uwsgi.emperor_pid >= 0) {
kill(uwsgi.emperor_pid, SIGKILL);
waitpid(uwsgi.emperor_pid, &i, 0);
uwsgi_log("killing the emperor with pid %d\n", uwsgi.emperor_pid);
}
uwsgi_detach_daemons();
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways[i].pid > 0)
kill(ushared->gateways[i].pid, SIGKILL);
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0)
kill(uwsgi.mules[i].pid, SIGKILL);
}
}
void uwsgi_master_cleanup_hooks(void) {
int j;
@@ -13,7 +67,7 @@ void uwsgi_master_cleanup_hooks(void) {
if (uwsgi.mywid > 0)
return;
uwsgi.cleaning = 1;
uwsgi.status.is_cleaning = 1;
for (j = 0; j < uwsgi.gp_cnt; j++) {
if (uwsgi.gp[j]->master_cleanup) {
@@ -78,7 +132,7 @@ int uwsgi_calc_cheaper(void) {
#endif
uwsgi.workers[oldest_worker].cheaped = 1;
uwsgi.workers[oldest_worker].manage_next_request = 0;
uwsgi.workers[oldest_worker].stopped_at = now;
uwsgi.workers[oldest_worker].cursed_at = now;
// wakeup task in case of wait
(void) kill(uwsgi.workers[oldest_worker].pid, SIGWINCH);
}
@@ -476,7 +530,8 @@ int uwsgi_respawn_worker(int wid) {
uwsgi.workers[wid].rss_size = 0;
uwsgi.workers[wid].vsz_size = 0;
// ... reset stopped_at
uwsgi.workers[wid].stopped_at = 0;
uwsgi.workers[wid].cursed_at = 0;
uwsgi.workers[wid].no_mercy_at = 0;
// internal statuses should be reset too
@@ -540,7 +595,7 @@ 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.cheap)) {
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);
@@ -1406,3 +1461,20 @@ void trigger_harakiri(int i) {
// to avoid races
}
void uwsgi_master_fix_request_counters() {
int i;
uint64_t total_counter = 0;
for (i = 1; i <= uwsgi.numproc;i++) {
uint64_t tmp_counter = 0;
int j;
for(j=0;j<uwsgi.cores;j++) {
tmp_counter += uwsgi.workers[i].cores[j].requests;
}
uwsgi.workers[i].requests = tmp_counter;
total_counter += tmp_counter;
}
uwsgi.workers[0].requests = total_counter;
}
+14
View File
@@ -406,3 +406,17 @@ int uwsgi_setup_snmp(void) {
return snmp_fd;
}
void uwsgi_master_manage_snmp(int snmp_fd) {
struct sockaddr_in udp_client;
socklen_t udp_len = sizeof(udp_client);
ssize_t rlen = recvfrom(snmp_fd, uwsgi.wsgi_req->buffer, uwsgi.buffer_size, 0, (struct sockaddr *) &udp_client, &udp_len);
if (rlen < 0) {
uwsgi_error("recvfrom()");
}
else if (rlen > 0) {
manage_snmp(snmp_fd, (uint8_t *) uwsgi.wsgi_req->buffer, rlen, &udp_client);
}
}
+34 -153
View File
@@ -441,7 +441,7 @@ static struct uwsgi_option uwsgi_base_options[] = {
{"chdir2", required_argument, 0, "chdir to specified directory after apps loading", uwsgi_opt_set_str, &uwsgi.chdir2, 0},
{"lazy", no_argument, 0, "set lazy mode (load apps in workers instead of master)", uwsgi_opt_true, &uwsgi.lazy, 0},
{"lazy-apps", no_argument, 0, "load apps in each worker instead of the master", uwsgi_opt_true, &uwsgi.lazy_apps, 0},
{"cheap", no_argument, 0, "set cheap mode (spawn workers only after the first request)", uwsgi_opt_true, &uwsgi.cheap, UWSGI_OPT_MASTER},
{"cheap", no_argument, 0, "set cheap mode (spawn workers only after the first request)", uwsgi_opt_true, &uwsgi.status.is_cheap, UWSGI_OPT_MASTER},
{"cheaper", required_argument, 0, "set cheaper mode (adaptive process spawning)", uwsgi_opt_set_int, &uwsgi.cheaper_count, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
{"cheaper-initial", required_argument, 0, "set the initial number of processes to spawn in cheaper mode", uwsgi_opt_set_int, &uwsgi.cheaper_initial, UWSGI_OPT_MASTER | UWSGI_OPT_CHEAPER},
{"cheaper-algo", required_argument, 0, "choose to algorithm used for adaptive process spawning)", uwsgi_opt_set_str, &uwsgi.requested_cheaper_algo, UWSGI_OPT_MASTER},
@@ -900,7 +900,7 @@ void end_me(int signum) {
void simple_goodbye_cruel_world() {
if (uwsgi.threads > 1 && !uwsgi.to_hell) {
if (uwsgi.threads > 1 && !uwsgi_instance_is_dying) {
wait_for_threads();
}
@@ -910,7 +910,7 @@ void simple_goodbye_cruel_world() {
}
void goodbye_cruel_world() {
uwsgi.workers[uwsgi.mywid].stopped_at = uwsgi_now();
uwsgi_curse(uwsgi.mywid, 0);
if (!uwsgi.gbcw_hook) {
simple_goodbye_cruel_world();
@@ -920,125 +920,39 @@ void goodbye_cruel_world() {
}
}
static void uwsgi_signal_spoolers(int signum) {
struct uwsgi_spooler *uspool = uwsgi.spoolers;
while (uspool) {
if (uspool->pid > 0) {
kill(uspool->pid, SIGKILL);
uwsgi_log("killing the spooler with pid %d\n", uspool->pid);
}
uspool = uspool->next;
}
}
// gracefully destroy
void kill_them_all(int signum) {
int i;
if (uwsgi.to_hell == 1)
return;
// count the number of active workers
int active_workers = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
active_workers++;
}
}
uwsgi.marked_workers = active_workers;
uwsgi.to_hell = 1;
if (uwsgi.reload_mercy > 0) {
uwsgi.master_mercy = uwsgi_now() + uwsgi.reload_mercy;
}
else {
uwsgi.master_mercy = uwsgi_now() + 5;
}
uwsgi_log("SIGINT/SIGQUIT received...killing workers...\n");
if (uwsgi_instance_is_dying) return;
uwsgi.status.gracefully_destroying = 1;
// unsubscribe if needed
uwsgi_unsubscribe_all();
uwsgi_log("SIGINT/SIGQUIT received...killing workers...\n");
int i;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid > 0)
kill(uwsgi.workers[i].pid, SIGINT);
}
uwsgi_signal_spoolers(SIGKILL);
if (uwsgi.emperor_pid >= 0) {
kill(uwsgi.emperor_pid, SIGKILL);
waitpid(uwsgi.emperor_pid, &i, 0);
uwsgi_log("killing the emperor with pid %d\n", uwsgi.emperor_pid);
}
uwsgi_detach_daemons();
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways[i].pid > 0)
kill(ushared->gateways[i].pid, SIGKILL);
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0)
kill(uwsgi.mules[i].pid, SIGKILL);
}
if (uwsgi.workers[i].pid > 0) {
uwsgi_curse(i, SIGINT);
}
}
uwsgi_destroy_processes();
}
// graceful reload
void grace_them_all(int signum) {
if (uwsgi_instance_is_reloading || uwsgi_instance_is_dying)
return;
uwsgi.status.gracefully_reloading = 1;
int i;
int waitpid_status;
if (uwsgi.to_heaven == 1 || uwsgi.to_outworld == 1 || uwsgi.lazy_respawned > 0)
return;
// count the number of active workers
int active_workers = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
active_workers++;
}
}
uwsgi.marked_workers = active_workers;
if (!uwsgi.lazy)
uwsgi.to_heaven = 1;
else
uwsgi.to_outworld = 1;
if (uwsgi.reload_mercy > 0) {
uwsgi.master_mercy = uwsgi_now() + uwsgi.reload_mercy;
}
else {
// wait max 60 seconds for graceful reload
uwsgi.master_mercy = uwsgi_now() + 60;
}
uwsgi_signal_spoolers(SIGKILL);
if (uwsgi.emperor_pid >= 0) {
kill(uwsgi.emperor_pid, SIGKILL);
waitpid(uwsgi.emperor_pid, &i, 0);
uwsgi_log("killing the emperor with pid %d\n", uwsgi.emperor_pid);
}
uwsgi_detach_daemons();
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways[i].pid > 0)
kill(ushared->gateways[i].pid, SIGKILL);
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (uwsgi.mules[i].pid > 0)
kill(uwsgi.mules[i].pid, SIGKILL);
}
uwsgi_destroy_processes();
uwsgi_log("...gracefully killing workers...\n");
@@ -1058,12 +972,11 @@ void grace_them_all(int signum) {
if (uwsgi.auto_snapshot > 0 && i > uwsgi.auto_snapshot) {
uwsgi.workers[i].snapshot = 0;
uwsgi.workers[i].destroy = 1;
kill(uwsgi.workers[i].pid, SIGHUP);
uwsgi_curse(i, SIGHUP);
}
else {
uwsgi.workers[i].snapshot = uwsgi.workers[i].pid;
kill(uwsgi.workers[i].pid, SIGURG);
uwsgi.lazy_respawned++;
}
}
}
@@ -1075,9 +988,9 @@ void grace_them_all(int signum) {
}
if (uwsgi.auto_snapshot) {
uwsgi.respawn_workers = uwsgi.numproc - uwsgi.auto_snapshot;
if (!uwsgi.respawn_workers)
uwsgi.respawn_workers = 1;
uwsgi.respawn_snapshots = uwsgi.numproc - uwsgi.auto_snapshot;
if (!uwsgi.respawn_snapshots)
uwsgi.respawn_snapshots = 1;
}
}
@@ -1096,61 +1009,28 @@ void uwsgi_nuclear_blast() {
exit(1);
}
// brutally reload
void reap_them_all(int signum) {
int i;
// avoid reace condition in lazy mode
if (uwsgi.to_outworld == 1 || uwsgi.lazy_respawned > 0)
if (uwsgi_instance_is_reloading)
return;
uwsgi.status.brutally_reloading = 1;
if (!uwsgi.workers) return;
// count the number of active workers
int active_workers = 0;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].cheaped == 0 && uwsgi.workers[i].pid > 0) {
active_workers++;
}
}
uwsgi.marked_workers = active_workers;
if (!uwsgi.lazy)
uwsgi.to_heaven = 1;
else
uwsgi.to_outworld = 1;
uwsgi_detach_daemons();
for (i = 0; i < ushared->gateways_cnt; i++) {
if (ushared->gateways[i].pid > 0)
kill(ushared->gateways[i].pid, SIGKILL);
}
for (i = 0; i < uwsgi.mules_cnt; i++) {
if (!uwsgi.mules)
break;
if (uwsgi.mules[i].pid > 0)
kill(uwsgi.mules[i].pid, SIGKILL);
}
if (uwsgi.emperor_pid >= 0) {
kill(uwsgi.emperor_pid, SIGKILL);
waitpid(uwsgi.emperor_pid, &i, 0);
uwsgi_log("killing the emperor with pid %d\n", uwsgi.emperor_pid);
}
if (!uwsgi.workers)
return;
uwsgi_destroy_processes();
uwsgi_log("...brutally killing workers...\n");
// unsubscribe if needed
uwsgi_unsubscribe_all();
int i;
for (i = 1; i <= uwsgi.numproc; i++) {
if (uwsgi.workers[i].pid > 0)
kill(uwsgi.workers[i].pid, SIGTERM);
uwsgi_curse(i, SIGTERM);
}
}
@@ -2403,7 +2283,8 @@ int uwsgi_start(void *v_argv) {
if (uwsgi.command_mode) {
uwsgi.sockets = NULL;
uwsgi.numproc = 1;
uwsgi.to_hell = 1;
// hack to destroy the instance after command exit
uwsgi.status.brutally_destroying = 1;
}
#ifndef UWSGI_DEBUG
@@ -2682,7 +2563,7 @@ next2:
uwsgi.current_time = uwsgi_now();
// here we spawn the workers...
if (!uwsgi.cheap) {
if (!uwsgi.status.is_cheap) {
if (uwsgi.cheaper && uwsgi.cheaper_count) {
int nproc = uwsgi.cheaper_initial;
if (!nproc)
+1 -1
View File
@@ -291,7 +291,7 @@ void carbon_master_cycle() {
if (!u_carbon.servers) return;
if (uwsgi.current_time - u_carbon.last_update >= u_carbon.freq || uwsgi.cleaning) {
if (uwsgi.current_time - u_carbon.last_update >= u_carbon.freq || uwsgi.status.is_cleaning) {
// update
u_carbon.need_retry = 0;
carbon_push_stats(0);
+51 -18
View File
@@ -1421,6 +1421,21 @@ struct uwsgi_cache {
struct uwsgi_offload_engine;
// these are the possible states of an instance
struct uwsgi_instance_status {
int gracefully_reloading;
int brutally_reloading;
int gracefully_destroying;
int brutally_destroying;
int chain_reloading;
int workers_reloading;
int is_cheap;
int is_cleaning;
};
#define uwsgi_instance_is_dying (uwsgi.status.gracefully_destroying || uwsgi.status.brutally_destroying)
#define uwsgi_instance_is_reloading (uwsgi.status.gracefully_reloading || uwsgi.status.brutally_reloading)
struct uwsgi_server {
@@ -1450,6 +1465,8 @@ struct uwsgi_server {
// quiet startup
int no_initial_output;
struct uwsgi_instance_status status;
struct uwsgi_string_list *get_list;
// enable threads
@@ -1474,13 +1491,13 @@ struct uwsgi_server {
struct uwsgi_string_list *whitelist;
int snapshot;
int respawn_snapshots;
// enable auto-snapshotting
int auto_snapshot;
pid_t restore_snapshot;
int respawn_workers;
unsigned int reloads;
// leave master running as root
@@ -1504,8 +1521,6 @@ struct uwsgi_server {
int lazy;
// enable lazy-apps mode
int lazy_apps;
// enable cheap mode
int cheap;
// enable cheaper mode
int cheaper;
char *requested_cheaper_algo;
@@ -1560,9 +1575,6 @@ struct uwsgi_server {
struct uwsgi_string_list *additional_headers;
struct uwsgi_string_list *remove_headers;
// maximum time to wait after a reload
time_t master_mercy;
// set cpu affinity
int cpu_affinity;
@@ -1841,6 +1853,8 @@ struct uwsgi_server {
struct uwsgi_string_list *touch_reload;
struct uwsgi_string_list *touch_chain_reload;
struct uwsgi_string_list *touch_workers_reload;
struct uwsgi_string_list *touch_gracefully_stop;
struct uwsgi_string_list *touch_logrotate;
struct uwsgi_string_list *touch_logreopen;
@@ -1873,18 +1887,9 @@ struct uwsgi_server {
char *snmp_addr;
char *snmp_community;
struct uwsgi_lock_item *snmp_lock;
int snmp_fd;
int to_heaven;
int to_hell;
int to_outworld;
int cleaning;
int marked_workers;
int ready_to_die;
int ready_to_reload;
int lazy_respawned;
int udp_fd;
uint16_t buffer_size;
int signal_bufsize;
@@ -2363,7 +2368,8 @@ struct uwsgi_rpc {
int sig;
uint8_t signum;
time_t stopped_at;
time_t cursed_at;
time_t no_mercy_at;
// signals managed by this worker
uint64_t signals;
@@ -2461,10 +2467,15 @@ void uwsgi_redirect_to_slash(struct wsgi_request *);
void manage_snmp(int, uint8_t *, int, struct sockaddr_in *);
void snmp_init(void);
void uwsgi_master_manage_snmp(int);
int spool_request(struct uwsgi_spooler *uspool, char *, int, int, char *, int, char *, time_t, char *, size_t);
void spooler(struct uwsgi_spooler *);
pid_t spooler_start(struct uwsgi_spooler *);
void uwsgi_curse(int, int);
void uwsgi_destroy_processes(void);
void set_harakiri(int);
void set_user_harakiri(int);
void set_mule_harakiri(int);
@@ -3773,6 +3784,28 @@ int uwsgi_upload_progress_update(struct wsgi_request *, int, size_t);
void uwsgi_upload_progress_destroy(char *, int);
void uwsgi_time_bomb(int, int);
void uwsgi_master_manage_emperor(void);
void uwsgi_master_manage_udp(int);
void uwsgi_threaded_logger_spawn(void);
void uwsgi_master_check_idle(void);
void uwsgi_master_check_workers_deadline(void);
void uwsgi_master_check_gateways_deadline(void);
void uwsgi_master_check_mules_deadline(void);
void uwsgi_master_check_spoolers_deadline(void);
int uwsgi_master_check_spoolers_death(int);
int uwsgi_master_check_emperor_death(int);
int uwsgi_master_check_mules_death(int);
int uwsgi_master_check_gateways_death(int);
int uwsgi_master_check_daemons_death(int);
void uwsgi_master_check_death(void);
int uwsgi_master_check_reload(char **);
void uwsgi_master_commit_status(void);
void uwsgi_master_fix_request_counters(void);
int uwsgi_master_manage_events(int);
#define uwsgi_response_add_connection_close(x) uwsgi_response_add_header(x, "Connection", 10, "close", 5)
#define uwsgi_response_add_content_type(x, y, z) uwsgi_response_add_header(x, "Content-Type", 12, y, z)
+2 -2
View File
@@ -446,10 +446,10 @@ class uConf(object):
self.config.read(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/notify', 'core/mule', 'core/subscription', 'core/stats', 'core/sendfile', 'core/async', 'core/master_checks',
'core/offload', 'core/io', 'core/static', 'core/websockets', 'core/spooler', 'core/snmp',
'core/setup_utils', 'core/clock', 'core/init', 'core/buffer', 'core/reader', 'core/writer',
'core/plugins', 'core/lock', 'core/cache', 'core/daemons', 'core/errors', 'core/hash',
'core/plugins', 'core/lock', 'core/cache', 'core/daemons', 'core/errors', 'core/hash', 'core/master_events',
'core/queue', 'core/event', 'core/signal', 'core/strings', 'core/progress', 'core/timebomb',
'core/rpc', 'core/gateway', 'core/loop', 'core/rb_timers', 'core/uwsgi']
# add protocols