int uwsgi_signal_add_rb_timer(uint8_t sig, int secs, int iterations) { if (!uwsgi.master_process) return -1; uwsgi_lock(uwsgi.rb_timer_table_lock); if (ushared->rb_timers_cnt < 64) { // fill the timer table, the master will use it to add items to the event queue ushared->rb_timers[ushared->rb_timers_cnt].value = secs; ushared->rb_timers[ushared->rb_timers_cnt].registered = 0; ushared->rb_timers[ushared->rb_timers_cnt].iterations = iterations; ushared->rb_timers[ushared->rb_timers_cnt].iterations_done = 0; ushared->rb_timers[ushared->rb_timers_cnt].sig = sig; ushared->rb_timers_cnt++; } else { uwsgi_log("you can register max 64 rb_timers !!!\n"); uwsgi_unlock(uwsgi.rb_timer_table_lock); return -1; } uwsgi_unlock(uwsgi.rb_timer_table_lock); return 0; }
int uwsgi_add_file_monitor(uint8_t sig, char *filename) { if (strlen(filename) > (0xff - 1)) { uwsgi_log("uwsgi_add_file_monitor: invalid filename length\n"); return -1; } uwsgi_lock(uwsgi.fmon_table_lock); if (ushared->files_monitored_cnt < 64) { // fill the fmon table, the master will use it to add items to the event queue memcpy(ushared->files_monitored[ushared->files_monitored_cnt].filename, filename, strlen(filename)); ushared->files_monitored[ushared->files_monitored_cnt].registered = 0; ushared->files_monitored[ushared->files_monitored_cnt].sig = sig; ushared->files_monitored_cnt++; } else { uwsgi_log("you can register max 64 file monitors !!!\n"); uwsgi_unlock(uwsgi.fmon_table_lock); return -1; } uwsgi_unlock(uwsgi.fmon_table_lock); return 0; }
int uwsgi_signal_add_cron(uint8_t sig, int minute, int hour, int day, int month, int week) { if (!uwsgi.master_process) return -1; uwsgi_lock(uwsgi.cron_table_lock); if (ushared->cron_cnt < MAX_CRONS) { ushared->cron[ushared->cron_cnt].sig = sig; ushared->cron[ushared->cron_cnt].minute = minute; ushared->cron[ushared->cron_cnt].hour = hour; ushared->cron[ushared->cron_cnt].day = day; ushared->cron[ushared->cron_cnt].month = month; ushared->cron[ushared->cron_cnt].week = week; ushared->cron_cnt++; } else { uwsgi_log("you can register max %d cron !!!\n", MAX_CRONS); uwsgi_unlock(uwsgi.cron_table_lock); return -1; } uwsgi_unlock(uwsgi.cron_table_lock); return 0; }
void uwsgi_manage_signal_cron(time_t now) { struct tm *uwsgi_cron_delta; int i; uwsgi_cron_delta = localtime(&now); if (uwsgi_cron_delta) { // fix month uwsgi_cron_delta->tm_mon++; uwsgi_lock(uwsgi.cron_table_lock); for (i = 0; i < ushared->cron_cnt; i++) { struct uwsgi_cron *ucron = &ushared->cron[i]; int run_task = uwsgi_cron_task_needs_execution(uwsgi_cron_delta, ucron->minute, ucron->hour, ucron->day, ucron->month, ucron->week); if (run_task == 1) { // date match, signal it ? if (now - ucron->last_job >= 60) { uwsgi_route_signal(ucron->sig); ucron->last_job = now; } } } uwsgi_unlock(uwsgi.cron_table_lock); } else { uwsgi_error("localtime()"); } }
JNIEXPORT void JNICALL uwsgi_jvm_api_lock(JNIEnv *env, jclass c, jint locknum) { if (locknum < 0 || locknum > uwsgi.locks) { uwsgi_jvm_throw("invalid lock number"); return; } uwsgi_lock(uwsgi.user_lock[locknum]); }
int uwsgi_user_lock(int lock_num) { if (lock_num < 0 || lock_num > uwsgi.locks) { return -1; } uwsgi_lock(uwsgi.user_lock[lock_num]); return 0; }
int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t modifier1) { struct uwsgi_signal_entry *use = NULL; if (strlen(receiver) > 63) return -1; uwsgi_lock(uwsgi.signal_table_lock); use = &uwsgi.shared->signal_table[sig]; if (use->handler) { uwsgi_log("[uwsgi-signal] you cannot re-register a signal !!!\n"); uwsgi_unlock(uwsgi.signal_table_lock); return -1; } strncpy(use->receiver, receiver, strlen(receiver) + 1); use->handler = handler; use->modifier1 = modifier1; use->wid = uwsgi.mywid; if (use->receiver[0] == 0) { uwsgi_log("[uwsgi-signal] signum %d registered (wid: %d modifier1: %d target: default, any worker)\n", sig, uwsgi.mywid, modifier1); } else { uwsgi_log("[uwsgi-signal] signum %d registered (wid: %d modifier1: %d target: %s)\n", sig, uwsgi.mywid, modifier1, receiver); } uwsgi_unlock(uwsgi.signal_table_lock); return 0; }
/* Unbit-specific workaround for robust-mutexes */ void *uwsgi_robust_mutexes_watchdog_loop(void *arg) { for(;;) { uwsgi_lock(uwsgi.the_thunder_lock); uwsgi_unlock(uwsgi.the_thunder_lock); sleep(1); } return NULL; }
int uwsgi_add_probe(uint8_t sig, char *kind, char *args, int timeout, int freq) { uwsgi_lock(uwsgi.probe_table_lock); if (ushared->probes_cnt < MAX_PROBES) { struct uwsgi_probe *up = uwsgi.probes; while (up) { if (!strcmp(up->name, kind)) { break; } up = up->next; } if (!up) { uwsgi_log("unable to find probe \"%s\" !!!\n", kind); uwsgi_unlock(uwsgi.probe_table_lock); return -1; } // fill the probe table ushared->probes[ushared->probes_cnt].func = up->func; strncpy(ushared->probes[ushared->probes_cnt].args, args, 1024 - 1); ushared->probes[ushared->probes_cnt].registered = 0; ushared->probes[ushared->probes_cnt].sig = sig; ushared->probes[ushared->probes_cnt].fd = -1; ushared->probes[ushared->probes_cnt].state = 0; ushared->probes[ushared->probes_cnt].last_event = 0; ushared->probes[ushared->probes_cnt].data = NULL; ushared->probes[ushared->probes_cnt].cycles = 0; ushared->probes[ushared->probes_cnt].bad = 0; if (!timeout) { timeout = uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]; } ushared->probes[ushared->probes_cnt].timeout = timeout; if (!freq) { freq = 1; } ushared->probes[ushared->probes_cnt].freq = freq; ushared->probes_cnt++; } else { uwsgi_log("you can register max %d probes !!!\n", MAX_PROBES); uwsgi_unlock(uwsgi.probe_table_lock); return -1; } uwsgi_unlock(uwsgi.probe_table_lock); return 0; }
int uwsgi_register_signal(uint8_t sig, char *receiver, void *handler, uint8_t modifier1) { struct uwsgi_signal_entry *use = NULL; if (!uwsgi.master_process) return -1; if (uwsgi.mywid == 0 && uwsgi.workers[0].pid != uwsgi.mypid) { uwsgi_log("only the master and the workers can register signal handlers\n"); return -1; } if (strlen(receiver) > 63) return -1; uwsgi_lock(uwsgi.signal_table_lock); int pos = (uwsgi.mywid * 256) + sig; use = &uwsgi.shared->signal_table[pos]; if (use->handler && uwsgi.mywid == 0) { uwsgi_log("[uwsgi-signal] you cannot re-register a signal as the master !!!\n"); uwsgi_unlock(uwsgi.signal_table_lock); return -1; } strncpy(use->receiver, receiver, strlen(receiver) + 1); use->handler = handler; use->modifier1 = modifier1; use->wid = uwsgi.mywid; if (use->receiver[0] == 0) { uwsgi_log("[uwsgi-signal] signum %d registered (wid: %d modifier1: %d target: default, any worker)\n", sig, uwsgi.mywid, modifier1); } else { uwsgi_log("[uwsgi-signal] signum %d registered (wid: %d modifier1: %d target: %s)\n", sig, uwsgi.mywid, modifier1, receiver); } // check for cow if (uwsgi.mywid == 0) { int i; for(i=1; i<=uwsgi.numproc; i++) { int pos = (i * 256); memcpy(&uwsgi.shared->signal_table[pos], &uwsgi.shared->signal_table[0], sizeof(struct uwsgi_signal_entry) * 256); } } uwsgi_unlock(uwsgi.signal_table_lock); return 0; }
static int uwsgi_api_lock(lua_State *L) { int lock_num = 0; // the spooler cannot lock resources if (uwsgi.i_am_a_spooler) { lua_pushstring(L, "The spooler cannot lock/unlock resources"); lua_error(L); } if (lua_gettop(L) > 0) { lock_num = lua_isnumber(L, 1) ? lua_tonumber(L, 1) : -1; if (lock_num < 0 || lock_num > uwsgi.locks) { lua_pushstring(L, "Invalid lock number"); lua_error(L); } } uwsgi_lock(uwsgi.user_lock[lock_num]); return 0; }
int uwsgi_add_timer(uint8_t sig, int secs) { uwsgi_lock(uwsgi.timer_table_lock); if (ushared->timers_cnt < 64) { // fill the timer table, the master will use it to add items to the event queue ushared->timers[ushared->timers_cnt].value = secs; ushared->timers[ushared->timers_cnt].registered = 0; ushared->timers[ushared->timers_cnt].sig = sig; ushared->timers_cnt++; } else { uwsgi_log("you can register max 64 timers !!!\n"); uwsgi_unlock(uwsgi.timer_table_lock); return -1; } uwsgi_unlock(uwsgi.timer_table_lock); return 0; }
int spool_request(struct uwsgi_spooler *uspool, char *filename, int rn, int core_id, char *buffer, int size, char *priority, time_t at, char *body, size_t body_len) { struct timeval tv; int fd; struct uwsgi_header uh; if (!uspool) { uspool = uwsgi.spoolers; } // this lock is for threads, the pid value in filename will avoid multiprocess races uwsgi_lock(uspool->lock); gettimeofday(&tv, NULL); if (priority) { if (snprintf(filename, 1024, "%s/%s", uspool->dir, priority) <= 0) { uwsgi_unlock(uspool->lock); return 0; } // no need to check for errors... (void) mkdir(filename, 0777); if (snprintf(filename, 1024, "%s/%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, priority, uwsgi.hostname, (int) getpid(), rn, core_id, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) { uwsgi_unlock(uspool->lock); return 0; } } else { if (snprintf(filename, 1024, "%s/uwsgi_spoolfile_on_%s_%d_%d_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), rn, core_id, (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec) <= 0) { uwsgi_unlock(uspool->lock); return 0; } } fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); if (fd < 0) { uwsgi_error_open(filename); uwsgi_unlock(uspool->lock); return 0; } // now lock the file, it will no be runnable, until the lock is not removed // a race could come if the spooler take the file before fcntl is called // in such case the spooler will detect a zeroed file and will retry later if (uwsgi_fcntl_lock(fd)) { close(fd); uwsgi_unlock(uspool->lock); return 0; } uh.modifier1 = 17; uh.modifier2 = 0; uh.pktsize = (uint16_t) size; #ifdef __BIG_ENDIAN__ uh.pktsize = uwsgi_swap16(uh.pktsize); #endif if (write(fd, &uh, 4) != 4) { goto clear; } if (write(fd, buffer, size) != size) { goto clear; } if (body && body_len > 0) { if ((size_t)write(fd, body, body_len) != body_len) { goto clear; } } if (at > 0) { struct timeval tv[2]; tv[0].tv_sec = at; tv[0].tv_usec = 0; tv[1].tv_sec = at; tv[1].tv_usec = 0; #ifdef __sun__ if (futimesat(fd, NULL, tv)) { #else if (futimes(fd, tv)) { #endif uwsgi_error("futimes()"); } } // here the file will be unlocked too close(fd); if (!uwsgi.spooler_quiet) uwsgi_log("[spooler] written %d bytes to file %s\n", size + body_len + 4, filename); // and here waiting threads can continue uwsgi_unlock(uspool->lock); /* wake up the spoolers attached to the specified dir ... (HACKY) no need to fear races, as USR1 is harmless an all of the uWSGI processes... it could be a problem if a new process takes the old pid, but modern systems should avoid that */ struct uwsgi_spooler *spoolers = uwsgi.spoolers; while(spoolers) { if (!strcmp(spoolers->dir, uspool->dir)) { if (spoolers->pid > 0 && spoolers->running == 0) { (void) kill(spoolers->pid, SIGUSR1); } } spoolers = spoolers->next; } return 1; clear: uwsgi_unlock(uspool->lock); uwsgi_error("write()"); if (unlink(filename)) { uwsgi_error("unlink()"); } // unlock the file too close(fd); return 0; } void spooler(struct uwsgi_spooler *uspool) { // prevent process blindly reading stdin to make mess int nullfd; // asked by Marco Beri #ifdef __HAIKU__ #ifdef UWSGI_DEBUG uwsgi_log("lowering spooler priority to %d\n", B_LOW_PRIORITY); #endif set_thread_priority(find_thread(NULL), B_LOW_PRIORITY); #else #ifdef UWSGI_DEBUG uwsgi_log("lowering spooler priority to %d\n", PRIO_MAX); #endif setpriority(PRIO_PROCESS, getpid(), PRIO_MAX); #endif nullfd = open("/dev/null", O_RDONLY); if (nullfd < 0) { uwsgi_error_open("/dev/null"); exit(1); } if (nullfd != 0) { dup2(nullfd, 0); close(nullfd); } int spooler_event_queue = event_queue_init(); int interesting_fd = -1; if (uwsgi.master_process) { event_queue_add_fd_read(spooler_event_queue, uwsgi.shared->spooler_signal_pipe[1]); } // reset the tasks counter uspool->tasks = 0; for (;;) { if (chdir(uspool->dir)) { uwsgi_error("chdir()"); exit(1); } if (uwsgi.spooler_ordered) { #ifdef __linux__ spooler_scandir(uspool, NULL); #else spooler_readdir(uspool, NULL); #endif } else { spooler_readdir(uspool, NULL); } int timeout = uwsgi.shared->spooler_frequency; if (wakeup > 0) { timeout = 0; } if (event_queue_wait(spooler_event_queue, timeout, &interesting_fd) > 0) { if (uwsgi.master_process) { if (interesting_fd == uwsgi.shared->spooler_signal_pipe[1]) { uwsgi_receive_signal(interesting_fd, "spooler", (int) getpid()); } } } // avoid races uint64_t tmp_wakeup = wakeup; if (tmp_wakeup > 0) { tmp_wakeup--; } wakeup = tmp_wakeup; // need to recycle ? if (uwsgi.spooler_max_tasks > 0 && uspool->tasks >= (uint64_t)uwsgi.spooler_max_tasks) { uwsgi_log("[spooler %s pid: %d] maximum number of tasks reached (%d) recycling ...\n", uspool->dir, (int) uwsgi.mypid, uwsgi.spooler_max_tasks); end_me(0); } } }
JNIEXPORT void JNICALL uwsgi_jvm_api_lock_zero(JNIEnv *env, jclass c) { uwsgi_lock(uwsgi.user_lock[0]); }
void uwsgi_user_lock(int lock_num) { uwsgi_lock(uwsgi.user_lock[lock_num]); }
/* CHANGED in 2.0.7: wsgi_req is useless ! */ char *uwsgi_spool_request(struct wsgi_request *wsgi_req, char *buf, size_t len, char *body, size_t body_len) { struct timeval tv; static uint64_t internal_counter = 0; int fd = -1; struct spooler_req sr; if (len > 0xffff) { uwsgi_log("[uwsgi-spooler] args buffer is limited to 64k, use the 'body' for bigger values\n"); return NULL; } // parse the request buffer memset(&sr, 0, sizeof(struct spooler_req)); uwsgi_hooked_parse(buf, len, spooler_req_parser_hook, &sr); struct uwsgi_spooler *uspool = uwsgi.spoolers; if (!uspool) { uwsgi_log("[uwsgi-spooler] no spooler available\n"); return NULL; } // if it is a number, get the spooler by id instead of by name if (sr.spooler && sr.spooler_len) { uspool = uwsgi_get_spooler_by_name(sr.spooler, sr.spooler_len); if (!uspool) { uwsgi_log("[uwsgi-spooler] unable to find spooler \"%.*s\"\n", sr.spooler_len, sr.spooler); return NULL; } } // this lock is for threads, the pid value in filename will avoid multiprocess races uwsgi_lock(uspool->lock); // we increase it even if the request fails internal_counter++; gettimeofday(&tv, NULL); char *filename = NULL; size_t filename_len = 0; if (sr.priority && sr.priority_len) { filename_len = strlen(uspool->dir) + sr.priority_len + strlen(uwsgi.hostname) + 256; filename = uwsgi_malloc(filename_len); int ret = snprintf(filename, filename_len, "%s/%.*s", uspool->dir, (int) sr.priority_len, sr.priority); if (ret <= 0 || ret >= (int) filename_len) { uwsgi_log("[uwsgi-spooler] error generating spooler filename\n"); free(filename); uwsgi_unlock(uspool->lock); return NULL; } // no need to check for errors... (void) mkdir(filename, 0777); ret = snprintf(filename, filename_len, "%s/%.*s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, (int)sr.priority_len, sr.priority, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, rand(), (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec); if (ret <= 0 || ret >=(int) filename_len) { uwsgi_log("[uwsgi-spooler] error generating spooler filename\n"); free(filename); uwsgi_unlock(uspool->lock); return NULL; } } else { filename_len = strlen(uspool->dir) + strlen(uwsgi.hostname) + 256; filename = uwsgi_malloc(filename_len); int ret = snprintf(filename, filename_len, "%s/uwsgi_spoolfile_on_%s_%d_%llu_%d_%llu_%llu", uspool->dir, uwsgi.hostname, (int) getpid(), (unsigned long long) internal_counter, rand(), (unsigned long long) tv.tv_sec, (unsigned long long) tv.tv_usec); if (ret <= 0 || ret >= (int) filename_len) { uwsgi_log("[uwsgi-spooler] error generating spooler filename\n"); free(filename); uwsgi_unlock(uspool->lock); return NULL; } } fd = open(filename, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); if (fd < 0) { uwsgi_error_open(filename); free(filename); uwsgi_unlock(uspool->lock); return NULL; } // now lock the file, it will no be runnable, until the lock is not removed // a race could come if the spooler take the file before fcntl is called // in such case the spooler will detect a zeroed file and will retry later if (uwsgi_fcntl_lock(fd)) { close(fd); free(filename); uwsgi_unlock(uspool->lock); return NULL; } struct uwsgi_header uh; uh.modifier1 = 17; uh.modifier2 = 0; uh.pktsize = (uint16_t) len; #ifdef __BIG_ENDIAN__ uh.pktsize = uwsgi_swap16(uh.pktsize); #endif if (write(fd, &uh, 4) != 4) { uwsgi_log("[spooler] unable to write header for %s\n", filename); goto clear; } if (write(fd, buf, len) != (ssize_t) len) { uwsgi_log("[spooler] unable to write args for %s\n", filename); goto clear; } if (body && body_len > 0) { if ((size_t) write(fd, body, body_len) != body_len) { uwsgi_log("[spooler] unable to write body for %s\n", filename); goto clear; } } if (sr.at > 0) { #ifdef __UCLIBC__ struct timespec ts[2]; ts[0].tv_sec = sr.at; ts[0].tv_nsec = 0; ts[1].tv_sec = sr.at; ts[1].tv_nsec = 0; if (futimens(fd, ts)) { uwsgi_error("uwsgi_spooler_request()/futimens()"); } #else struct timeval tv[2]; tv[0].tv_sec = sr.at; tv[0].tv_usec = 0; tv[1].tv_sec = sr.at; tv[1].tv_usec = 0; #ifdef __sun__ if (futimesat(fd, NULL, tv)) { #else if (futimes(fd, tv)) { #endif uwsgi_error("uwsgi_spooler_request()/futimes()"); } #endif } // here the file will be unlocked too close(fd); if (!uwsgi.spooler_quiet) uwsgi_log("[spooler] written %lu bytes to file %s\n", (unsigned long) len + body_len + 4, filename); // and here waiting threads can continue uwsgi_unlock(uspool->lock); /* wake up the spoolers attached to the specified dir ... (HACKY) no need to fear races, as USR1 is harmless an all of the uWSGI processes... it could be a problem if a new process takes the old pid, but modern systems should avoid that */ struct uwsgi_spooler *spoolers = uwsgi.spoolers; while (spoolers) { if (!strcmp(spoolers->dir, uspool->dir)) { if (spoolers->pid > 0 && spoolers->running == 0) { (void) kill(spoolers->pid, SIGUSR1); } } spoolers = spoolers->next; } return filename; clear: uwsgi_unlock(uspool->lock); uwsgi_error("uwsgi_spool_request()/write()"); if (unlink(filename)) { uwsgi_error("uwsgi_spool_request()/unlink()"); } free(filename); // unlock the file too close(fd); return NULL; } void spooler(struct uwsgi_spooler *uspool) { // prevent process blindly reading stdin to make mess int nullfd; // asked by Marco Beri #ifdef __HAIKU__ #ifdef UWSGI_DEBUG uwsgi_log("lowering spooler priority to %d\n", B_LOW_PRIORITY); #endif set_thread_priority(find_thread(NULL), B_LOW_PRIORITY); #else #ifdef UWSGI_DEBUG uwsgi_log("lowering spooler priority to %d\n", PRIO_MAX); #endif setpriority(PRIO_PROCESS, getpid(), PRIO_MAX); #endif nullfd = open("/dev/null", O_RDONLY); if (nullfd < 0) { uwsgi_error_open("/dev/null"); exit(1); } if (nullfd != 0) { dup2(nullfd, 0); close(nullfd); } int spooler_event_queue = event_queue_init(); int interesting_fd = -1; if (uwsgi.master_process) { event_queue_add_fd_read(spooler_event_queue, uwsgi.shared->spooler_signal_pipe[1]); } // reset the tasks counter uspool->tasks = 0; for (;;) { if (chdir(uspool->dir)) { uwsgi_error("chdir()"); exit(1); } if (uwsgi.spooler_ordered) { #ifdef __linux__ spooler_scandir(uspool, NULL); #else spooler_readdir(uspool, NULL); #endif } else { spooler_readdir(uspool, NULL); } int timeout = uwsgi.shared->spooler_frequency ? uwsgi.shared->spooler_frequency : uwsgi.spooler_frequency; if (wakeup > 0) { timeout = 0; } if (event_queue_wait(spooler_event_queue, timeout, &interesting_fd) > 0) { if (uwsgi.master_process) { if (interesting_fd == uwsgi.shared->spooler_signal_pipe[1]) { uwsgi_receive_signal(interesting_fd, "spooler", (int) getpid()); } } } // avoid races uint64_t tmp_wakeup = wakeup; if (tmp_wakeup > 0) { tmp_wakeup--; } wakeup = tmp_wakeup; } }
void uwsgi_manage_signal_cron(time_t now) { struct tm *uwsgi_cron_delta; int i; uwsgi_cron_delta = localtime(&now); if (uwsgi_cron_delta) { // fix month uwsgi_cron_delta->tm_mon++; uwsgi_lock(uwsgi.cron_table_lock); for (i = 0; i < ushared->cron_cnt; i++) { struct uwsgi_cron *ucron = &ushared->cron[i]; int uc_minute, uc_hour, uc_day, uc_month, uc_week; uc_minute = ucron->minute; uc_hour = ucron->hour; uc_day = ucron->day; uc_month = ucron->month; uc_week = ucron->week; // negative values as interval -1 = * , -5 = */5 if (ucron->minute < 0) { if ((uwsgi_cron_delta->tm_min % abs(ucron->minute)) == 0) { uc_minute = uwsgi_cron_delta->tm_min; } } if (ucron->hour < 0) { if ((uwsgi_cron_delta->tm_hour % abs(ucron->hour)) == 0) { uc_hour = uwsgi_cron_delta->tm_hour; } } if (ucron->month < 0) { if ((uwsgi_cron_delta->tm_mon % abs(ucron->month)) == 0) { uc_month = uwsgi_cron_delta->tm_mon; } } if (ucron->day < 0) { if ((uwsgi_cron_delta->tm_mday % abs(ucron->day)) == 0) { uc_day = uwsgi_cron_delta->tm_mday; } } if (ucron->week < 0) { if ((uwsgi_cron_delta->tm_wday % abs(ucron->week)) == 0) { uc_week = uwsgi_cron_delta->tm_wday; } } int run_task = 0; // mday and wday are ORed if (ucron->day >= 0 && ucron->week >= 0) { if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && (uwsgi_cron_delta->tm_mday == uc_day || uwsgi_cron_delta->tm_wday == uc_week)) { run_task = 1; } } else { if (uwsgi_cron_delta->tm_min == uc_minute && uwsgi_cron_delta->tm_hour == uc_hour && uwsgi_cron_delta->tm_mon == uc_month && uwsgi_cron_delta->tm_mday == uc_day && uwsgi_cron_delta->tm_wday == uc_week) { run_task = 1; } } if (run_task == 1) { // date match, signal it ? if (now - ucron->last_job > 60) { uwsgi_route_signal(ucron->sig); ucron->last_job = now; } } } uwsgi_unlock(uwsgi.cron_table_lock); } else { uwsgi_error("localtime()"); } }
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; pthread_t cache_sweeper; #ifdef UWSGI_UDP int udp_fd = -1; #ifdef UWSGI_MULTICAST char *cluster_opt_buf = NULL; size_t cluster_opt_size = 4; #endif #endif #ifdef UWSGI_SNMP int snmp_fd = -1; #endif int i = 0; int rlen; int check_interval = 1; struct uwsgi_rb_timer *min_timeout; struct rb_root *rb_timers = uwsgi_init_rb_timer(); if (uwsgi.procname_master) { uwsgi_set_processname(uwsgi.procname_master); } else if (uwsgi.procname) { uwsgi_set_processname(uwsgi.procname); } else if (uwsgi.auto_procname) { uwsgi_set_processname("uWSGI master"); } uwsgi.current_time = uwsgi_now(); uwsgi_unix_signal(SIGTSTP, suspend_resume_them_all); uwsgi_unix_signal(SIGHUP, grace_them_all); if (uwsgi.die_on_term) { uwsgi_unix_signal(SIGTERM, kill_them_all); uwsgi_unix_signal(SIGQUIT, reap_them_all); } else { uwsgi_unix_signal(SIGTERM, reap_them_all); uwsgi_unix_signal(SIGQUIT, kill_them_all); } uwsgi_unix_signal(SIGINT, kill_them_all); uwsgi_unix_signal(SIGUSR1, stats); if (uwsgi.auto_snapshot) { uwsgi_unix_signal(SIGURG, uwsgi_restore_auto_snapshot); } atexit(uwsgi_master_cleanup_hooks); uwsgi.master_queue = event_queue_init(); /* route signals to workers... */ #ifdef UWSGI_DEBUG uwsgi_log("adding %d to signal poll\n", uwsgi.shared->worker_signal_pipe[0]); #endif event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_signal_pipe[0]); #ifdef UWSGI_SPOOLER if (uwsgi.spoolers) { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->spooler_signal_pipe[0]); } #endif if (uwsgi.mules_cnt > 0) { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->mule_signal_pipe[0]); } if (uwsgi.log_master) { uwsgi.log_master_buf = uwsgi_malloc(uwsgi.log_master_bufsize); if (!uwsgi.threaded_logger) { #ifdef UWSGI_DEBUG uwsgi_log("adding %d to master logging\n", uwsgi.shared->worker_log_pipe[0]); #endif event_queue_add_fd_read(uwsgi.master_queue, uwsgi.shared->worker_log_pipe[0]); } 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]); uwsgi.threaded_logger = 0; } } #ifdef UWSGI_ALARM // initialize the alarm subsystem uwsgi_alarms_init(); #endif } if (uwsgi.cache_max_items > 0 && !uwsgi.cache_no_expire) { if (pthread_create(&cache_sweeper, NULL, cache_sweeper_loop, NULL)) { uwsgi_error("pthread_create()"); uwsgi_log("unable to run the cache sweeper !!!\n"); } else { uwsgi_log("cache sweeper thread enabled\n"); } } uwsgi.wsgi_req->buffer = uwsgi.workers[0].cores[0].buffer; if (uwsgi.has_emperor) { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.emperor_fd); } if (uwsgi.zerg_server) { uwsgi.zerg_server_fd = bind_to_unix(uwsgi.zerg_server, uwsgi.listen_queue, 0, 0); event_queue_add_fd_read(uwsgi.master_queue, uwsgi.zerg_server_fd); uwsgi_log("*** Zerg server enabled on %s ***\n", uwsgi.zerg_server); } if (uwsgi.stats) { char *tcp_port = strchr(uwsgi.stats, ':'); if (tcp_port) { // disable deferred accept for this socket int current_defer_accept = uwsgi.no_defer_accept; uwsgi.no_defer_accept = 1; uwsgi.stats_fd = bind_to_tcp(uwsgi.stats, uwsgi.listen_queue, tcp_port); uwsgi.no_defer_accept = current_defer_accept; } else { uwsgi.stats_fd = bind_to_unix(uwsgi.stats, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket); } event_queue_add_fd_read(uwsgi.master_queue, uwsgi.stats_fd); uwsgi_log("*** Stats server enabled on %s fd: %d ***\n", uwsgi.stats, uwsgi.stats_fd); } #ifdef UWSGI_UDP if (uwsgi.udp_socket) { udp_fd = bind_to_udp(uwsgi.udp_socket, 0, 0); if (udp_fd < 0) { uwsgi_log("unable to bind to udp socket. SNMP and cluster management services will be disabled.\n"); } else { uwsgi_log("UDP server enabled.\n"); event_queue_add_fd_read(uwsgi.master_queue, udp_fd); } } #ifdef UWSGI_MULTICAST if (uwsgi.cluster) { event_queue_add_fd_read(uwsgi.master_queue, uwsgi.cluster_fd); cluster_opt_buf = uwsgi_setup_clusterbuf(&cluster_opt_size); } #endif #endif #ifdef UWSGI_SNMP snmp_fd = uwsgi_setup_snmp(); #endif if (uwsgi.cheap) { uwsgi_add_sockets_to_queue(uwsgi.master_queue, -1); for (i = 1; i <= uwsgi.numproc; i++) { uwsgi.workers[i].cheaped = 1; } uwsgi_log("cheap mode enabled: waiting for socket connection...\n"); } // spawn mules for (i = 0; i < uwsgi.mules_cnt; i++) { size_t mule_patch_size = 0; uwsgi.mules[i].patch = uwsgi_string_get_list(&uwsgi.mules_patches, i, &mule_patch_size); uwsgi_mule(i + 1); } // spawn gateways for (i = 0; i < ushared->gateways_cnt; i++) { if (ushared->gateways[i].pid == 0) { gateway_respawn(i); } } // spawn daemons uwsgi_daemons_spawn_all(); // first subscription struct uwsgi_string_list *subscriptions = uwsgi.subscriptions; while (subscriptions) { uwsgi_subscribe(subscriptions->value, 0); subscriptions = subscriptions->next; } // sync the cache store if needed if (uwsgi.cache_store && uwsgi.cache_filesize) { if (msync(uwsgi.cache_items, uwsgi.cache_filesize, MS_ASYNC)) { uwsgi_error("msync()"); } } if (uwsgi.queue_store && uwsgi.queue_filesize) { if (msync(uwsgi.queue_header, uwsgi.queue_filesize, MS_ASYNC)) { uwsgi_error("msync()"); } } // update touches timestamps uwsgi_check_touches(uwsgi.touch_reload); uwsgi_check_touches(uwsgi.touch_logrotate); uwsgi_check_touches(uwsgi.touch_logreopen); // setup cheaper algos uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare; if (uwsgi.requested_cheaper_algo) { uwsgi.cheaper_algo = NULL; struct uwsgi_cheaper_algo *uca = uwsgi.cheaper_algos; while (uca) { if (!strcmp(uca->name, uwsgi.requested_cheaper_algo)) { uwsgi.cheaper_algo = uca->func; break; } uca = uca->next; } if (!uwsgi.cheaper_algo) { uwsgi_log("unable to find requested cheaper algorithm, falling back to spare\n"); uwsgi.cheaper_algo = uwsgi_cheaper_algo_spare; } } // here really starts the master loop for (;;) { //uwsgi_log("uwsgi.ready_to_reload %d %d\n", uwsgi.ready_to_reload, uwsgi.numproc); // run master_cycle hook for every plugin for (i = 0; i < uwsgi.gp_cnt; i++) { if (uwsgi.gp[i]->master_cycle) { uwsgi.gp[i]->master_cycle(); } } for (i = 0; i < 256; i++) { if (uwsgi.p[i]->master_cycle) { uwsgi.p[i]->master_cycle(); } } uwsgi_daemons_smart_check(); // 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++; } } if (uwsgi.to_outworld) { //uwsgi_log("%d/%d\n", uwsgi.lazy_respawned, uwsgi.numproc); if (uwsgi.lazy_respawned >= active_workers) { uwsgi.to_outworld = 0; uwsgi.master_mercy = 0; uwsgi.lazy_respawned = 0; } } if (uwsgi_master_check_mercy()) return 0; if (uwsgi.respawn_workers) { for (i = 1; i <= uwsgi.respawn_workers; i++) { if (uwsgi_respawn_worker(i)) return 0; } uwsgi.respawn_workers = 0; } if (uwsgi.restore_snapshot) { uwsgi_master_restore_snapshot(); continue; } // cheaper management if (uwsgi.cheaper && !uwsgi.cheap && !uwsgi.to_heaven && !uwsgi.to_hell && !uwsgi.to_outworld && !uwsgi.workers[0].suspended) { if (!uwsgi_calc_cheaper()) return 0; } if ((uwsgi.cheap || uwsgi.ready_to_die >= active_workers) && 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 >= active_workers) && uwsgi.to_heaven) { uwsgi_reload(argv); // never here (unless in shared library mode) return -1; } 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; } diedpid = 0; } else { uwsgi_error("waitpid()"); /* here is better to reload all the uWSGI stack */ uwsgi_log("something horrible happened...\n"); reap_them_all(0); exit(1); } } if (diedpid == 0) { /* all processes ok, doing status scan after N seconds */ check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL]; if (!check_interval) check_interval = 1; // add unregistered file monitors // locking is not needed as monitors can only increase for (i = 0; i < ushared->files_monitored_cnt; i++) { if (!ushared->files_monitored[i].registered) { ushared->files_monitored[i].fd = event_queue_add_file_monitor(uwsgi.master_queue, ushared->files_monitored[i].filename, &ushared->files_monitored[i].id); ushared->files_monitored[i].registered = 1; } } // add unregistered timers // locking is not needed as timers can only increase for (i = 0; i < ushared->timers_cnt; i++) { if (!ushared->timers[i].registered) { ushared->timers[i].fd = event_queue_add_timer(uwsgi.master_queue, &ushared->timers[i].id, ushared->timers[i].value); ushared->timers[i].registered = 1; } } // add unregistered rb_timers // locking is not needed as rb_timers can only increase for (i = 0; i < ushared->rb_timers_cnt; i++) { if (!ushared->rb_timers[i].registered) { ushared->rb_timers[i].uwsgi_rb_timer = uwsgi_add_rb_timer(rb_timers, uwsgi_now() + ushared->rb_timers[i].value, &ushared->rb_timers[i]); ushared->rb_timers[i].registered = 1; } } int interesting_fd = -1; if (ushared->rb_timers_cnt > 0) { min_timeout = uwsgi_min_rb_timer(rb_timers); if (min_timeout == NULL) { check_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL]; } else { check_interval = min_timeout->key - uwsgi_now(); if (check_interval <= 0) { expire_rb_timeouts(rb_timers); check_interval = 0; } } } // wait for event rlen = event_queue_wait(uwsgi.master_queue, check_interval, &interesting_fd); if (rlen == 0) { if (ushared->rb_timers_cnt > 0) { expire_rb_timeouts(rb_timers); } } // check uwsgi-cron table if (ushared->cron_cnt) { uwsgi_manage_signal_cron(uwsgi_now()); } if (uwsgi.crons) { uwsgi_manage_command_cron(uwsgi_now()); } // check for probes if (ushared->probes_cnt > 0) { uwsgi_lock(uwsgi.probe_table_lock); for (i = 0; i < ushared->probes_cnt; i++) { if (interesting_fd == -1) { // increment cycles ushared->probes[i].cycles++; } if (ushared->probes[i].func(interesting_fd, &ushared->probes[i])) { uwsgi_route_signal(ushared->probes[i].sig); } } uwsgi_unlock(uwsgi.probe_table_lock); } 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.stats && uwsgi.stats_fd > -1) { if (interesting_fd == uwsgi.stats_fd) { uwsgi_send_stats(uwsgi.stats_fd); 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; } #ifdef UWSGI_SNMP if (uwsgi.snmp_addr && interesting_fd == snmp_fd) { uwsgi_master_manage_snmp(snmp_fd); goto health_cycle; } #endif #ifdef UWSGI_UDP if (uwsgi.udp_socket && interesting_fd == udp_fd) { uwsgi_master_manage_udp(udp_fd); goto health_cycle; } #ifdef UWSGI_MULTICAST if (interesting_fd == uwsgi.cluster_fd) { if (uwsgi_get_dgram(uwsgi.cluster_fd, &uwsgi.workers[0].cores[0].req)) { goto health_cycle; } manage_cluster_message(cluster_opt_buf, cluster_opt_size); goto health_cycle; } #endif #endif 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; } #ifdef UWSGI_SPOOLER // 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; } } #endif // 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; } uwsgi.current_time = now; // checking logsize if (uwsgi.logfile) { uwsgi_check_logrotate(); } // this will be incremented at (more or less) regular intervals uwsgi.master_cycles++; // recalculate requests counter on race conditions risky configurations // a bit of inaccuracy is better than locking;) 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_interval = uwsgi.shared->options[UWSGI_OPTION_MASTER_INTERVAL]; if (!check_interval) check_interval = 1; #ifdef __linux__ // get listen_queue status struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (uwsgi_sock->family == AF_INET) { get_linux_tcp_info(uwsgi_sock->fd); } #ifdef SIOBKLGQ else if (uwsgi_sock->family == AF_UNIX) { get_linux_unbit_SIOBKLGQ(uwsgi_sock->fd); } #endif uwsgi_sock = uwsgi_sock->next; } #endif 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; } } // 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; } } } #ifdef UWSGI_SPOOLER 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; } #endif #ifdef __linux__ #ifdef MADV_MERGEABLE if (uwsgi.linux_ksm > 0 && (uwsgi.master_cycles % uwsgi.linux_ksm) == 0) { uwsgi_linux_ksm_map(); } #endif #endif #ifdef UWSGI_UDP // check for cluster nodes master_check_cluster_nodes(); // reannounce myself every 10 cycles if (uwsgi.cluster && uwsgi.cluster_fd >= 0 && !uwsgi.cluster_nodes && (uwsgi.master_cycles % 10) == 0) { uwsgi_cluster_add_me(); } // resubscribe every 10 cycles by default if ((uwsgi.subscriptions && ((uwsgi.master_cycles % uwsgi.subscribe_freq) == 0 || uwsgi.master_cycles == 1)) && !uwsgi.to_heaven && !uwsgi.to_hell && !uwsgi.workers[0].suspended) { struct uwsgi_string_list *subscriptions = uwsgi.subscriptions; while (subscriptions) { uwsgi_subscribe(subscriptions->value, 0); subscriptions = subscriptions->next; } } #endif if (uwsgi.cache_store && uwsgi.cache_filesize && uwsgi.cache_store_sync && ((uwsgi.master_cycles % uwsgi.cache_store_sync) == 0)) { if (msync(uwsgi.cache_items, uwsgi.cache_filesize, MS_ASYNC)) { uwsgi_error("msync()"); } } if (uwsgi.queue_store && uwsgi.queue_filesize && uwsgi.queue_store_sync && ((uwsgi.master_cycles % uwsgi.queue_store_sync) == 0)) { if (msync(uwsgi.queue_header, uwsgi.queue_filesize, MS_ASYNC)) { uwsgi_error("msync()"); } } // check touch_reload if (!uwsgi.to_heaven && !uwsgi.to_hell) { char *touched = uwsgi_check_touches(uwsgi.touch_reload); if (touched) { uwsgi_log("*** %s has been touched... grace them all !!! ***\n", touched); uwsgi_block_signal(SIGHUP); grace_them_all(0); uwsgi_unblock_signal(SIGHUP); } } continue; } // no one died if (diedpid <= 0) continue; // check for deadlocks first uwsgi_deadlock_check(diedpid); // reload gateways and daemons only on normal workflow (+outworld status) if (!uwsgi.to_heaven && !uwsgi.to_hell) { #ifdef UWSGI_SPOOLER /* 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; #endif 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; } /* What happens here ? case 1) the diedpid is not a worker, report it and continue case 2) the diedpid is a worker and we are not in a reload procedure -> reload it case 3) the diedpid is a worker and we are in graceful reload -> uwsgi.ready_to_reload++ and continue case 3) the diedpid is a worker and we are in brutal reload -> uwsgi.ready_to_die++ and continue */ uwsgi.mywid = find_worker_id(diedpid); if (uwsgi.mywid <= 0) { // check spooler, mules, gateways and daemons #ifdef UWSGI_SPOOLER struct uwsgi_spooler *uspool = uwsgi.spoolers; while (uspool) { if (uspool->pid > 0 && diedpid == uspool->pid) { uwsgi_log("spooler (pid: %d) annihilated\n", (int) diedpid); goto next; } uspool = uspool->next; } #endif for (i = 0; i < uwsgi.mules_cnt; i++) { if (uwsgi.mules[i].pid == diedpid) { uwsgi_log("mule %d (pid: %d) annihilated\n", i + 1, (int) diedpid); goto next; } } for (i = 0; i < ushared->gateways_cnt; i++) { if (ushared->gateways[i].pid == diedpid) { uwsgi_log("gateway %d (%s, pid: %d) annihilated\n", i + 1, ushared->gateways[i].fullname, (int) diedpid); goto next; } } if (uwsgi_daemon_check_pid_death(diedpid)) goto next; if (WIFEXITED(waitpid_status)) { uwsgi_log("subprocess %d exited with code %d\n", (int) diedpid, WEXITSTATUS(waitpid_status)); } else if (WIFSIGNALED(waitpid_status)) { uwsgi_log("subprocess %d exited by signal %d\n", (int) diedpid, WTERMSIG(waitpid_status)); } else if (WIFSTOPPED(waitpid_status)) { uwsgi_log("subprocess %d stopped\n", (int) diedpid); } next: continue; } // 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; } 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); } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_DE_HIJACKED_CODE) { uwsgi_log("...restoring worker %d (pid: %d)...\n", uwsgi.mywid, (int) diedpid); } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_EXCEPTION_CODE) { uwsgi_log("... monitored exception detected, respawning worker %d (pid: %d)...\n", uwsgi.mywid, (int) diedpid); } else if (WIFEXITED(waitpid_status) && WEXITSTATUS(waitpid_status) == UWSGI_QUIET_CODE) { // noop } else if (uwsgi.workers[uwsgi.mywid].manage_next_request) { if (WIFSIGNALED(waitpid_status)) { uwsgi_log("DAMN ! worker %d (pid: %d) died, killed by signal %d :( trying respawn ...\n", uwsgi.mywid, (int) diedpid, (int) WTERMSIG(waitpid_status)); } else { uwsgi_log("DAMN ! worker %d (pid: %d) died :( trying respawn ...\n", uwsgi.mywid, (int) diedpid); } } else { uwsgi_log("DAMN ! worker %d (pid: %d) MISTERIOUSLY died :( trying respawn ...\n", uwsgi.mywid, (int) diedpid); } 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; } gettimeofday(&last_respawn, NULL); if (last_respawn.tv_sec <= uwsgi.respawn_delta + check_interval) { last_respawn_rate++; if (last_respawn_rate > uwsgi.numproc) { if (uwsgi.forkbomb_delay > 0) { uwsgi_log("worker respawning too fast !!! i have to sleep a bit (%d seconds)...\n", uwsgi.forkbomb_delay); /* use --forkbomb-delay 0 to disable sleeping */ sleep(uwsgi.forkbomb_delay); } last_respawn_rate = 0; } } else { last_respawn_rate = 0; } gettimeofday(&last_respawn, NULL); uwsgi.respawn_delta = last_respawn.tv_sec; if (uwsgi_respawn_worker(uwsgi.mywid)) return 0; // end of the loop } // never here }