void fpm_request_end(void) /* {{{ */ { struct fpm_scoreboard_proc_s *proc; struct timeval now; #ifdef HAVE_TIMES struct tms cpu; #endif size_t memory = zend_memory_peak_usage(1); fpm_clock_get(&now); #ifdef HAVE_TIMES times(&cpu); #endif proc = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (proc == NULL) { zlog(ZLOG_WARNING, "failed to acquire proc scoreboard"); return; } proc->request_stage = FPM_REQUEST_FINISHED; proc->tv = now; timersub(&now, &proc->accepted, &proc->duration); #ifdef HAVE_TIMES timersub(&proc->tv, &proc->accepted, &proc->cpu_duration); proc->last_request_cpu.tms_utime = cpu.tms_utime - proc->cpu_accepted.tms_utime; proc->last_request_cpu.tms_stime = cpu.tms_stime - proc->cpu_accepted.tms_stime; proc->last_request_cpu.tms_cutime = cpu.tms_cutime - proc->cpu_accepted.tms_cutime; proc->last_request_cpu.tms_cstime = cpu.tms_cstime - proc->cpu_accepted.tms_cstime; #endif proc->memory = memory; fpm_scoreboard_proc_release(proc); }
void fpm_request_info() { TSRMLS_FETCH(); struct fpm_shm_slot_s *slot; char *request_method = fpm_php_request_method(TSRMLS_C); char *script_filename = fpm_php_script_filename(TSRMLS_C); slot = fpm_shm_slots_acquire(0, 0); slot->request_stage = FPM_REQUEST_INFO; fpm_clock_get(&slot->tv); if (request_method) { cpystrn(slot->request_method, request_method, sizeof(slot->request_method)); } slot->content_length = fpm_php_content_length(TSRMLS_C); /* if cgi.fix_pathinfo is set to "1" and script cannot be found (404) the sapi_globals.request_info.path_translated is set to NULL */ if (script_filename) { cpystrn(slot->script_filename, script_filename, sizeof(slot->script_filename)); } fpm_shm_slots_release(slot); }
void fpm_request_executing() { struct fpm_shm_slot_s *slot; slot = fpm_shm_slots_acquire(0, 0); slot->request_stage = FPM_REQUEST_EXECUTING; fpm_clock_get(&slot->tv); fpm_shm_slots_release(slot); }
void fpm_request_finished() { struct fpm_shm_slot_s *slot; slot = fpm_shm_slots_acquire(0, 0); slot->request_stage = FPM_REQUEST_FINISHED; fpm_clock_get(&slot->tv); memset(&slot->accepted, 0, sizeof(slot->accepted)); fpm_shm_slots_release(slot); }
void fpm_request_reading_headers() { struct fpm_shm_slot_s *slot; slot = fpm_shm_slots_acquire(0, 0); slot->request_stage = FPM_REQUEST_READING_HEADERS; fpm_clock_get(&slot->tv); slot->accepted = slot->tv; fpm_shm_slots_release(slot); }
int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to_spawn, int is_debug) /* {{{ */ { pid_t pid; struct fpm_child_s *child; int max; if (wp->config->pm == PM_STYLE_DYNAMIC) { if (!in_event_loop) { /* starting */ max = wp->config->pm_start_servers; } else { max = wp->running_children + nb_to_spawn; } } else { /* PM_STYLE_STATIC */ max = wp->config->pm_max_children; } while (fpm_pctl_can_spawn_children() && wp->running_children < max) { child = fpm_resources_prepare(wp); if (!child) { return 2; } pid = fork(); switch (pid) { case 0 : fpm_child_resources_use(child); fpm_globals.is_child = 1; fpm_child_init(wp); return 0; case -1 : zlog(ZLOG_SYSERROR, "fork() failed"); fpm_resources_discard(child); return 2; default : child->pid = pid; fpm_clock_get(&child->started); fpm_parent_resources_use(child); zlog(is_debug ? ZLOG_DEBUG : ZLOG_NOTICE, "[pool %s] child %d started", wp->config->name, (int) pid); } } return 1; /* we are done */ }
void fpm_request_accepting() { struct fpm_shm_slot_s *slot; slot = fpm_shm_slots_acquire(0, 0); slot->request_stage = FPM_REQUEST_ACCEPTING; fpm_clock_get(&slot->tv); memset(slot->request_method, 0, sizeof(slot->request_method)); slot->content_length = 0; memset(slot->script_filename, 0, sizeof(slot->script_filename)); fpm_shm_slots_release(slot); }
void fpm_request_info() /* {{{ */ { struct fpm_scoreboard_proc_s *proc; char *request_uri = fpm_php_request_uri(); char *request_method = fpm_php_request_method(); char *script_filename = fpm_php_script_filename(); char *query_string = fpm_php_query_string(); char *auth_user = fpm_php_auth_user(); size_t content_length = fpm_php_content_length(); struct timeval now; fpm_clock_get(&now); proc = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (proc == NULL) { zlog(ZLOG_WARNING, "failed to acquire proc scoreboard"); return; } proc->request_stage = FPM_REQUEST_INFO; proc->tv = now; if (request_uri) { strlcpy(proc->request_uri, request_uri, sizeof(proc->request_uri)); } if (request_method) { strlcpy(proc->request_method, request_method, sizeof(proc->request_method)); } if (query_string) { strlcpy(proc->query_string, query_string, sizeof(proc->query_string)); } if (auth_user) { strlcpy(proc->auth_user, auth_user, sizeof(proc->auth_user)); } proc->content_length = content_length; /* if cgi.fix_pathinfo is set to "1" and script cannot be found (404) the sapi_globals.request_info.path_translated is set to NULL */ if (script_filename) { strlcpy(proc->script_filename, script_filename, sizeof(proc->script_filename)); } fpm_scoreboard_proc_release(proc); }
void fpm_request_finished() /* {{{ */ { struct fpm_scoreboard_proc_s *proc; struct timeval now; fpm_clock_get(&now); proc = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (proc == NULL) { zlog(ZLOG_WARNING, "failed to acquire proc scoreboard"); return; } proc->request_stage = FPM_REQUEST_FINISHED; proc->tv = now; fpm_scoreboard_proc_release(proc); }
void fpm_request_reading_headers() /* {{{ */ { struct fpm_scoreboard_proc_s *proc; struct timeval now; clock_t now_epoch; #ifdef HAVE_TIMES struct tms cpu; #endif fpm_clock_get(&now); now_epoch = time(NULL); #ifdef HAVE_TIMES times(&cpu); #endif proc = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (proc == NULL) { zlog(ZLOG_WARNING, "failed to acquire proc scoreboard"); return; } proc->request_stage = FPM_REQUEST_READING_HEADERS; proc->tv = now; proc->accepted = now; proc->accepted_epoch = now_epoch; #ifdef HAVE_TIMES proc->cpu_accepted = cpu; #endif proc->requests++; proc->request_uri[0] = '\0'; proc->request_method[0] = '\0'; proc->script_filename[0] = '\0'; proc->query_string[0] = '\0'; proc->query_string[0] = '\0'; proc->auth_user[0] = '\0'; proc->content_length = 0; fpm_scoreboard_proc_release(proc); /* idle--, active++, request++ */ fpm_scoreboard_update(-1, 1, 0, 0, 1, 0, 0, FPM_SCOREBOARD_ACTION_INC, NULL); }
void fpm_request_accepting() /* {{{ */ { struct fpm_scoreboard_proc_s *proc; struct timeval now; fpm_clock_get(&now); proc = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (proc == NULL) { zlog(ZLOG_WARNING, "failed to acquire proc scoreboard"); return; } proc->request_stage = FPM_REQUEST_ACCEPTING; proc->tv = now; fpm_scoreboard_proc_release(proc); /* idle++, active-- */ fpm_scoreboard_update(1, -1, 0, 0, 0, 0, 0, FPM_SCOREBOARD_ACTION_INC, NULL); }
void fpm_status_update_activity(struct fpm_shm_s *shm, int idle, int active, int total, unsigned cur_lq, int max_lq, int clear_last_update) /* {{{ */ { struct fpm_status_s status; if (!shm) shm = fpm_status_shm; if (!shm || !shm->mem) return; /* one shot operation */ status = *(struct fpm_status_s *)shm->mem; status.idle = idle; status.active = active; status.total = total; status.cur_lq = cur_lq; status.max_lq = max_lq; if (clear_last_update) { memset(&status.last_update, 0, sizeof(status.last_update)); } else { fpm_clock_get(&status.last_update); } /* one shot operation */ *(struct fpm_status_s *)shm->mem = status; }
int fpm_status_handle_request(TSRMLS_D) /* {{{ */ { struct fpm_scoreboard_s scoreboard, *scoreboard_p; struct fpm_scoreboard_proc_s proc; char *buffer, *time_format, time_buffer[64]; time_t now_epoch; int full, encode; char *short_syntax, *short_post; char *full_pre, *full_syntax, *full_post, *full_separator; zend_string *_GET_str; if (!SG(request_info).request_uri) { return 0; } /* PING */ if (fpm_status_ping_uri && fpm_status_ping_response && !strcmp(fpm_status_ping_uri, SG(request_info).request_uri)) { fpm_request_executing(); sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1 TSRMLS_CC); sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1 TSRMLS_CC); sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1 TSRMLS_CC); SG(sapi_headers).http_response_code = 200; /* handle HEAD */ if (SG(request_info).headers_only) { return 1; } PUTS(fpm_status_ping_response); return 1; } /* STATUS */ if (fpm_status_uri && !strcmp(fpm_status_uri, SG(request_info).request_uri)) { fpm_request_executing(); scoreboard_p = fpm_scoreboard_get(); if (!scoreboard_p) { zlog(ZLOG_ERROR, "status: unable to find or access status shared memory"); SG(sapi_headers).http_response_code = 500; sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1 TSRMLS_CC); sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1 TSRMLS_CC); sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1 TSRMLS_CC); PUTS("Internal error. Please review log file for errors."); return 1; } if (!fpm_spinlock(&scoreboard_p->lock, 1)) { zlog(ZLOG_NOTICE, "[pool %s] status: scoreboard already in used.", scoreboard_p->pool); SG(sapi_headers).http_response_code = 503; sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1 TSRMLS_CC); sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1 TSRMLS_CC); sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1 TSRMLS_CC); PUTS("Server busy. Please try again later."); return 1; } /* copy the scoreboard not to bother other processes */ scoreboard = *scoreboard_p; fpm_unlock(scoreboard_p->lock); if (scoreboard.idle < 0 || scoreboard.active < 0) { zlog(ZLOG_ERROR, "[pool %s] invalid status values", scoreboard.pool); SG(sapi_headers).http_response_code = 500; sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1 TSRMLS_CC); sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1 TSRMLS_CC); sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1 TSRMLS_CC); PUTS("Internal error. Please review log file for errors."); return 1; } /* send common headers */ sapi_add_header_ex(ZEND_STRL("Expires: Thu, 01 Jan 1970 00:00:00 GMT"), 1, 1 TSRMLS_CC); sapi_add_header_ex(ZEND_STRL("Cache-Control: no-cache, no-store, must-revalidate, max-age=0"), 1, 1 TSRMLS_CC); SG(sapi_headers).http_response_code = 200; /* handle HEAD */ if (SG(request_info).headers_only) { return 1; } /* full status ? */ _GET_str = STR_INIT("_GET", sizeof("_GET")-1, 0); full = (fpm_php_get_string_from_table(_GET_str, "full" TSRMLS_CC) != NULL); short_syntax = short_post = NULL; full_separator = full_pre = full_syntax = full_post = NULL; encode = 0; /* HTML */ if (fpm_php_get_string_from_table(_GET_str, "html" TSRMLS_CC)) { sapi_add_header_ex(ZEND_STRL("Content-Type: text/html"), 1, 1 TSRMLS_CC); time_format = "%d/%b/%Y:%H:%M:%S %z"; encode = 1; short_syntax = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n" "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n" "<head><title>PHP-FPM Status Page</title></head>\n" "<body>\n" "<table>\n" "<tr><th>pool</th><td>%s</td></tr>\n" "<tr><th>process manager</th><td>%s</td></tr>\n" "<tr><th>start time</th><td>%s</td></tr>\n" "<tr><th>start since</th><td>%lu</td></tr>\n" "<tr><th>accepted conn</th><td>%lu</td></tr>\n" #ifdef HAVE_FPM_LQ "<tr><th>listen queue</th><td>%u</td></tr>\n" "<tr><th>max listen queue</th><td>%u</td></tr>\n" "<tr><th>listen queue len</th><td>%d</td></tr>\n" #endif "<tr><th>idle processes</th><td>%d</td></tr>\n" "<tr><th>active processes</th><td>%d</td></tr>\n" "<tr><th>total processes</th><td>%d</td></tr>\n" "<tr><th>max active processes</th><td>%d</td></tr>\n" "<tr><th>max children reached</th><td>%u</td></tr>\n" "<tr><th>slow requests</th><td>%lu</td></tr>\n" "</table>\n"; if (!full) { short_post = "</body></html>"; } else { full_pre = "<table border=\"1\">\n" "<tr>" "<th>pid</th>" "<th>state</th>" "<th>start time</th>" "<th>start since</th>" "<th>requests</th>" "<th>request duration</th>" "<th>request method</th>" "<th>request uri</th>" "<th>content length</th>" "<th>user</th>" "<th>script</th>" #ifdef HAVE_FPM_LQ "<th>last request cpu</th>" #endif "<th>last request memory</th>" "</tr>\n"; full_syntax = "<tr>" "<td>%d</td>" "<td>%s</td>" "<td>%s</td>" "<td>%lu</td>" "<td>%lu</td>" "<td>%lu</td>" "<td>%s</td>" "<td>%s%s%s</td>" "<td>%zu</td>" "<td>%s</td>" "<td>%s</td>" #ifdef HAVE_FPM_LQ "<td>%.2f</td>" #endif "<td>%zu</td>" "</tr>\n"; full_post = "</table></body></html>"; } /* XML */ } else if (fpm_php_get_string_from_table(_GET_str, "xml" TSRMLS_CC)) { sapi_add_header_ex(ZEND_STRL("Content-Type: text/xml"), 1, 1 TSRMLS_CC); time_format = "%s"; encode = 1; short_syntax = "<?xml version=\"1.0\" ?>\n" "<status>\n" "<pool>%s</pool>\n" "<process-manager>%s</process-manager>\n" "<start-time>%s</start-time>\n" "<start-since>%lu</start-since>\n" "<accepted-conn>%lu</accepted-conn>\n" #ifdef HAVE_FPM_LQ "<listen-queue>%u</listen-queue>\n" "<max-listen-queue>%u</max-listen-queue>\n" "<listen-queue-len>%d</listen-queue-len>\n" #endif "<idle-processes>%d</idle-processes>\n" "<active-processes>%d</active-processes>\n" "<total-processes>%d</total-processes>\n" "<max-active-processes>%d</max-active-processes>\n" "<max-children-reached>%u</max-children-reached>\n" "<slow-requests>%lu</slow-requests>\n"; if (!full) { short_post = "</status>"; } else { full_pre = "<processes>\n"; full_syntax = "<process>" "<pid>%d</pid>" "<state>%s</state>" "<start-time>%s</start-time>" "<start-since>%lu</start-since>" "<requests>%lu</requests>" "<request-duration>%lu</request-duration>" "<request-method>%s</request-method>" "<request-uri>%s%s%s</request-uri>" "<content-length>%zu</content-length>" "<user>%s</user>" "<script>%s</script>" #ifdef HAVE_FPM_LQ "<last-request-cpu>%.2f</last-request-cpu>" #endif "<last-request-memory>%zu</last-request-memory>" "</process>\n" ; full_post = "</processes>\n</status>"; } /* JSON */ } else if (fpm_php_get_string_from_table(_GET_str, "json" TSRMLS_CC)) { sapi_add_header_ex(ZEND_STRL("Content-Type: application/json"), 1, 1 TSRMLS_CC); time_format = "%s"; short_syntax = "{" "\"pool\":\"%s\"," "\"process manager\":\"%s\"," "\"start time\":%s," "\"start since\":%lu," "\"accepted conn\":%lu," #ifdef HAVE_FPM_LQ "\"listen queue\":%u," "\"max listen queue\":%u," "\"listen queue len\":%d," #endif "\"idle processes\":%d," "\"active processes\":%d," "\"total processes\":%d," "\"max active processes\":%d," "\"max children reached\":%u," "\"slow requests\":%lu"; if (!full) { short_post = "}"; } else { full_separator = ","; full_pre = ", \"processes\":["; full_syntax = "{" "\"pid\":%d," "\"state\":\"%s\"," "\"start time\":%s," "\"start since\":%lu," "\"requests\":%lu," "\"request duration\":%lu," "\"request method\":\"%s\"," "\"request uri\":\"%s%s%s\"," "\"content length\":%zu," "\"user\":\"%s\"," "\"script\":\"%s\"," #ifdef HAVE_FPM_LQ "\"last request cpu\":%.2f," #endif "\"last request memory\":%zu" "}"; full_post = "]}"; } /* TEXT */ } else { sapi_add_header_ex(ZEND_STRL("Content-Type: text/plain"), 1, 1 TSRMLS_CC); time_format = "%d/%b/%Y:%H:%M:%S %z"; short_syntax = "pool: %s\n" "process manager: %s\n" "start time: %s\n" "start since: %lu\n" "accepted conn: %lu\n" #ifdef HAVE_FPM_LQ "listen queue: %u\n" "max listen queue: %u\n" "listen queue len: %d\n" #endif "idle processes: %d\n" "active processes: %d\n" "total processes: %d\n" "max active processes: %d\n" "max children reached: %u\n" "slow requests: %lu\n"; if (full) { full_syntax = "\n" "************************\n" "pid: %d\n" "state: %s\n" "start time: %s\n" "start since: %lu\n" "requests: %lu\n" "request duration: %lu\n" "request method: %s\n" "request URI: %s%s%s\n" "content length: %zu\n" "user: %s\n" "script: %s\n" #ifdef HAVE_FPM_LQ "last request cpu: %.2f\n" #endif "last request memory: %zu\n"; } } strftime(time_buffer, sizeof(time_buffer) - 1, time_format, localtime(&scoreboard.start_epoch)); now_epoch = time(NULL); spprintf(&buffer, 0, short_syntax, scoreboard.pool, PM2STR(scoreboard.pm), time_buffer, now_epoch - scoreboard.start_epoch, scoreboard.requests, #ifdef HAVE_FPM_LQ scoreboard.lq, scoreboard.lq_max, scoreboard.lq_len, #endif scoreboard.idle, scoreboard.active, scoreboard.idle + scoreboard.active, scoreboard.active_max, scoreboard.max_children_reached, scoreboard.slow_rq); PUTS(buffer); efree(buffer); STR_RELEASE(_GET_str); if (short_post) { PUTS(short_post); } /* no need to test the var 'full' */ if (full_syntax) { int i, first; zend_string *tmp_query_string; char *query_string; struct timeval duration, now; #ifdef HAVE_FPM_LQ float cpu; #endif fpm_clock_get(&now); if (full_pre) { PUTS(full_pre); } first = 1; for (i=0; i<scoreboard_p->nprocs; i++) { if (!scoreboard_p->procs[i] || !scoreboard_p->procs[i]->used) { continue; } proc = *scoreboard_p->procs[i]; if (first) { first = 0; } else { if (full_separator) { PUTS(full_separator); } } query_string = NULL; tmp_query_string = NULL; if (proc.query_string[0] != '\0') { if (!encode) { query_string = proc.query_string; } else { tmp_query_string = php_escape_html_entities_ex((unsigned char *)proc.query_string, strlen(proc.query_string), 1, ENT_HTML_IGNORE_ERRORS & ENT_COMPAT, NULL, 1 TSRMLS_CC); query_string = tmp_query_string->val; } } #ifdef HAVE_FPM_LQ /* prevent NaN */ if (proc.cpu_duration.tv_sec == 0 && proc.cpu_duration.tv_usec == 0) { cpu = 0.; } else { cpu = (proc.last_request_cpu.tms_utime + proc.last_request_cpu.tms_stime + proc.last_request_cpu.tms_cutime + proc.last_request_cpu.tms_cstime) / fpm_scoreboard_get_tick() / (proc.cpu_duration.tv_sec + proc.cpu_duration.tv_usec / 1000000.) * 100.; } #endif if (proc.request_stage == FPM_REQUEST_ACCEPTING) { duration = proc.duration; } else { timersub(&now, &proc.accepted, &duration); } strftime(time_buffer, sizeof(time_buffer) - 1, time_format, localtime(&proc.start_epoch)); spprintf(&buffer, 0, full_syntax, proc.pid, fpm_request_get_stage_name(proc.request_stage), time_buffer, now_epoch - proc.start_epoch, proc.requests, duration.tv_sec * 1000000UL + duration.tv_usec, proc.request_method[0] != '\0' ? proc.request_method : "-", proc.request_uri[0] != '\0' ? proc.request_uri : "-", query_string ? "?" : "", query_string ? query_string : "", proc.content_length, proc.auth_user[0] != '\0' ? proc.auth_user : "******", proc.script_filename[0] != '\0' ? proc.script_filename : "-", #ifdef HAVE_FPM_LQ proc.request_stage == FPM_REQUEST_ACCEPTING ? cpu : 0., #endif proc.request_stage == FPM_REQUEST_ACCEPTING ? proc.memory : 0); PUTS(buffer); efree(buffer); if (tmp_query_string) { STR_FREE(tmp_query_string); } } if (full_post) { PUTS(full_post); } } return 1; } return 0; }
int fpm_children_make(struct fpm_worker_pool_s *wp, int in_event_loop, int nb_to_spawn, int is_debug) /* {{{ */ { pid_t pid; struct fpm_child_s *child; int max; static int warned = 0; //动态模式 if (wp->config->pm == PM_STYLE_DYNAMIC) { if (!in_event_loop) { /* starting */ max = wp->config->pm_start_servers; } else { max = wp->running_children + nb_to_spawn; } } else if (wp->config->pm == PM_STYLE_ONDEMAND) { //ondemand模式 if (!in_event_loop) { /* starting */ max = 0; /* do not create any child at startup */ } else { max = wp->running_children + nb_to_spawn; } } else { /* PM_STYLE_STATIC */ //静态模式 max = wp->config->pm_max_children; } /* * fork children while: * - fpm_pctl_can_spawn_children : FPM is running in a NORMAL state (aka not restart, stop or reload) * - wp->running_children < max : there is less than the max process for the current pool * - (fpm_global_config.process_max < 1 || fpm_globals.running_children < fpm_global_config.process_max): * if fpm_global_config.process_max is set, FPM has not fork this number of processes (globaly) */ //当执行restart、stop、reload命令时,fpm_pctl_can_spawn_children()为false while (fpm_pctl_can_spawn_children() && wp->running_children < max && (fpm_global_config.process_max < 1 || fpm_globals.running_children < fpm_global_config.process_max)) { warned = 0; child = fpm_resources_prepare(wp); if (!child) { return 2; } //fork子进程 pid = fork(); switch (pid) { case 0 : fpm_child_resources_use(child); fpm_globals.is_child = 1; //子进程初始化 fpm_child_init(wp); return 0; case -1 : zlog(ZLOG_SYSERROR, "fork() failed"); fpm_resources_discard(child); return 2; default : child->pid = pid; fpm_clock_get(&child->started); fpm_parent_resources_use(child); zlog(is_debug ? ZLOG_DEBUG : ZLOG_NOTICE, "[pool %s] child %d started", wp->config->name, (int) pid); } } if (!warned && fpm_global_config.process_max > 0 && fpm_globals.running_children >= fpm_global_config.process_max) { warned = 1; zlog(ZLOG_WARNING, "The maximum number of processes has been reached. Please review your configuration and consider raising 'process.max'"); } return 1; /* we are done */ }
void fpm_children_bury() /* {{{ */ { int status; pid_t pid; struct fpm_child_s *child; while ( (pid = waitpid(-1, &status, WNOHANG | WUNTRACED)) > 0) { char buf[128]; int severity = ZLOG_NOTICE; int restart_child = 1; child = fpm_child_find(pid); /* WIFEXITED(status)如果子进程正常结束则为非0值。 WEXITSTATUS(status)取得子进程exit()返回的结束代码,一般会先用WIFEXITED 来判断是否正常结束才能使用此宏。 WIFSIGNALED(status)如果子进程是因为信号而结束则此宏值为真 WTERMSIG(status)取得子进程因信号而中止的信号代码,一般会先用WIFSIGNALED 来判断后才使用此宏。 WIFSTOPPED(status)如果子进程处于暂停执行情况则此宏值为真。一般只有使用WUNTRACED 时才会有此情况。 WSTOPSIG(status)取得引发子进程暂停的信号代码, */ if (WIFEXITED(status)) { snprintf(buf, sizeof(buf), "with code %d", WEXITSTATUS(status)); /* if it's been killed because of dynamic process management * don't restart it automaticaly */ if (child && child->idle_kill) { restart_child = 0; } if (WEXITSTATUS(status) != FPM_EXIT_OK) { severity = ZLOG_WARNING; } } else if (WIFSIGNALED(status)) { const char *signame = fpm_signal_names[WTERMSIG(status)]; const char *have_core = WCOREDUMP(status) ? " - core dumped" : ""; if (signame == NULL) { signame = ""; } snprintf(buf, sizeof(buf), "on signal %d (%s%s)", WTERMSIG(status), signame, have_core); /* if it's been killed because of dynamic process management * don't restart it automaticaly */ if (child && child->idle_kill && WTERMSIG(status) == SIGQUIT) { restart_child = 0; } if (WTERMSIG(status) != SIGQUIT) { /* possible request loss */ severity = ZLOG_WARNING; } } else if (WIFSTOPPED(status)) { zlog(ZLOG_NOTICE, "child %d stopped for tracing", (int) pid); //回调 php_trace.c if (child && child->tracer) { child->tracer(child); } continue; } if (child) { struct fpm_worker_pool_s *wp = child->wp; struct timeval tv1, tv2; fpm_child_unlink(child); //释放scoreboard fpm_scoreboard_proc_free(wp->scoreboard, child->scoreboard_i); fpm_clock_get(&tv1); timersub(&tv1, &child->started, &tv2); if (restart_child) { if (!fpm_pctl_can_spawn_children()) { severity = ZLOG_DEBUG; } zlog(severity, "[pool %s] child %d exited %s after %ld.%06d seconds from start", child->wp->config->name, (int) pid, buf, tv2.tv_sec, (int) tv2.tv_usec); } else { zlog(ZLOG_DEBUG, "[pool %s] child %d has been killed by the process managment after %ld.%06d seconds from start", child->wp->config->name, (int) pid, tv2.tv_sec, (int) tv2.tv_usec); } fpm_child_close(child, 1 /* in event_loop */); fpm_pctl_child_exited(); if (last_faults && (WTERMSIG(status) == SIGSEGV || WTERMSIG(status) == SIGBUS)) { time_t now = tv1.tv_sec; int restart_condition = 1; int i; last_faults[fault++] = now; if (fault == fpm_global_config.emergency_restart_threshold) { fault = 0; } for (i = 0; i < fpm_global_config.emergency_restart_threshold; i++) { if (now - last_faults[i] > fpm_global_config.emergency_restart_interval) { restart_condition = 0; break; } } if (restart_condition) { zlog(ZLOG_WARNING, "failed processes threshold (%d in %d sec) is reached, initiating reload", fpm_global_config.emergency_restart_threshold, fpm_global_config.emergency_restart_interval); fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET); } } if (restart_child) { fpm_children_make(wp, 1 /* in event loop */, 1, 0); if (fpm_globals.is_child) { break; } } } else { zlog(ZLOG_ALERT, "oops, unknown child (%d) exited %s. Please open a bug report (https://bugs.php.net).", pid, buf); } } }
// 初始化fpm_request_info void fpm_request_info() /* {{{ */ { TSRMLS_FETCH(); // 记分牌,记录请求的相关信息 struct fpm_scoreboard_proc_s *proc; //从SG全局变量中拿各种数据 /* * uri * method * filename * query_string * 等等 */ char *request_uri = fpm_php_request_uri(TSRMLS_C); char *request_method = fpm_php_request_method(TSRMLS_C); char *script_filename = fpm_php_script_filename(TSRMLS_C); char *query_string = fpm_php_query_string(TSRMLS_C); char *auth_user = fpm_php_auth_user(TSRMLS_C); size_t content_length = fpm_php_content_length(TSRMLS_C); struct timeval now; fpm_clock_get(&now); // 拿到进程,加锁 proc = fpm_scoreboard_proc_acquire(NULL, -1, 0); if (proc == NULL) { zlog(ZLOG_WARNING, "failed to acquire proc scoreboard"); return; } proc->request_stage = FPM_REQUEST_INFO; proc->tv = now; if (request_uri) { strlcpy(proc->request_uri, request_uri, sizeof(proc->request_uri)); } if (request_method) { // post, get, delete, or... strlcpy(proc->request_method, request_method, sizeof(proc->request_method)); } if (query_string) { strlcpy(proc->query_string, query_string, sizeof(proc->query_string)); } if (auth_user) { strlcpy(proc->auth_user, auth_user, sizeof(proc->auth_user)); } proc->content_length = content_length; /* if cgi.fix_pathinfo is set to "1" and script cannot be found (404) the sapi_globals.request_info.path_translated is set to NULL */ if (script_filename) { strlcpy(proc->script_filename, script_filename, sizeof(proc->script_filename)); } // 释放锁 fpm_scoreboard_proc_release(proc); }