void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) { int i, ret; char spool_buf[0xffff]; struct uwsgi_header uh; char *body = NULL; size_t body_len = 0; int spool_fd; if (!dir) dir = uspool->dir; if (!strncmp("uwsgi_spoolfile_on_", task, 19) || (uwsgi.spooler_ordered && is_a_number(task))) { struct stat sf_lstat; if (lstat(task, &sf_lstat)) { return; } // a spool request for the future if (sf_lstat.st_mtime > uwsgi_now()) { return; } #ifdef __linux__ if (S_ISDIR(sf_lstat.st_mode) && uwsgi.spooler_ordered) { if (chdir(task)) { uwsgi_error("chdir()"); return; } char *prio_path = realpath(".", NULL); spooler_scandir(uspool, prio_path); free(prio_path); if (chdir(dir)) { uwsgi_error("chdir()"); } return; } #endif if (!S_ISREG(sf_lstat.st_mode)) { return; } if (!access(task, R_OK | W_OK)) { spool_fd = open(task, O_RDWR); if (spool_fd < 0) { if (errno != ENOENT) uwsgi_error_open(task); return; } // check if the file is locked by another process if (uwsgi_fcntl_is_locked(spool_fd)) { uwsgi_protected_close(spool_fd); return; } // unlink() can destroy the lock !!! if (access(task, R_OK | W_OK)) { uwsgi_protected_close(spool_fd); return; } ssize_t rlen = uwsgi_protected_read(spool_fd, &uh, 4); if (rlen != 4) { // it could be here for broken file or just opened one if (rlen < 0) uwsgi_error("read()"); uwsgi_protected_close(spool_fd); return; } #ifdef __BIG_ENDIAN__ uh.pktsize = uwsgi_swap16(uh.pktsize); #endif if (uwsgi_protected_read(spool_fd, spool_buf, uh.pktsize) != uh.pktsize) { uwsgi_error("read()"); destroy_spool(dir, task); uwsgi_protected_close(spool_fd); return; } // body available ? if (sf_lstat.st_size > (uh.pktsize+4)) { body_len = sf_lstat.st_size - (uh.pktsize+4); body = uwsgi_malloc(body_len); if ((size_t)uwsgi_protected_read(spool_fd, body, body_len) != body_len) { uwsgi_error("read()"); destroy_spool(dir, task); uwsgi_protected_close(spool_fd); free(body); return; } } // now the task is running and should not be waken up uspool->running = 1; if (!uwsgi.spooler_quiet) uwsgi_log("[spooler %s pid: %d] managing request %s ...\n", uspool->dir, (int) uwsgi.mypid, task); // chdir before running the task (if requested) if (uwsgi.spooler_chdir) { if (chdir(uwsgi.spooler_chdir)) { uwsgi_error("chdir()"); } } int callable_found = 0; for(i=0; i<256; i++) { if (uwsgi.p[i]->spooler) { time_t now = uwsgi_now(); if(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) { set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]); } ret = uwsgi.p[i]->spooler(task, spool_buf, uh.pktsize, body, body_len); if(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) { set_spooler_harakiri(0); } if (ret == 0) continue; callable_found = 1; // increase task counter uspool->tasks++; if (ret == -2) { if (!uwsgi.spooler_quiet) uwsgi_log("[spooler %s pid: %d] done with task %s after %d seconds\n", uspool->dir, (int) uwsgi.mypid, task, uwsgi_now()-now); destroy_spool(dir, task); } // re-spool it break; } } if (body) free(body); // here we free and unlock the task uwsgi_protected_close(spool_fd); uspool->running = 0; if (chdir(dir)) { uwsgi_error("chdir()"); uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n"); exit(1); } if (!callable_found) { uwsgi_log("unable to find the spooler function, have you loaded it into the spooler process ?\n"); } } } }
int uwsgi_signal_handler(uint8_t sig) { struct uwsgi_signal_entry *use = NULL; use = &uwsgi.shared->signal_table[sig]; if (!uwsgi.p[use->modifier1]->signal_handler) { return -1; } // check for COW if (uwsgi.master_process) { if (use->wid != 0 && use->wid != uwsgi.mywid) { uwsgi_log("[uwsgi-signal] you have registered this signal in worker %d memory area, only that process will be able to run it\n", use->wid); return -1; } } // in lazy mode (without a master), only the same worker will be able to run handlers else if (uwsgi.lazy) { if (use->wid != uwsgi.mywid) { uwsgi_log("[uwsgi-signal] you have registered this signal in worker %d memory area, only that process will be able to run it\n", use->wid); return -1; } } else { // when master is not active, worker1 is the COW-leader if (use->wid != 1 && use->wid != uwsgi.mywid) { uwsgi_log("[uwsgi-signal] you have registered this signal in worker %d memory area, only that process will be able to run it\n", use->wid); return -1; } } // set harakiri here (if required and if i am a worker) if (uwsgi.mywid > 0) { uwsgi.workers[uwsgi.mywid].sig = 1; uwsgi.workers[uwsgi.mywid].signum = sig; uwsgi.workers[uwsgi.mywid].signals++; if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) { set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]); } } else if (uwsgi.muleid > 0) { uwsgi.mules[uwsgi.muleid - 1].sig = 1; uwsgi.mules[uwsgi.muleid - 1].signum = sig; uwsgi.mules[uwsgi.muleid - 1].signals++; if (uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI] > 0) { set_mule_harakiri(uwsgi.shared->options[UWSGI_OPTION_MULE_HARAKIRI]); } } #ifdef UWSGI_SPOOLER else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) { if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) { set_spooler_harakiri(uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI]); } } #endif int ret = uwsgi.p[use->modifier1]->signal_handler(sig, use->handler); if (uwsgi.mywid > 0) { uwsgi.workers[uwsgi.mywid].sig = 0; if (uwsgi.workers[uwsgi.mywid].harakiri > 0) { set_harakiri(0); } } else if (uwsgi.muleid > 0) { uwsgi.mules[uwsgi.muleid - 1].sig = 0; if (uwsgi.mules[uwsgi.muleid - 1].harakiri > 0) { set_mule_harakiri(0); } } #ifdef UWSGI_SPOOLER else if (uwsgi.i_am_a_spooler && (getpid() == uwsgi.i_am_a_spooler->pid)) { if (uwsgi.shared->options[UWSGI_OPTION_SPOOLER_HARAKIRI] > 0) { set_spooler_harakiri(0); } } #endif return ret; }
void spooler_manage_task(struct uwsgi_spooler *uspool, char *dir, char *task) { int i, ret; char spool_buf[0xffff]; struct uwsgi_header uh; char *body = NULL; size_t body_len = 0; int spool_fd; if (!dir) dir = uspool->dir; if (!strncmp("uwsgi_spoolfile_on_", task, 19) || (uwsgi.spooler_ordered && is_a_number(task))) { struct stat sf_lstat; if (lstat(task, &sf_lstat)) { return; } // a spool request for the future if (sf_lstat.st_mtime > uwsgi_now()) { return; } if (S_ISDIR(sf_lstat.st_mode) && uwsgi.spooler_ordered) { if (chdir(task)) { uwsgi_error("spooler_manage_task()/chdir()"); return; } #ifdef __UCLIBC__ char *prio_path = uwsgi_malloc(PATH_MAX); realpath(".", prio_path); #else char *prio_path = realpath(".", NULL); #endif spooler_scandir(uspool, prio_path); free(prio_path); if (chdir(dir)) { uwsgi_error("spooler_manage_task()/chdir()"); } return; } if (!S_ISREG(sf_lstat.st_mode)) { return; } if (!access(task, R_OK | W_OK)) { spool_fd = open(task, O_RDWR); if (spool_fd < 0) { if (errno != ENOENT) uwsgi_error_open(task); return; } if (uwsgi_spooler_read_header(task, spool_fd, &uh)) return; // access lstat second time after getting a lock // first-time lstat could be dirty (for example between writes in master) if (lstat(task, &sf_lstat)) { return; } if (uwsgi_spooler_read_content(spool_fd, spool_buf, &body, &body_len, &uh, &sf_lstat)) { destroy_spool(dir, task); return; } // now the task is running and should not be woken up uspool->running = 1; // this is used in cheap mode for making decision about who must die uspool->last_task_managed = uwsgi_now(); if (!uwsgi.spooler_quiet) uwsgi_log("[spooler %s pid: %d] managing request %s ...\n", uspool->dir, (int) uwsgi.mypid, task); // chdir before running the task (if requested) if (uwsgi.spooler_chdir) { if (chdir(uwsgi.spooler_chdir)) { uwsgi_error("spooler_manage_task()/chdir()"); } } int callable_found = 0; for (i = 0; i < 256; i++) { if (uwsgi.p[i]->spooler) { time_t now = uwsgi_now(); if (uwsgi.harakiri_options.spoolers > 0) { set_spooler_harakiri(uwsgi.harakiri_options.spoolers); } ret = uwsgi.p[i]->spooler(task, spool_buf, uh._pktsize, body, body_len); if (uwsgi.harakiri_options.spoolers > 0) { set_spooler_harakiri(0); } if (ret == 0) continue; callable_found = 1; // increase task counter uspool->tasks++; if (ret == -2) { if (!uwsgi.spooler_quiet) uwsgi_log("[spooler %s pid: %d] done with task %s after %lld seconds\n", uspool->dir, (int) uwsgi.mypid, task, (long long) uwsgi_now() - now); destroy_spool(dir, task); } // re-spool it break; } } if (body) free(body); // here we free and unlock the task uwsgi_protected_close(spool_fd); uspool->running = 0; // 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); } if (chdir(dir)) { uwsgi_error("chdir()"); uwsgi_log("[spooler] something horrible happened to the spooler. Better to kill it.\n"); exit(1); } if (!callable_found) { uwsgi_log("unable to find the spooler function, have you loaded it into the spooler process ?\n"); } } } }