⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 perchild.c

📁 Apache V2.0.15 Alpha For Linuxhttpd-2_0_15-alpha.tar.Z
💻 C
📖 第 1 页 / 共 4 页
字号:
                    NULL, pchild);    apr_lock_create(&thread_accept_mutex, APR_MUTEX, APR_INTRAPROCESS,                    NULL, pchild);    apr_threadattr_create(&worker_thread_attr, pchild);    apr_threadattr_detach_set(worker_thread_attr);                                         apr_create_signal_thread(&thread, worker_thread_attr, check_signal, pchild);    /* We are creating worker threads right now */    for (i=0; i < threads_to_start; i++) {        /* start_thread shouldn't fail here */        if (!start_thread()) {            break;        }    }    /* This thread will be be a worker thread too. */    worker_thread(&worker_thread_free_ids[max_threads - 1]);}static int make_child(server_rec *s, int slot){    int pid;    if (slot + 1 > ap_max_daemons_limit) {        ap_max_daemons_limit = slot + 1;    }    if (one_process) {	set_signals();        ap_child_table[slot].pid = getpid();        ap_child_table[slot].status = SERVER_ALIVE;	child_main(slot);    }    (void) ap_update_child_status(slot, 0, SERVER_STARTING, (request_rec *) NULL);    if ((pid = fork()) == -1) {        ap_log_error(APLOG_MARK, APLOG_ERR, errno, s,                     "fork: Unable to fork new process");	/* In case system resources are maxxed out, we don't want	   Apache running away with the CPU trying to fork over and	   over and over again. */	sleep(10);	return -1;    }    if (!pid) {#ifdef AIX_BIND_PROCESSOR      /* By default, AIX binds to a single processor.  This bit unbinds	 children which will then bind to another CPU.      */#include <sys/processor.h>        int status = bindprocessor(BINDPROCESS, (int)getpid(),			       PROCESSOR_CLASS_ANY);	if (status != OK)	    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, errno,                          ap_server_conf, "processor unbind failed %d", status);#endif        RAISE_SIGSTOP(MAKE_CHILD);	/* XXX - For an unthreaded server, a signal handler will be necessary        apr_signal(SIGTERM, just_die);	*/        child_main(slot);	return 0;    }    /* else */    ap_child_table[slot].pid = pid;    ap_child_table[slot].status = SERVER_ALIVE;    return 0;}/* start up a bunch of children */static int startup_children(int number_to_start){    int i;    for (i = 0; number_to_start && i < num_daemons; ++i) {	if (ap_child_table[i].pid) {	    continue;	}	if (make_child(ap_server_conf, i) < 0) {	    break;	}	--number_to_start;    }    return number_to_start;}/* * spawn_rate is the number of children that will be spawned on the * next maintenance cycle if there aren't enough servers.  It is * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by * without the need to spawn. */static int spawn_rate = 1;#ifndef MAX_SPAWN_RATE#define MAX_SPAWN_RATE	(32)#endifstatic int hold_off_on_exponential_spawning;static void perform_child_maintenance(void){    int i;    int free_length;    int free_slots[MAX_SPAWN_RATE];    int last_non_dead = -1;    /* initialize the free_list */    free_length = 0;        for (i = 0; i < num_daemons; ++i) {        if (ap_child_table[i].pid == 0) {            if (free_length < spawn_rate) {                free_slots[free_length] = i;                ++free_length;            }        }        else {            last_non_dead = i;        }	if (i >= ap_max_daemons_limit && free_length >= spawn_rate) {	    break;	}    }    ap_max_daemons_limit = last_non_dead + 1;    if (free_length > 0) {	for (i = 0; i < free_length; ++i) {	    make_child(ap_server_conf, free_slots[i]);	}	/* the next time around we want to spawn twice as many if this	 * wasn't good enough, but not if we've just done a graceful	 */	if (hold_off_on_exponential_spawning) {	    --hold_off_on_exponential_spawning;	}	else if (spawn_rate < MAX_SPAWN_RATE) {	    spawn_rate *= 2;	}    }    else {        spawn_rate = 1;    }}static void server_main_loop(int remaining_children_to_start){    int child_slot;    apr_wait_t status;    apr_proc_t pid;    int i;    while (!restart_pending && !shutdown_pending) {        ap_wait_or_timeout(&status, &pid, pconf);                if (pid.pid != -1) {            ap_process_child_status(&pid, status);            /* non-fatal death... note that it's gone in the child table and             * clean out the status table. */            child_slot = -1;            for (i = 0; i < ap_max_daemons_limit; ++i) {        	if (ap_child_table[i].pid == pid.pid) {                    child_slot = i;                    break;                }            }            if (child_slot >= 0) {                ap_child_table[child_slot].pid = 0;                ap_update_child_status(child_slot, i, SERVER_DEAD, (request_rec *) NULL);                		if (remaining_children_to_start		    && child_slot < num_daemons) {		    /* we're still doing a 1-for-1 replacement of dead                     * children with new children                     */		    make_child(ap_server_conf, child_slot);		    --remaining_children_to_start;		}#if APR_HAS_OTHER_CHILD	    }	    else if (apr_proc_other_child_read(&pid, status) == 0) {		/* handled */#endif	    }	    else if (is_graceful) {		/* Great, we've probably just lost a slot in the		 * child table.  Somehow we don't know about this		 * child.		 */		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, 0,                              ap_server_conf,			    "long lost child came home! (pid %ld)",                              (long)pid.pid);	    }	    /* Don't perform idle maintenance when a child dies,             * only do it when there's a timeout.  Remember only a             * finite number of children can die, and it's pretty             * pathological for a lot to die suddenly.             */	    continue;	}	else if (remaining_children_to_start) {	    /* we hit a 1 second timeout in which none of the previous	     * generation of children needed to be reaped... so assume	     * they're all done, and pick up the slack if any is left.	     */	    remaining_children_to_start = \	    	startup_children(remaining_children_to_start);	    /* In any event we really shouldn't do the code below because	     * few of the servers we just started are in the IDLE state	     * yet, so we'd mistakenly create an extra server.	     */	    continue;	}	perform_child_maintenance();    }}int ap_mpm_run(apr_pool_t *_pconf, apr_pool_t *plog, server_rec *s){    int remaining_children_to_start;    int i;    apr_status_t rv;    apr_size_t one = 1;    pconf = _pconf;    ap_server_conf = s;    if ((rv = apr_file_pipe_create(&pipe_of_death_in, &pipe_of_death_out, pconf))         != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_ERR, rv,                     (const server_rec*) ap_server_conf,                     "apr_file_pipe_create (pipe_of_death)");        exit(1);    }    if ((rv = apr_file_pipe_timeout_set(pipe_of_death_in, 0)) != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_ERR, rv,                     (const server_rec*) ap_server_conf,                     "apr_file_pipe_timeout_set (pipe_of_death)");        exit(1);    }    ap_server_conf = s;    if ((num_listenfds = ap_setup_listeners(ap_server_conf)) < 1) {        /* XXX: hey, what's the right way for the mpm to indicate a fatal error? */        ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ALERT, 0, s,            "no listening sockets available, shutting down");        return 1;    }    ap_log_pid(pconf, ap_pid_fname);    /* Initialize cross-process accept lock */    lock_fname = apr_psprintf(_pconf, "%s.%u",                             ap_server_root_relative(_pconf, lock_fname),                             my_pid);    rv = SAFE_ACCEPT(apr_lock_create(&process_accept_mutex, APR_MUTEX,                                    APR_CROSS_PROCESS, lock_fname, _pconf));    if (rv != APR_SUCCESS) {        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,                     "Couldn't create cross-process lock");        return 1;    }    if (!is_graceful) {        ap_create_scoreboard(pconf, SB_SHARED);    }    /* Initialize the child table */    if (!is_graceful) {        for (i = 0; i < HARD_SERVER_LIMIT; i++) {            ap_child_table[i].pid = 0;        }    }    set_signals();    /* If we're doing a graceful_restart then we're going to see a lot     * of children exiting immediately when we get into the main loop     * below (because we just sent them SIGWINCH).  This happens pretty     * rapidly... and for each one that exits we'll start a new one until     * we reach at least daemons_min_free.  But we may be permitted to     * start more than that, so we'll just keep track of how many we're     * supposed to start up without the 1 second penalty between each fork.     */    remaining_children_to_start = num_daemons;    if (!is_graceful) {	remaining_children_to_start = \	    startup_children(remaining_children_to_start);    }    else {	/* give the system some time to recover before kicking into	    * exponential mode */	hold_off_on_exponential_spawning = 10;    }    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,		"%s configured -- resuming normal operations",		ap_get_server_version());    ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf,		"Server built: %s", ap_get_server_built());    restart_pending = shutdown_pending = 0;    server_main_loop(remaining_children_to_start);    if (shutdown_pending) {        /* Time to gracefully shut down:         * Kill child processes, tell them to call child_exit, etc...         */        if (unixd_killpg(getpgrp(), SIGTERM) < 0) {            ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,                         "killpg SIGTERM");        }        ap_reclaim_child_processes(1);		/* Start with SIGTERM */            /* cleanup pid file on normal shutdown */        {            const char *pidfile = NULL;            pidfile = ap_server_root_relative (pconf, ap_pid_fname);            if ( pidfile != NULL && unlink(pidfile) == 0)                ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0,            		 ap_server_conf,            		 "removed PID file %s (pid=%ld)",            		 pidfile, (long)getpid());        }            ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0,                     ap_server_conf, "caught SIGTERM, shutting down");    	return 1;    }    /* we've been told to restart */    apr_signal(SIGHUP, SIG_IGN);    if (one_process) {	/* not worth thinking about */	return 1;    }    if (is_graceful) {        char char_of_death = '!';	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0, ap_server_conf,		    "SIGWINCH received.  Doing graceful restart");	/* This is mostly for debugging... so that we know what is still         * gracefully dealing with existing request.         */		for (i = 0; i < num_daemons; ++i) {	    if (ap_child_table[i].pid) {	        ap_child_table[i].status = SERVER_DYING;	    } 	}	/* give the children the signal to die */        for (i = 0; i < num_daemons;) {            if ((rv = apr_file_write(pipe_of_death_out, &char_of_death, &one)) != APR_SUCCESS) {                if (APR_STATUS_IS_EINTR(rv)) continue;                ap_log_error(APLOG_MARK, APLOG_WARNING, rv, ap_server_conf,                             "write pipe_of_death");            }            i++;        }    }    else {      /* Kill 'em all.  Since the child acts the same on the parents SIGTERM        * and a SIGHUP, we may as well use the same signal, because some user       * pthreads are stealing signals from us left and right.       */	if (unixd_killpg(getpgrp(), SIGTERM) < 0) {	    ap_log_error(APLOG_MARK, APLOG_WARNING, errno, ap_server_conf,                         "killpg SIGTERM");	}        ap_reclaim_child_processes(1);		/* Start with SIGTERM */	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, 0,                     ap_server_conf, "SIGHUP received.  Attempting to restart");    }    return 0;}static void perchild_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp){    static int restart_num = 0;    int no_detach = 0;    int i;    one_process = !!ap_exists_config_define("ONE_PROCESS");    no_detach = !!ap_exists_config_define("NO_DETACH");    /* sigh, want this only the second time around */    if (restart_num++ == 1) {	is_graceful = 0;	if (!one_process && !no_detach) {	    apr_proc_detach();	}	my_pid = getpid();    }    unixd_pre_config(ptemp);    ap_listen_pre_config();    num_daemons = DEFAULT_NUM_DAEMON;    threads_to_start = DEFAULT_START_THREAD;    min_spare_threads = DEFAULT_MIN_SPARE_THREAD;    max_spare_threads = DEFAULT_MAX_SPARE_THREAD;    max_threads = HARD_THREAD_LIMIT;    ap_pid_fname = DEFAULT_PIDLOG;    ap_scoreboard_fname = DEFAULT_SCOREBOARD;    lock_fname = DEFAULT_LOCKFILE;    max_requests_per_child = DEFAULT_MAX_REQUESTS_PER_CHILD;    curr_child_num = 0;    apr_cpystrn(ap_coredump_dir, ap_server_root, sizeof(ap_coredump_dir));    for (i = 0; i < HARD_SERVER_LIMIT; i++) {        child_info_table[i].uid = -1;        child_info_table[i].gid = -1;        child_info_table[i].sd = -1;    }    for (i = 0; i < HARD_THREAD_LIMIT; i++) {        thread_socket_table[i] = -1;    }}static int pass_request(request_rec *r){    apr_socket_t *thesock = r->connection->client_socket;    struct msghdr msg;    struct cmsghdr *cmsg;    int sfd;    struct iovec iov;    apr_bucket_brigade *bb = apr_brigade_create(r->pool);    perchild_server_conf *sconf = (perchild_server_conf *)                            ap_get_module_config(r->server->module_config,                                                  &mpm_perchild_module);    char *foo;    int len;    apr_pool_userdata_get((void **)&foo, "PERCHILD_BUFFER", r->connection->pool);    len = strlen(foo);    apr_pool_userdata_set(NULL, "PERCHILD_BUFFER", apr_pool_cleanup_null,                      r->connection->pool);    apr_os_sock_get(&sfd, thesock);    iov.iov_base = NULL;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -