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

📄 spmt_os2.c

📁 Apache V2.0.15 Alpha For Linuxhttpd-2_0_15-alpha.tar.Z
💻 C
📖 第 1 页 / 共 3 页
字号:
    r->connection->keepalive = 0;    thread_control[THREAD_GLOBAL(thread_num)].deferred_die = 1;}int ap_graceful_stop_signalled(void){    if (thread_control[THREAD_GLOBAL(thread_num)].deferred_die ||	ap_scoreboard_image->global.running_generation != thread_control[THREAD_GLOBAL(thread_num)].generation) {	return 1;    }    return 0;}int ap_stop_signalled(void){    if (shutdown_pending || restart_pending ||        thread_control[THREAD_GLOBAL(thread_num)].deferred_die ||	ap_scoreboard_image->global.running_generation != thread_control[THREAD_GLOBAL(thread_num)].generation) {	return 1;    }    return 0;}static int setup_listen_poll(apr_pool_t *pchild, apr_pollfd_t **listen_poll){    ap_listen_rec *lr;    int numfds = 0;    for (lr = ap_listeners; lr; lr = lr->next) {        numfds++;    }    apr_poll_setup(listen_poll, numfds, pchild);    for (lr = ap_listeners; lr; lr = lr->next) {	apr_poll_socket_add(*listen_poll, lr->sd, APR_POLLIN);    }    return 0;}static void thread_main(void *thread_num_arg){    ap_listen_rec *lr = NULL;    ap_listen_rec *first_lr = NULL;    apr_pool_t *ptrans;    conn_rec *current_conn;    apr_pool_t *pchild;    int requests_this_child = 0;    apr_pollfd_t *listen_poll;    apr_socket_t *csd = NULL;    int nsds, rv;    /* Disable the restart signal handlers and enable the just_die stuff.     * Note that since restart() just notes that a restart has been     * requested there's no race condition here.     */    set_signals(); /* signals aren't inherrited by child threads */    signal(SIGHUP, just_die);    signal(SIGUSR1, just_die);    signal(SIGTERM, just_die);    /* Get a sub pool for global allocations in this child, so that     * we can have cleanups occur when the child exits.     */    apr_pool_create(&pchild, pconf);    *ppthread_globals = (struct thread_globals *)apr_palloc(pchild, sizeof(struct thread_globals));    THREAD_GLOBAL(thread_num) = (int)thread_num_arg;    THREAD_GLOBAL(pchild) = pchild;    thread_control[THREAD_GLOBAL(thread_num)].generation = ap_scoreboard_image->global.running_generation;    apr_pool_create(&ptrans, pchild);    if (setup_listen_poll(pchild, &listen_poll)) {	clean_child_exit(1);    }    /* needs to be done before we switch UIDs so we have permissions */    SAFE_ACCEPT(accept_mutex_child_init(pchild));    ap_run_child_init(pchild, ap_server_conf);    (void) ap_update_child_status(0, THREAD_GLOBAL(thread_num), SERVER_READY, (request_rec *) NULL);        signal(SIGHUP, just_die);    signal(SIGTERM, just_die);    while (!ap_stop_signalled()) {        int srv;        apr_socket_t *sd;	/* Prepare to receive a SIGUSR1 due to graceful restart so that	 * we can exit cleanly.	 */	THREAD_GLOBAL(usr1_just_die) = 1;	signal(SIGUSR1, usr1_handler);	/*	 * (Re)initialize this child to a pre-connection state.	 */	current_conn = NULL;	apr_pool_clear(ptrans);	if ((ap_max_requests_per_child > 0	     && requests_this_child++ >= ap_max_requests_per_child)) {	    clean_child_exit(0);	}	(void) ap_update_child_status(0, THREAD_GLOBAL(thread_num), SERVER_READY, (request_rec *) NULL);	/*	 * Wait for an acceptable connection to arrive.	 */	/* Lock around "accept", if necessary */        SAFE_ACCEPT(accept_mutex_on());        if (ap_stop_signalled()) {            clean_child_exit(0);        }	for (;;) {	    if (ap_listeners->next) {		/* more than one socket */                srv = apr_poll(listen_poll, &nsds, -1);		if (srv != APR_SUCCESS) {		    /* Single Unix documents select as returning errnos		     * EBADF, EINTR, and EINVAL... and in none of those		     * cases does it make sense to continue.  In fact		     * on Linux 2.0.x we seem to end up with EFAULT		     * occasionally, and we'd loop forever due to it.		     */		    ap_log_error(APLOG_MARK, APLOG_ERR, errno, ap_server_conf, "select: (listen)");		    clean_child_exit(1);		}		/* we remember the last_lr we searched last time around so that		   we don't end up starving any particular listening socket */		if (first_lr == NULL) {		    first_lr = ap_listeners;		}		                lr = first_lr;		                do {                    apr_int16_t event;		    if (!lr) {			lr = ap_listeners;		    }                    apr_poll_revents_get(&event, lr->sd, listen_poll);		    if (event == APR_POLLIN) {                        first_lr = lr->next;		        break;		    }		    lr = lr->next;		} while (lr != first_lr);				if (lr == first_lr) {		    continue;		}		sd = lr->sd;	    }	    else {		/* only one socket, just pretend we did the other stuff */		sd = ap_listeners->sd;	    }	    /* if we accept() something we don't want to die, so we have to	     * defer the exit	     */            THREAD_GLOBAL(usr1_just_die) = 0;            rv = apr_accept(&csd, sd, ptrans);            if (APR_STATUS_IS_SUCCESS(rv)) {		break;		/* We have a socket ready for reading */            }            else if (APR_STATUS_IS_ECONNABORTED(rv)                   || APR_STATUS_IS_ECONNRESET(rv)                  || APR_STATUS_IS_ETIMEDOUT(rv)                  || APR_STATUS_IS_EHOSTUNREACH(rv)                  || APR_STATUS_IS_ENETUNREACH(rv)) {		/* Our old behaviour here was to continue after accept()		 * errors.  But this leads us into lots of troubles		 * because most of the errors are quite fatal.  For		 * example, EMFILE can be caused by slow descriptor		 * leaks (say in a 3rd party module, or libc).  It's		 * foolish for us to continue after an EMFILE.  We also		 * seem to tickle kernel bugs on some platforms which		 * lead to never-ending loops here.  So it seems best		 * to just exit in most cases.		 */                /* Linux generates most of these, other tcp                 * stacks (i.e. bsd) tend to hide them behind                 * getsockopt() interfaces.  They occur when                 * the net goes sour or the client disconnects                 * after the three-way handshake has been done                 * in the kernel but before userland has picked                 * up the socket.                 */                 break;            }            else if (APR_STATUS_IS_EINTR(rv)) {                /* We only get hit by an EINTR if the parent is                 * killing us off                 */                clean_child_exit(0);            }            else {                ap_log_error(APLOG_MARK, APLOG_ERR, rv, ap_server_conf,                             "accept: (client socket)");                clean_child_exit(1);	    }	    if (ap_stop_signalled()) {		clean_child_exit(0);	    }	    THREAD_GLOBAL(usr1_just_die) = 1;	}	SAFE_ACCEPT(accept_mutex_off());	/* unlock after "accept" */	/* We've got a socket, let's at least process one request off the	 * socket before we accept a graceful restart request.  We set	 * the signal to ignore because we don't want to disturb any	 * third party code.	 */	signal(SIGUSR1, SIG_IGN);	/*	 * We now have a connection, so set it up with the appropriate	 * socket options, file descriptors, and read/write buffers.	 */	ap_sock_disable_nagle(csd);	current_conn = ap_new_connection(ptrans, ap_server_conf, csd,                                         THREAD_GLOBAL(thread_num));        if (current_conn) {            ap_process_connection(current_conn);            ap_lingering_close(current_conn);        }    }    clean_child_exit(0);}static int make_child(server_rec *s, int slot){    TID tid;    if (slot + 1 > max_daemons_limit) {	max_daemons_limit = slot + 1;    }    if (one_process) {        struct thread_globals *parent_globals = *ppthread_globals;	signal(SIGHUP, just_die);	signal(SIGINT, just_die);#ifdef SIGQUIT	signal(SIGQUIT, SIG_DFL);#endif	signal(SIGTERM, just_die);        thread_main((void *)slot);        *ppthread_globals = parent_globals;    }    ap_update_child_status(0, slot, SERVER_STARTING, (request_rec *) NULL);    if ((tid = _beginthread(thread_main, NULL,  256*1024, (void *)slot)) == -1) {	ap_log_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, s, "_beginthread: Unable to create new thread");	/* _beginthread didn't succeed. Fix the scoreboard or else	 * it will say SERVER_STARTING forever and ever	 */	(void) ap_update_child_status(0, slot, SERVER_DEAD, (request_rec *) NULL);	/* In case system resources are maxxed out, we don't want	   Apache running away with the CPU trying to _beginthread over and	   over and over again. */	sleep(10);	return -1;    }    ap_scoreboard_image->servers[0][slot].tid = tid;    return 0;}/* start up a bunch of children */static void startup_children(int number_to_start){    int i;    for (i = 0; number_to_start && i < ap_daemons_limit; ++i) {	if (ap_scoreboard_image->servers[0][i].status != SERVER_DEAD) {	    continue;	}	if (make_child(ap_server_conf, i) < 0) {	    break;	}	--number_to_start;    }}/* * idle_spawn_rate is the number of children that will be spawned on the * next maintenance cycle if there aren't enough idle servers.  It is * doubled up to MAX_SPAWN_RATE, and reset only when a cycle goes by * without the need to spawn. */static int idle_spawn_rate = 1;#ifndef MAX_SPAWN_RATE#define MAX_SPAWN_RATE	(32)#endifstatic int hold_off_on_exponential_spawning;static void perform_idle_server_maintenance(void){    int i;    int to_kill;    int idle_count;    short_score *ss;    int free_length;    int free_slots[MAX_SPAWN_RATE];    int last_non_dead;    int total_non_dead;    /* initialize the free_list */    free_length = 0;    to_kill = -1;    idle_count = 0;    last_non_dead = -1;    total_non_dead = 0;    for (i = 0; i < ap_daemons_limit; ++i) {	int status;	if (i >= max_daemons_limit && free_length == idle_spawn_rate)	    break;	ss = &ap_scoreboard_image->servers[0][i];	status = ss->status;	if (status == SERVER_DEAD) {	    /* try to keep children numbers as low as possible */	    if (free_length < idle_spawn_rate) {		free_slots[free_length] = i;		++free_length;	    }	}	else {	    /* We consider a starting server as idle because we started it	     * at least a cycle ago, and if it still hasn't finished starting	     * then we're just going to swamp things worse by forking more.	     * So we hopefully won't need to fork more if we count it.	     * This depends on the ordering of SERVER_READY and SERVER_STARTING.	     */	    if (status <= SERVER_READY) {		++ idle_count;		/* always kill the highest numbered child if we have to...		 * no really well thought out reason ... other than observing		 * the server behaviour under linux where lower numbered children		 * tend to service more hits (and hence are more likely to have		 * their data in cpu caches).		 */		to_kill = i;	    }	    ++total_non_dead;	    last_non_dead = i;	}    }    max_daemons_limit = last_non_dead + 1;    if (idle_count > ap_daemons_max_free) {	/* kill off one child... we use SIGUSR1 because that'll cause it to	 * shut down gracefully, in case it happened to pick up a request	 * while we were counting	 */	thread_control[to_kill].deferred_die = 1;	idle_spawn_rate = 1;    }    else if (idle_count < ap_daemons_min_free) {	/* terminate the free list */	if (free_length == 0) {	    /* only report this condition once */	    static int reported = 0;	    if (!reported) {		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, ap_server_conf,			    "server reached MaxClients setting, consider"			    " raising the MaxClients setting");		reported = 1;	    }	    idle_spawn_rate = 1;	}	else {	    if (idle_spawn_rate >= 8) {		ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, ap_server_conf,		    "server seems busy, (you may need "		    "to increase StartServers, or Min/MaxSpareServers), "		    "spawning %d children, there are %d idle, and "		    "%d total children", idle_spawn_rate,		    idle_count, total_non_dead);	    }	    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 (idle_spawn_rate < MAX_SPAWN_RATE) {		idle_spawn_rate *= 2;	    }	}    }    else {

⌨️ 快捷键说明

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