📄 perchild.c
字号:
else {
thread_socket_table[thread_num] = AP_PERCHILD_THISCHILD;
}
requests_this_child--;
}
else {
if ((rv = SAFE_ACCEPT(apr_proc_mutex_unlock(process_accept_mutex)))
!= APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
"apr_proc_mutex_unlock failed. Attempting to shutdown "
"process gracefully.");
workers_may_exit = 1;
}
apr_thread_mutex_unlock(thread_accept_mutex);
apr_thread_mutex_lock(idle_thread_count_mutex);
idle_thread_count--;
apr_thread_mutex_unlock(idle_thread_count_mutex);
break;
}
apr_pool_clear(ptrans);
}
apr_thread_mutex_lock(thread_pool_parent_mutex);
ap_update_child_status_from_indexes(child_num, thread_num, SERVER_DEAD,
(request_rec *) NULL);
apr_pool_destroy(tpool);
apr_thread_mutex_unlock(thread_pool_parent_mutex);
apr_thread_mutex_lock(worker_thread_count_mutex);
worker_thread_count--;
worker_thread_free_ids[worker_thread_count] = thread_num;
if (worker_thread_count == 0) {
/* All the threads have exited, now finish the shutdown process
* by signalling the sigwait thread */
kill(my_pid, SIGTERM);
}
apr_thread_mutex_unlock(worker_thread_count_mutex);
apr_bucket_alloc_destroy(bucket_alloc);
return NULL;
}
/* Set group privileges.
*
* Note that we use the username as set in the config files, rather than
* the lookup of to uid --- the same uid may have multiple passwd entries,
* with different sets of groups for each.
*/
static int set_group_privs(uid_t uid, gid_t gid)
{
if (!geteuid()) {
const char *name;
/* Get username if passed as a uid */
struct passwd *ent;
if ((ent = getpwuid(uid)) == NULL) {
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
"getpwuid: couldn't determine user name from uid %u, "
"you probably need to modify the User directive",
(unsigned)uid);
return -1;
}
name = ent->pw_name;
/*
* Set the GID before initgroups(), since on some platforms
* setgid() is known to zap the group list.
*/
if (setgid(gid) == -1) {
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
"setgid: unable to set group id to Group %u",
(unsigned)gid);
return -1;
}
/* Reset `groups' attributes. */
if (initgroups(name, gid) == -1) {
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
"initgroups: unable to set groups for User %s "
"and Group %u", name, (unsigned)gid);
return -1;
}
}
return 0;
}
static int perchild_setup_child(int childnum)
{
child_info_t *ug = &child_info_table[childnum];
if (ug->uid == -1 && ug->gid == -1) {
return unixd_setup_child();
}
if (set_group_privs(ug->uid, ug->gid)) {
return -1;
}
/* Only try to switch if we're running as root */
if (!geteuid()
&& (
#ifdef _OSD_POSIX
os_init_job_environment(server_conf, unixd_config.user_name,
one_process) != 0 ||
#endif
setuid(ug->uid) == -1)) {
ap_log_error(APLOG_MARK, APLOG_ALERT, errno, NULL,
"setuid: unable to change to uid: %ld",
(long) ug->uid);
return -1;
}
return 0;
}
static int check_signal(int signum)
{
switch (signum) {
case SIGTERM:
case SIGINT:
just_die(signum);
return 1;
}
return 0;
}
typedef struct perchild_header {
char *headers;
apr_pool_t *p;
} perchild_header;
/* Send a single HTTP header field to the client. Note that this function
* is used in calls to table_do(), so their interfaces are co-dependent.
* In other words, don't change this one without checking table_do in alloc.c.
* It returns true unless there was a write error of some kind.
*/
static int perchild_header_field(perchild_header *h,
const char *fieldname, const char *fieldval)
{
apr_pstrcat(h->p, h->headers, fieldname, ": ", fieldval, CRLF, NULL);
return 1;
}
static void child_main(int child_num_arg)
{
int i;
apr_status_t rv;
apr_socket_t *sock = NULL;
ap_listen_rec *lr;
my_pid = getpid();
ap_fatal_signal_child_setup(ap_server_conf);
child_num = child_num_arg;
apr_pool_create(&pchild, pconf);
for (lr = ap_listeners ; lr->next != NULL; lr = lr->next) {
continue;
}
apr_os_sock_put(&sock, &child_info_table[child_num].input, pconf);
lr->next = apr_palloc(pconf, sizeof(*lr));
lr->next->sd = sock;
lr->next->active = 1;
lr->next->accept_func = receive_from_other_child;
lr->next->next = NULL;
lr = lr->next;
num_listensocks++;
/*stuff to do before we switch id's, so we have permissions.*/
rv = SAFE_ACCEPT(apr_proc_mutex_child_init(&process_accept_mutex,
ap_lock_fname, pchild));
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_EMERG, rv, ap_server_conf,
"Couldn't initialize cross-process lock in child");
clean_child_exit(APEXIT_CHILDFATAL);
}
if (perchild_setup_child(child_num)) {
clean_child_exit(APEXIT_CHILDFATAL);
}
ap_run_child_init(pchild, ap_server_conf);
/*done with init critical section */
apr_setup_signal_thread();
requests_this_child = ap_max_requests_per_child;
/* Setup worker threads */
if (threads_to_start > max_threads) {
threads_to_start = max_threads;
}
idle_thread_count = threads_to_start;
worker_thread_count = 0;
worker_thread_free_ids = (int *)apr_pcalloc(pchild, thread_limit * sizeof(int));
for (i = 0; i < max_threads; i++) {
worker_thread_free_ids[i] = i;
}
apr_pool_create(&thread_pool_parent, pchild);
apr_thread_mutex_create(&thread_pool_parent_mutex,
APR_THREAD_MUTEX_DEFAULT, pchild);
apr_thread_mutex_create(&idle_thread_count_mutex,
APR_THREAD_MUTEX_DEFAULT, pchild);
apr_thread_mutex_create(&worker_thread_count_mutex,
APR_THREAD_MUTEX_DEFAULT, pchild);
apr_thread_mutex_create(&pipe_of_death_mutex,
APR_THREAD_MUTEX_DEFAULT, pchild);
apr_thread_mutex_create(&thread_accept_mutex,
APR_THREAD_MUTEX_DEFAULT, pchild);
apr_threadattr_create(&worker_thread_attr, pchild);
apr_threadattr_detach_set(worker_thread_attr, 1);
/* 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;
}
}
apr_signal_thread(check_signal);
}
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_from_indexes(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 HAVE_BINDPROCESSOR
/* By default, AIX binds to a single processor. This bit unbinds
* children which will then bind to another CPU.
*/
int status = bindprocessor(BINDPROCESS, (int)getpid(),
PROCESSOR_CLASS_ANY);
if (status != OK) {
ap_log_error(APLOG_MARK, 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);
clean_child_exit(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)
#endif
static 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_exit_why_e exitwhy;
int status;
apr_proc_t pid;
int i;
while (!restart_pending && !shutdown_pending) {
ap_wait_or_timeout(&exitwhy, &status, &pid, pconf);
if (pid.pid != -1) {
if (ap_process_child_status(&pid, exitwhy, status)
== APEXIT_CHILDFATAL) {
shutdown_pending = 1;
child_fatal = 1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -