View | Details | Raw Unified | Return to bug 48769
Collapse All | Expand All

(-)a/modules/fcgid/fcgid_bridge.c (-12 / +17 lines)
Lines 59-65 static fcgid_procnode *apply_free_procnode(request_rec *r, Link Here
59
        if (current_node->inode == inode
59
        if (current_node->inode == inode
60
            && current_node->deviceid == deviceid
60
            && current_node->deviceid == deviceid
61
            && !strcmp(current_node->cmdline, cmdline)
61
            && !strcmp(current_node->cmdline, cmdline)
62
            && current_node->virtualhost == virtualhost
62
            && !strcmp(current_node->virtualhost, virtualhost)
63
            && current_node->uid == uid && current_node->gid == gid) {
63
            && current_node->uid == uid && current_node->gid == gid) {
64
            /* Unlink from idle list */
64
            /* Unlink from idle list */
65
            previous_node->next_index = current_node->next_index;
65
            previous_node->next_index = current_node->next_index;
Lines 109-124 return_procnode(request_rec *r, Link Here
109
        current_node = next_node;
109
        current_node = next_node;
110
    }
110
    }
111
111
112
    /* Return to error list or idle list */
112
    if (current_node == procnode) {
113
    if (communicate_error) {
113
        /* If we removed it from the busy list, the process must be returned to the idle or error list */
114
        /* Link to error list */
114
        if (communicate_error) {
115
        procnode->next_index = error_list_header->next_index;
115
            /* Link to error list */
116
        error_list_header->next_index = procnode - proc_table;
116
            procnode->next_index = error_list_header->next_index;
117
    }
117
            error_list_header->next_index = procnode - proc_table;
118
    else {
118
        }
119
        /* Link to idle list */
119
        else {
120
        procnode->next_index = idle_list_header->next_index;
120
            /* Link to idle list */
121
        idle_list_header->next_index = procnode - proc_table;
121
            procnode->next_index = idle_list_header->next_index;
122
            idle_list_header->next_index = procnode - proc_table;
123
        }
122
    }
124
    }
123
125
124
    proctable_unlock(r);
126
    proctable_unlock(r);
Lines 139-145 static int count_busy_processes(request_rec *r, fcgid_command *command) Link Here
139
        if (current_node->inode == command->inode
141
        if (current_node->inode == command->inode
140
            && current_node->deviceid == command->deviceid
142
            && current_node->deviceid == command->deviceid
141
            && !strcmp(current_node->cmdline, command->cmdline)
143
            && !strcmp(current_node->cmdline, command->cmdline)
142
            && current_node->virtualhost == command->virtualhost
144
            && !strcmp(current_node->virtualhost,command->virtualhost)
143
            && current_node->uid == command->uid
145
            && current_node->uid == command->uid
144
            && current_node->gid == command->gid) {
146
            && current_node->gid == command->gid) {
145
            result++;
147
            result++;
Lines 191-196 apr_status_t bucket_ctx_cleanup(void *thectx) Link Here
191
                          ctx->procnode->cmdopts.busy_timeout);
193
                          ctx->procnode->cmdopts.busy_timeout);
192
            return_procnode(r, ctx->procnode, 1 /* busy timeout */ );
194
            return_procnode(r, ctx->procnode, 1 /* busy timeout */ );
193
        }
195
        }
196
        else if (ctx->procnode->diewhy == FCGID_DIE_SHUTDOWN) {
197
            return_procnode(r, ctx->procnode, 1 /* child from previous generation */ );
198
        }
194
        else if (ctx->has_error) {
199
        else if (ctx->has_error) {
195
            ctx->procnode->diewhy = FCGID_DIE_COMM_ERROR;
200
            ctx->procnode->diewhy = FCGID_DIE_COMM_ERROR;
196
            return_procnode(r, ctx->procnode, 1 /* communication error */ );
201
            return_procnode(r, ctx->procnode, 1 /* communication error */ );
(-)a/modules/fcgid/fcgid_mutex.h (-1 / +1 lines)
Lines 21-25 apr_status_t fcgid_mutex_register(const char *mutex_type, Link Here
21
apr_status_t fcgid_mutex_create(apr_global_mutex_t **mutex,
21
apr_status_t fcgid_mutex_create(apr_global_mutex_t **mutex,
22
                                const char **lockfile,
22
                                const char **lockfile,
23
                                const char *mutex_type,
23
                                const char *mutex_type,
24
                                apr_pool_t *pconf,
24
                                apr_pool_t *pool,
25
                                server_rec *s);
25
                                server_rec *s);
(-)a/modules/fcgid/fcgid_mutex_unix.c (-5 / +10 lines)
Lines 36-49 apr_status_t fcgid_mutex_register(const char *mutex_type, Link Here
36
apr_status_t fcgid_mutex_create(apr_global_mutex_t **mutex,
36
apr_status_t fcgid_mutex_create(apr_global_mutex_t **mutex,
37
                                const char **lockfile,
37
                                const char **lockfile,
38
                                const char *mutex_type,
38
                                const char *mutex_type,
39
                                apr_pool_t *pconf,
39
                                apr_pool_t *pool,
40
                                server_rec *main_server)
40
                                server_rec *main_server)
41
{
41
{
42
    apr_status_t rv;
42
    apr_status_t rv;
43
43
44
    *lockfile = NULL;
44
    *lockfile = NULL;
45
    rv = ap_global_mutex_create(mutex, mutex_type, NULL, main_server,
45
    rv = ap_global_mutex_create(mutex, mutex_type, NULL, main_server,
46
                                pconf, 0);
46
                                pool, 0);
47
    if (rv != APR_SUCCESS) {
47
    if (rv != APR_SUCCESS) {
48
        return rv;
48
        return rv;
49
    }
49
    }
Lines 105-111 static apr_lockmech_e pick_mutex_mechanism(void) Link Here
105
apr_status_t fcgid_mutex_create(apr_global_mutex_t **mutex,
105
apr_status_t fcgid_mutex_create(apr_global_mutex_t **mutex,
106
                                const char **lockfilep,
106
                                const char **lockfilep,
107
                                const char *mutex_type,
107
                                const char *mutex_type,
108
                                apr_pool_t *pconf,
108
                                apr_pool_t *pool,
109
                                server_rec *s)
109
                                server_rec *s)
110
{
110
{
111
    apr_status_t rv;
111
    apr_status_t rv;
Lines 116-124 apr_status_t fcgid_mutex_create(apr_global_mutex_t **mutex, Link Here
116
     * to a better place would require a directive to override it.  This
116
     * to a better place would require a directive to override it.  This
117
     * is resolved for httpd 2.3+ by hooking into the Mutex support.
117
     * is resolved for httpd 2.3+ by hooking into the Mutex support.
118
     */
118
     */
119
    lockfile = apr_palloc(pconf, L_tmpnam);
119
    if (*lockfilep == NULL) {
120
        lockfile = apr_palloc(pool, L_tmpnam);
121
    }
122
    else {
123
        lockfile = *lockfilep;
124
    }
120
    tmpnam(lockfile);
125
    tmpnam(lockfile);
121
    rv = apr_global_mutex_create(mutex, lockfile, mechanism, pconf);
126
    rv = apr_global_mutex_create(mutex, lockfile, mechanism, pool);
122
    if (rv != APR_SUCCESS) {
127
    if (rv != APR_SUCCESS) {
123
        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
128
        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
124
                     "mod_fcgid: Can't create global %s mutex", mutex_type);
129
                     "mod_fcgid: Can't create global %s mutex", mutex_type);
(-)a/modules/fcgid/fcgid_pm.h (-1 / +4 lines)
Lines 20-31 Link Here
20
#include "fcgid_global.h"
20
#include "fcgid_global.h"
21
#include "fcgid_conf.h"
21
#include "fcgid_conf.h"
22
22
23
#define FCGID_PM_MAX_SHUTDOWN_WAIT_ATTEMPTS 30
24
23
typedef struct {
25
typedef struct {
24
    char cgipath[_POSIX_PATH_MAX];
26
    char cgipath[_POSIX_PATH_MAX];
25
    char cmdline[_POSIX_PATH_MAX];
27
    char cmdline[_POSIX_PATH_MAX];
26
    apr_ino_t inode;
28
    apr_ino_t inode;
27
    dev_t deviceid;
29
    dev_t deviceid;
28
    const char *virtualhost;  /* Virtualhost granularity */
30
    char virtualhost[_POSIX_PATH_MAX];  /* Virtualhost granularity */
29
    uid_t uid;                  /* For suEXEC */
31
    uid_t uid;                  /* For suEXEC */
30
    gid_t gid;                  /* For suEXEC */
32
    gid_t gid;                  /* For suEXEC */
31
    int userdir;                /* For suEXEC */
33
    int userdir;                /* For suEXEC */
Lines 52-56 apr_status_t procmgr_post_config(server_rec * main_server, Link Here
52
54
53
apr_status_t procmgr_stop_procmgr(void *dummy);
55
apr_status_t procmgr_stop_procmgr(void *dummy);
54
int procmgr_must_exit(void);
56
int procmgr_must_exit(void);
57
int procmgr_graceful_restart(void);
55
58
56
#endif
59
#endif
(-)a/modules/fcgid/fcgid_pm_main.c (-38 / +86 lines)
Lines 352-400 static void scan_errorlist(server_rec * main_server) Link Here
352
    proctable_pm_unlock(main_server);
352
    proctable_pm_unlock(main_server);
353
}
353
}
354
354
355
static void kill_all_subprocess(server_rec * main_server)
355
static void kill_all_subprocess(server_rec * main_server, int graceful)
356
{
356
{
357
    size_t i;
357
    int wait_attempts = 0;
358
    int exitcode;
359
    apr_exit_why_e exitwhy;
360
    fcgid_procnode *proc_table = proctable_get_table_array();
358
    fcgid_procnode *proc_table = proctable_get_table_array();
359
    fcgid_procnode *free_list_header = proctable_get_free_list();
360
    fcgid_procnode *busy_list_header = proctable_get_busy_list();
361
    fcgid_procnode *idle_list_header = proctable_get_idle_list();
362
    fcgid_procnode *error_list_header = proctable_get_error_list();
363
    fcgid_procnode *previous_node, *current_node, *next_node;
364
    
361
365
362
    /* Kill gracefully */
366
    /* We'll scan the idle and busy lists signaling each process to shut down
363
    for (i = 0; i < proctable_get_table_size(); i++) {
367
       The processes in the idle list will be moved to the error list
364
        if (proc_table[i].proc_pool)
368
       Processes in the busy list will be moved to the error list only during a hard shutdown/restart.
365
            proc_kill_gracefully(&proc_table[i], main_server);
369
       After we've moved everything to the error list that needs to die, we walk it until everything is cleaned up */
366
    }
370
    
367
    apr_sleep(apr_time_from_sec(1));
371
    proctable_pm_lock(main_server);
368
372
369
    /* Kill with SIGKILL if it doesn't work */
373
    /* signal all processes in the error list once */
370
    for (i = 0; i < proctable_get_table_size(); i++) {
374
    previous_node = error_list_header;
371
        if (proc_table[i].proc_pool) {
375
    current_node = &proc_table[previous_node->next_index];
372
            if (apr_proc_wait(&(proc_table[i].proc_id), &exitcode, &exitwhy,
376
    while (current_node != proc_table) {
373
                              APR_NOWAIT) != APR_CHILD_NOTDONE) {
377
        proc_kill_gracefully(current_node, main_server);               
374
                proc_table[i].diewhy = FCGID_DIE_SHUTDOWN;
378
        previous_node = current_node;
375
                proc_print_exit_info(&proc_table[i], exitcode, exitwhy,
379
        current_node = &proc_table[current_node->next_index];
376
                                     main_server);
380
    }
377
                apr_pool_destroy(proc_table[i].proc_pool);
381
378
                proc_table[i].proc_pool = NULL;
382
    /* Previous node is going to be the tail end of the error list.  Attach all the idle list to it and signal those processes to exit */
379
            }
383
    current_node = &proc_table[idle_list_header->next_index];
380
            else
384
    if (current_node != proc_table) {
381
                proc_kill_force(&proc_table[i], main_server);
385
        previous_node->next_index = (current_node - proc_table);
386
        idle_list_header->next_index = 0;
387
        while ( current_node != proc_table ) {
388
            proc_kill_gracefully( current_node, main_server );
389
            current_node->diewhy = FCGID_DIE_SHUTDOWN;
390
            previous_node = current_node;
391
            current_node     = &proc_table[ current_node->next_index ];
382
        }
392
        }
383
    }
393
    }
384
394
385
    /* Wait again */
395
    /* If this is a forced shutdown, link the busy list to the error list */
386
    for (i = 0; i < proctable_get_table_size(); i++) {
396
    current_node = &proc_table[busy_list_header->next_index];
387
        if (proc_table[i].proc_pool) {
397
    if (!graceful && current_node != proc_table) {
388
            if (apr_proc_wait(&(proc_table[i].proc_id), &exitcode, &exitwhy,
398
        previous_node->next_index = (current_node - proc_table);
389
                              APR_WAIT) != APR_CHILD_NOTDONE) {
399
        busy_list_header->next_index = 0;
390
                proc_table[i].diewhy = FCGID_DIE_SHUTDOWN;
400
    }
391
                proc_print_exit_info(&proc_table[i], exitcode, exitwhy,
401
        
392
                                     main_server);
402
    /* Signal processes in the busy list */
393
                apr_pool_destroy(proc_table[i].proc_pool);
403
    while (current_node != proc_table) {
394
                proc_table[i].proc_pool = NULL;
404
        proc_kill_gracefully( current_node, main_server );
405
        current_node->diewhy = FCGID_DIE_SHUTDOWN;
406
        current_node     = &proc_table[ current_node->next_index ];
407
    }
408
409
    /* Now clear the error list into the free list...
410
       We are blocking all the bridged processes from completing during this timeframe
411
       since they can't aquire the mutex to check the process tables.  This should be
412
       acceptable for both graceful and hard restarts.  This loop should end rapidly
413
       with graceful restarts and connection interruptions are going to happen regardless
414
       with hard restarts. */
415
    while (error_list_header->next_index != 0) {
416
        apr_sleep(apr_time_from_sec(1));
417
        wait_attempts++;
418
        previous_node = error_list_header;
419
        current_node = &proc_table[previous_node->next_index];
420
        while (current_node != proc_table) {
421
            next_node = &proc_table[current_node->next_index];
422
            if (proc_wait_process(main_server, current_node) == APR_CHILD_NOTDONE
423
                && wait_attempts < FCGID_PM_MAX_SHUTDOWN_WAIT_ATTEMPTS ) {
424
                /* kill it hard and check again in 1 second */
425
                proc_kill_force( current_node, main_server );
426
                previous_node = current_node;
395
            }
427
            }
428
            else {
429
                /* Unlink from error list */
430
                previous_node->next_index = current_node->next_index;
431
432
                /* Link to free list */
433
                current_node->next_index = free_list_header->next_index;
434
                free_list_header->next_index = current_node - proc_table;
435
            }
436
            current_node = next_node;
396
        }
437
        }
397
    }
438
    }
439
440
    /* At this point in a graceful restart, the busy and free lists have all the process nodes */
441
    /* In a forced restart, all nodes are in the free list */
442
    
443
    proctable_pm_unlock(main_server);
398
}
444
}
399
445
400
/* This should be proposed as a stand-alone improvement to the httpd module,
446
/* This should be proposed as a stand-alone improvement to the httpd module,
Lines 482-488 fastcgi_spawn(fcgid_command * command, server_rec * main_server, Link Here
482
    if (free_list_header->next_index == 0) {
528
    if (free_list_header->next_index == 0) {
483
        proctable_pm_unlock(main_server);
529
        proctable_pm_unlock(main_server);
484
        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, main_server,
530
        ap_log_error(APLOG_MARK, APLOG_WARNING, 0, main_server,
485
                     "mod_fcgid: too much processes, please increase FCGID_MAX_APPLICATION");
531
                     "mod_fcgid: too many processes, please increase FCGID_MAX_APPLICATION");
486
        return;
532
        return;
487
    }
533
    }
488
    procnode = &proctable_array[free_list_header->next_index];
534
    procnode = &proctable_array[free_list_header->next_index];
Lines 494-500 fastcgi_spawn(fcgid_command * command, server_rec * main_server, Link Here
494
    procnode->deviceid = command->deviceid;
540
    procnode->deviceid = command->deviceid;
495
    procnode->inode = command->inode;
541
    procnode->inode = command->inode;
496
    apr_cpystrn(procnode->cmdline, command->cmdline, _POSIX_PATH_MAX);
542
    apr_cpystrn(procnode->cmdline, command->cmdline, _POSIX_PATH_MAX);
497
    procnode->virtualhost = command->virtualhost;
543
    apr_cpystrn(procnode->virtualhost, command->virtualhost, _POSIX_PATH_MAX);
498
    procnode->uid = command->uid;
544
    procnode->uid = command->uid;
499
    procnode->gid = command->gid;
545
    procnode->gid = command->gid;
500
    procnode->start_time = procnode->last_active_time = apr_time_now();
546
    procnode->start_time = procnode->last_active_time = apr_time_now();
Lines 510-516 fastcgi_spawn(fcgid_command * command, server_rec * main_server, Link Here
510
    procinfo.gid = command->gid;
556
    procinfo.gid = command->gid;
511
    procinfo.userdir = command->userdir;
557
    procinfo.userdir = command->userdir;
512
    if ((rv =
558
    if ((rv =
513
         apr_pool_create(&procnode->proc_pool, configpool)) != APR_SUCCESS
559
         apr_pool_create(&procnode->proc_pool, main_server->process->pool)) != APR_SUCCESS
514
        || (procinfo.proc_environ =
560
        || (procinfo.proc_environ =
515
            apr_table_make(procnode->proc_pool, INITENV_CNT)) == NULL) {
561
            apr_table_make(procnode->proc_pool, INITENV_CNT)) == NULL) {
516
        /* Link the node back to free list in this case */
562
        /* Link the node back to free list in this case */
Lines 523-528 fastcgi_spawn(fcgid_command * command, server_rec * main_server, Link Here
523
                     "mod_fcgid: can't create pool for process");
569
                     "mod_fcgid: can't create pool for process");
524
        return;
570
        return;
525
    }
571
    }
572
    
526
    /* Set up longer, system defaults before falling into parsing fixed-limit
573
    /* Set up longer, system defaults before falling into parsing fixed-limit
527
     * request-by-request variables, so if any are overriden, they preempt
574
     * request-by-request variables, so if any are overriden, they preempt
528
     * any system default assumptions
575
     * any system default assumptions
Lines 563-568 fastcgi_spawn(fcgid_command * command, server_rec * main_server, Link Here
563
apr_status_t pm_main(server_rec * main_server, apr_pool_t * configpool)
610
apr_status_t pm_main(server_rec * main_server, apr_pool_t * configpool)
564
{
611
{
565
    fcgid_command command;
612
    fcgid_command command;
613
    apr_status_t rv;
566
614
567
    while (1) {
615
    while (1) {
568
        if (procmgr_must_exit())
616
        if (procmgr_must_exit())
Lines 586-592 apr_status_t pm_main(server_rec * main_server, apr_pool_t * configpool) Link Here
586
    }
634
    }
587
635
588
    /* Stop all processes */
636
    /* Stop all processes */
589
    kill_all_subprocess(main_server);
637
    kill_all_subprocess(main_server, procmgr_graceful_restart());
590
638
591
    return APR_SUCCESS;
639
    return APR_SUCCESS;
592
}
640
}
(-)a/modules/fcgid/fcgid_pm_unix.c (-20 / +66 lines)
Lines 63-68 static const char *g_pipelock_name; Link Here
63
static const char *g_pipelock_mutex_type = "fcgid-pipe";
63
static const char *g_pipelock_mutex_type = "fcgid-pipe";
64
64
65
static int volatile g_caughtSigTerm = 0;
65
static int volatile g_caughtSigTerm = 0;
66
static int volatile g_caughtSigUsr1 = 0;
66
static pid_t g_pm_pid;
67
static pid_t g_pm_pid;
67
static void signal_handler(int signo)
68
static void signal_handler(int signo)
68
{
69
{
Lines 73-83 static void signal_handler(int signo) Link Here
73
        return;
74
        return;
74
    }
75
    }
75
76
76
    if ((signo == SIGTERM) || (signo == SIGUSR1) || (signo == SIGHUP)) {
77
    if ((signo == SIGTERM) || (signo == SIGHUP)) {
77
        g_caughtSigTerm = 1;
78
        g_caughtSigTerm = 1;
79
        g_caughtSigUsr1 = 0;
78
        /* Tell the world it's time to die */
80
        /* Tell the world it's time to die */
79
        proctable_get_globalshare()->must_exit = 1;
81
        proctable_get_globalshare()->must_exit = 1;
80
    }
82
    }
83
    if (signo == SIGUSR1 && !g_caughtSigTerm) {
84
        g_caughtSigUsr1 = 1;
85
        proctable_get_globalshare()->must_exit = 1;
86
    }
81
}
87
}
82
88
83
static apr_status_t init_signal(server_rec * main_server)
89
static apr_status_t init_signal(server_rec * main_server)
Lines 161-166 static void fcgid_maint(int reason, void *data, apr_wait_t status) Link Here
161
        }
167
        }
162
        break;
168
        break;
163
    case APR_OC_REASON_RESTART:
169
    case APR_OC_REASON_RESTART:
170
        kill(proc->pid, SIGTERM);
164
        apr_proc_other_child_unregister(data);
171
        apr_proc_other_child_unregister(data);
165
        break;
172
        break;
166
    case APR_OC_REASON_LOST:
173
    case APR_OC_REASON_LOST:
Lines 178-184 static void fcgid_maint(int reason, void *data, apr_wait_t status) Link Here
178
        break;
185
        break;
179
    case APR_OC_REASON_UNREGISTER:
186
    case APR_OC_REASON_UNREGISTER:
180
        /* I don't think it's going to happen */
187
        /* I don't think it's going to happen */
181
        kill(proc->pid, SIGHUP);
188
        kill(proc->pid, SIGUSR1);
182
        break;
189
        break;
183
    }
190
    }
184
}
191
}
Lines 313-319 create_process_manager(server_rec * main_server, apr_pool_t * configpool) Link Here
313
    /* I am the parent
320
    /* I am the parent
314
       I will send the stop signal in procmgr_stop_procmgr() */
321
       I will send the stop signal in procmgr_stop_procmgr() */
315
    apr_pool_note_subprocess(configpool, g_process_manager,
322
    apr_pool_note_subprocess(configpool, g_process_manager,
316
                             APR_KILL_ONLY_ONCE);
323
                             APR_JUST_WAIT);
317
    apr_proc_other_child_register(g_process_manager, fcgid_maint,
324
    apr_proc_other_child_register(g_process_manager, fcgid_maint,
318
                                  g_process_manager, NULL, configpool);
325
                                  g_process_manager, NULL, configpool);
319
326
Lines 327-333 procmgr_child_init(server_rec * main_server, apr_pool_t * configpool) Link Here
327
334
328
    if ((rv = apr_global_mutex_child_init(&g_pipelock,
335
    if ((rv = apr_global_mutex_child_init(&g_pipelock,
329
                                          g_pipelock_name,
336
                                          g_pipelock_name,
330
                                          main_server->process->pconf)) !=
337
                                          main_server->process->pool)) !=
331
        APR_SUCCESS) {
338
        APR_SUCCESS) {
332
        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server,
339
        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server,
333
                     "mod_fcgid: apr_global_mutex_child_init error for pipe mutex");
340
                     "mod_fcgid: apr_global_mutex_child_init error for pipe mutex");
Lines 346-353 apr_status_t procmgr_pre_config(apr_pool_t *p, apr_pool_t *plog, Link Here
346
apr_status_t
353
apr_status_t
347
procmgr_post_config(server_rec * main_server, apr_pool_t * configpool)
354
procmgr_post_config(server_rec * main_server, apr_pool_t * configpool)
348
{
355
{
356
    const char *userdata_mutex_key = "fcgid_procmgr_mutex";
357
    const char *userdata_filename_key = "fcgid_procmgr_mutex_file";
358
    const char *userdata_pipe_key[] = { "fcgid_pipe_pm_read", "fcgid_pipe_pm_write", "fcgid_pipe_ap_read", "fcgid_pipe_ap_write" };
359
    apr_file_t **userdata_pipe_handle[] = { &g_pm_read_pipe, &g_pm_write_pipe, &g_ap_read_pipe, &g_ap_write_pipe };
349
    apr_status_t rv;
360
    apr_status_t rv;
350
    apr_finfo_t finfo;
361
    apr_finfo_t finfo;
362
    size_t i;
363
    size_t j;
351
    fcgid_server_conf *sconf = ap_get_module_config(main_server->module_config,
364
    fcgid_server_conf *sconf = ap_get_module_config(main_server->module_config,
352
                                                    &fcgid_module);
365
                                                    &fcgid_module);
353
366
Lines 395-416 procmgr_post_config(server_rec * main_server, apr_pool_t * configpool) Link Here
395
        }
408
        }
396
    }
409
    }
397
410
398
    /* Create pipes to communicate between process manager and apache */
411
    /* Create pipes to communicate between process manager and apache
399
    if ((rv = apr_file_pipe_create(&g_pm_read_pipe, &g_ap_write_pipe,
412
       The pipes will last across restarts */
400
                                   configpool)) != APR_SUCCESS
413
    for (i = 0; i < 4; i++) {
401
        || (rv = apr_file_pipe_create(&g_ap_read_pipe, &g_pm_write_pipe,
414
        apr_pool_userdata_get((void *) userdata_pipe_handle[i], userdata_pipe_key[i],
402
                                      configpool))) {
415
                              main_server->process->pool);
403
        ap_log_error(APLOG_MARK, APLOG_ERR, rv, main_server,
416
        if (*userdata_pipe_handle[i] == NULL) {
404
                     "mod_fcgid: Can't create pipe between PM and stub");
417
            if ((rv = apr_file_pipe_create(&g_pm_read_pipe, &g_ap_write_pipe,
405
        return rv;
418
                                           main_server->process->pool)) != APR_SUCCESS
419
                || (rv = apr_file_pipe_create(&g_ap_read_pipe, &g_pm_write_pipe,
420
                                              main_server->process->pool))) {
421
                ap_log_error(APLOG_MARK, APLOG_ERR, rv, main_server,
422
                             "mod_fcgid: Can't create pipe between PM and stub");
423
                return rv;
424
            }
425
            for (j = 0; j < 4; j++) {
426
                apr_pool_userdata_set(*(userdata_pipe_handle[j]), userdata_pipe_key[j],
427
                                      apr_pool_cleanup_null,
428
                                      main_server->process->pool);
429
            }
430
            break;
431
        }
406
    }
432
    }
407
433
408
    /* Create mutex for pipe reading and writing */
434
    /* Create mutex for pipe reading and writing
409
    rv = fcgid_mutex_create(&g_pipelock, &g_pipelock_name,
435
       All mutexex are going to persist across restarts */
410
                            g_pipelock_mutex_type,
436
    g_pipelock = NULL;
411
                            main_server->process->pconf, main_server);
437
    g_pipelock_name = NULL;
412
    if (rv != APR_SUCCESS) {
438
    apr_pool_userdata_get((void *) &g_pipelock, userdata_mutex_key,
413
        exit(1);
439
                         main_server->process->pool);
440
    apr_pool_userdata_get((void *) &g_pipelock_name, userdata_filename_key,
441
                         main_server->process->pool);
442
    if (g_pipelock == NULL || g_pipelock_name == NULL) {
443
        rv = fcgid_mutex_create(&g_pipelock, &g_pipelock_name,
444
                                g_pipelock_mutex_type,
445
                                main_server->process->pool, main_server);
446
        if (rv != APR_SUCCESS) {
447
            exit(1);
448
        }
449
        apr_pool_userdata_set(g_pipelock, userdata_mutex_key,
450
                              apr_pool_cleanup_null,
451
                              main_server->process->pool);
452
        apr_pool_userdata_set(g_pipelock_name, userdata_filename_key,
453
                              apr_pool_cleanup_null,
454
                              main_server->process->pool);
414
    }
455
    }
415
456
416
    /* Create process manager process */
457
    /* Create process manager process */
Lines 437-445 void procmgr_init_spawn_cmd(fcgid_command * command, request_rec * r, Link Here
437
478
438
    apr_cpystrn(command->cgipath, cmd_conf->cgipath, _POSIX_PATH_MAX);
479
    apr_cpystrn(command->cgipath, cmd_conf->cgipath, _POSIX_PATH_MAX);
439
    apr_cpystrn(command->cmdline, cmd_conf->cmdline, _POSIX_PATH_MAX);
480
    apr_cpystrn(command->cmdline, cmd_conf->cmdline, _POSIX_PATH_MAX);
481
    apr_cpystrn(command->virtualhost, r->server->server_hostname, _POSIX_PATH_MAX);
440
    command->deviceid = cmd_conf->deviceid;
482
    command->deviceid = cmd_conf->deviceid;
441
    command->inode = cmd_conf->inode;
483
    command->inode = cmd_conf->inode;
442
    command->virtualhost = r->server->server_hostname;
443
484
444
    get_cmd_options(r, command->cgipath, &command->cmdopts, &command->cmdenv);
485
    get_cmd_options(r, command->cgipath, &command->cmdopts, &command->cmdenv);
445
}
486
}
Lines 535-541 apr_status_t procmgr_peek_cmd(fcgid_command * command, Link Here
535
576
536
int procmgr_must_exit()
577
int procmgr_must_exit()
537
{
578
{
538
    return g_caughtSigTerm;
579
    return g_caughtSigTerm || g_caughtSigUsr1;
580
}
581
582
int procmgr_graceful_restart()
583
{
584
    return g_caughtSigUsr1;
539
}
585
}
540
586
541
apr_status_t procmgr_stop_procmgr(void *server)
587
apr_status_t procmgr_stop_procmgr(void *server)
(-)a/modules/fcgid/fcgid_proctbl.h (-1 / +3 lines)
Lines 49-55 typedef struct { Link Here
49
    char cmdline[_POSIX_PATH_MAX]; /* entire command line */
49
    char cmdline[_POSIX_PATH_MAX]; /* entire command line */
50
    gid_t gid;                  /* for suEXEC */
50
    gid_t gid;                  /* for suEXEC */
51
    uid_t uid;                  /* for suEXEC */
51
    uid_t uid;                  /* for suEXEC */
52
    const char *virtualhost;      /* the virtualhost this process belongs to */
52
    char virtualhost[_POSIX_PATH_MAX]; /* the virtualhost this process belongs to */
53
    apr_time_t start_time;      /* the time of this process create */
53
    apr_time_t start_time;      /* the time of this process create */
54
    apr_time_t last_active_time;    /* the time this process last active */
54
    apr_time_t last_active_time;    /* the time this process last active */
55
    int requests_handled;       /* number of requests process has handled */
55
    int requests_handled;       /* number of requests process has handled */
Lines 94-99 void proctable_pm_lock(server_rec *s); Link Here
94
void proctable_pm_unlock(server_rec *s);
94
void proctable_pm_unlock(server_rec *s);
95
void proctable_lock(request_rec *r);
95
void proctable_lock(request_rec *r);
96
void proctable_unlock(request_rec *r);
96
void proctable_unlock(request_rec *r);
97
apr_status_t proctable_lock_safe(void);
98
apr_status_t proctable_unlock_safe(void);
97
99
98
/* Just for debug */
100
/* Just for debug */
99
void proctable_print_debug_info(server_rec * main_server);
101
void proctable_print_debug_info(server_rec * main_server);
(-)a/modules/fcgid/fcgid_proctbl_unix.c (-31 / +83 lines)
Lines 129-164 apr_status_t proctable_pre_config(apr_pool_t *p, apr_pool_t *plog, Link Here
129
apr_status_t
129
apr_status_t
130
proctable_post_config(server_rec * main_server, apr_pool_t * configpool)
130
proctable_post_config(server_rec * main_server, apr_pool_t * configpool)
131
{
131
{
132
    const char *userdata_mutex_key = "fcgid_proctbl_mutex";
133
    const char *userdata_filename_key = "fcgid_proctbl_mutex_file";
132
    size_t shmem_size = sizeof(fcgid_share);
134
    size_t shmem_size = sizeof(fcgid_share);
133
    fcgid_procnode *ptmpnode = NULL;
135
    fcgid_procnode *ptmpnode = NULL;
134
    int i;
136
    int i;
137
    int reused_shm = 0;
135
    apr_status_t rv;
138
    apr_status_t rv;
136
    fcgid_server_conf *sconf = ap_get_module_config(main_server->module_config,
139
    fcgid_server_conf *sconf = ap_get_module_config(main_server->module_config,
137
                                                    &fcgid_module);
140
                                                    &fcgid_module);
138
141
139
    /* Remove share memory first */
142
    g_sharelock_name = NULL;
140
    apr_shm_remove(sconf->shmname_path, main_server->process->pconf);
143
    g_sharemem = NULL;
141
144
    g_sharelock = NULL;
142
    /* Create share memory */
145
143
    if ((rv = apr_shm_create(&g_sharemem, shmem_size, sconf->shmname_path,
146
    /* Check to see if we can reclaim the mutex first
144
                             main_server->process->pconf)) != APR_SUCCESS)
147
       All mutexes are going to persist across restarts */
145
    {
148
    apr_pool_userdata_get((void *) &g_sharelock, userdata_mutex_key,
146
        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server,
149
                          main_server->process->pool);
147
                     "mod_fcgid: Can't create shared memory for size %" APR_SIZE_T_FMT " bytes",
150
    apr_pool_userdata_get((void *) &g_sharelock_name, userdata_filename_key,
148
                     shmem_size);
151
                          main_server->process->pool);
149
        exit(1);
152
    if (g_sharelock == NULL || g_sharelock_name == NULL ) {
153
        rv = fcgid_mutex_create(&g_sharelock, &g_sharelock_name,
154
                                g_sharelock_mutex_type,
155
                                main_server->process->pool, main_server);
156
        if (rv != APR_SUCCESS) {
157
            exit(1);
158
        }
159
        apr_pool_userdata_set(g_sharelock, userdata_mutex_key,
160
                              apr_pool_cleanup_null,
161
                              main_server->process->pool);
162
        apr_pool_userdata_set(g_sharelock_name, userdata_filename_key,
163
                              apr_pool_cleanup_null,
164
                              main_server->process->pool);
165
        
166
        /* Since we couldn't use the old mutex we're going to assume
167
           the old shared memory is also invalid */
168
        apr_shm_remove(sconf->shmname_path, main_server->process->pool);
169
    }
170
    else {
171
        /* We reclaimed the old mutex so we'll try to also reclaim the old shared memory */
172
        if ((rv = apr_shm_attach(&g_sharemem, sconf->shmname_path, main_server->process->pool)) == APR_SUCCESS) {
173
            if ( apr_shm_size_get(g_sharemem) == shmem_size ) {
174
                /* TODO: Additional checks here that shm comes from the current server */
175
                _global_memory = apr_shm_baseaddr_get(g_sharemem);
176
                reused_shm = 1;
177
            }
178
            else {
179
                apr_shm_detach(g_sharemem);
180
            }
181
        }
182
        if (rv != APR_SUCCESS || g_sharemem == NULL) {
183
            /* Couldn't reuse the old shared memory, make sure the file is removed */
184
            apr_shm_remove(sconf->shmname_path, main_server->process->pool);
185
        }
150
    }
186
    }
151
    _global_memory = apr_shm_baseaddr_get(g_sharemem);
152
187
153
    /* Create global mutex */
188
    if (!reused_shm) {
154
    rv = fcgid_mutex_create(&g_sharelock, &g_sharelock_name,
189
        if ((rv = apr_shm_create(&g_sharemem, shmem_size, sconf->shmname_path,
155
                            g_sharelock_mutex_type,
190
                                 main_server->process->pool)) != APR_SUCCESS) {
156
                            main_server->process->pconf, main_server);
191
            ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server,
192
                         "mod_fcgid: Can't create shared memory for size %" APR_SIZE_T_FMT " bytes",
193
                         shmem_size);
194
            exit(1);
195
        }
196
        _global_memory = apr_shm_baseaddr_get(g_sharemem);
197
        memset(_global_memory, 0, shmem_size);
198
    }
199
    
200
    rv = proctable_lock_safe();
157
    if (rv != APR_SUCCESS) {
201
    if (rv != APR_SUCCESS) {
202
        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server,
203
                     "mod_fcgid: Can't lock process table for initialization");
158
        exit(1);
204
        exit(1);
159
    }
205
    }
160
206
        
161
    memset(_global_memory, 0, shmem_size);
162
    g_proc_array = _global_memory->procnode_array;
207
    g_proc_array = _global_memory->procnode_array;
163
    g_global_share = &_global_memory->global;
208
    g_global_share = &_global_memory->global;
164
209
Lines 169-179 proctable_post_config(server_rec * main_server, apr_pool_t * configpool) Link Here
169
    g_busy_list_header = g_idle_list_header + 1;
214
    g_busy_list_header = g_idle_list_header + 1;
170
    g_error_list_header = g_busy_list_header + 1;
215
    g_error_list_header = g_busy_list_header + 1;
171
    g_free_list_header = g_error_list_header + 1;
216
    g_free_list_header = g_error_list_header + 1;
172
    ptmpnode = g_free_list_header;
217
    if (!reused_shm) {
173
    for (i = 0; i < FCGID_MAX_APPLICATION; i++) {
218
        /* This initially adds all nodes to the free list */
174
        ptmpnode->next_index = ptmpnode - g_proc_array + 1;
219
        ptmpnode = g_free_list_header;
175
        ptmpnode++;
220
        for (i = 0; i < FCGID_MAX_APPLICATION; i++) {
221
            ptmpnode->next_index = ptmpnode - g_proc_array + 1;
222
            ptmpnode++;
223
        }
176
    }
224
    }
225
    proctable_unlock_safe();
226
177
227
178
    return APR_SUCCESS;
228
    return APR_SUCCESS;
179
}
229
}
Lines 185-191 proctable_child_init(server_rec * main_server, apr_pool_t * configpool) Link Here
185
235
186
    if ((rv = apr_global_mutex_child_init(&g_sharelock,
236
    if ((rv = apr_global_mutex_child_init(&g_sharelock,
187
                                          g_sharelock_name,
237
                                          g_sharelock_name,
188
                                          main_server->process->pconf)) !=
238
                                          main_server->process->pool)) !=
189
        APR_SUCCESS) {
239
        APR_SUCCESS) {
190
        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server,
240
        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, main_server,
191
                     "mod_fcgid: apr_global_mutex_child_init error");
241
                     "mod_fcgid: apr_global_mutex_child_init error");
Lines 200-210 static apr_status_t proctable_lock_internal(void) Link Here
200
    return apr_global_mutex_lock(g_sharelock);
250
    return apr_global_mutex_lock(g_sharelock);
201
}
251
}
202
252
253
apr_status_t proctable_lock_safe(void)
254
{
255
    return proctable_lock_internal();
256
}
257
203
static apr_status_t proctable_unlock_internal(void)
258
static apr_status_t proctable_unlock_internal(void)
204
{
259
{
205
    return apr_global_mutex_unlock(g_sharelock);
260
    return apr_global_mutex_unlock(g_sharelock);
206
}
261
}
207
262
263
apr_status_t proctable_unlock_safe(void)
264
{
265
    return proctable_unlock_internal();
266
}
267
208
fcgid_procnode *proctable_get_free_list(void)
268
fcgid_procnode *proctable_get_free_list(void)
209
{
269
{
210
    return g_free_list_header;
270
    return g_free_list_header;
Lines 272-285 void proctable_pm_lock(server_rec *s) Link Here
272
{
332
{
273
    apr_status_t rv;
333
    apr_status_t rv;
274
334
275
    if (g_global_share->must_exit) {
276
        ap_log_error(APLOG_MARK, APLOG_EMERG, 0, s,
277
                     "mod_fcgid: server is restarted, pid %" APR_PID_T_FMT
278
                     " must exit",
279
                     getpid());
280
        kill(getpid(), SIGTERM);
281
    }
282
283
    /* Lock error is a fatal error */
335
    /* Lock error is a fatal error */
284
    if ((rv = proctable_lock_internal()) != APR_SUCCESS) {
336
    if ((rv = proctable_lock_internal()) != APR_SUCCESS) {
285
        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
337
        ap_log_error(APLOG_MARK, APLOG_EMERG, rv, s,
(-)a/modules/fcgid/fcgid_spawn_ctl.c (-4 / +4 lines)
Lines 60-66 register_life_death(server_rec * main_server, Link Here
60
        if (current_node->inode == procnode->inode
60
        if (current_node->inode == procnode->inode
61
            && current_node->deviceid == procnode->deviceid
61
            && current_node->deviceid == procnode->deviceid
62
            && !strcmp(current_node->cmdline, procnode->cmdline)
62
            && !strcmp(current_node->cmdline, procnode->cmdline)
63
            && current_node->virtualhost == procnode->virtualhost
63
            && !strcmp(current_node->virtualhost, procnode->virtualhost)
64
            && current_node->uid == procnode->uid
64
            && current_node->uid == procnode->uid
65
            && current_node->gid == procnode->gid)
65
            && current_node->gid == procnode->gid)
66
            break;
66
            break;
Lines 96-102 register_life_death(server_rec * main_server, Link Here
96
        current_node->deviceid = procnode->deviceid;
96
        current_node->deviceid = procnode->deviceid;
97
        current_node->inode = procnode->inode;
97
        current_node->inode = procnode->inode;
98
        current_node->cmdline = apr_pstrdup(g_stat_pool, procnode->cmdline);
98
        current_node->cmdline = apr_pstrdup(g_stat_pool, procnode->cmdline);
99
        current_node->virtualhost = procnode->virtualhost;
99
        current_node->virtualhost = apr_pstrdup(g_stat_pool, procnode->virtualhost);
100
        current_node->uid = procnode->uid;
100
        current_node->uid = procnode->uid;
101
        current_node->gid = procnode->gid;
101
        current_node->gid = procnode->gid;
102
        current_node->last_stat_time = apr_time_now();
102
        current_node->last_stat_time = apr_time_now();
Lines 165-171 int is_spawn_allowed(server_rec * main_server, fcgid_command * command) Link Here
165
        if (current_node->inode == command->inode
165
        if (current_node->inode == command->inode
166
            && current_node->deviceid == command->deviceid
166
            && current_node->deviceid == command->deviceid
167
            && !strcmp(current_node->cmdline, command->cmdline)
167
            && !strcmp(current_node->cmdline, command->cmdline)
168
            && current_node->virtualhost == command->virtualhost
168
            && !strcmp(current_node->virtualhost, command->virtualhost)
169
            && current_node->uid == command->uid
169
            && current_node->uid == command->uid
170
            && current_node->gid == command->gid)
170
            && current_node->gid == command->gid)
171
            break;
171
            break;
Lines 229-235 int is_kill_allowed(server_rec * main_server, fcgid_procnode * procnode) Link Here
229
        if (current_node->inode == procnode->inode
229
        if (current_node->inode == procnode->inode
230
            && current_node->deviceid == procnode->deviceid
230
            && current_node->deviceid == procnode->deviceid
231
            && !strcmp(current_node->cmdline, procnode->cmdline)
231
            && !strcmp(current_node->cmdline, procnode->cmdline)
232
            && current_node->virtualhost == procnode->virtualhost
232
            && !strcmp(current_node->virtualhost, procnode->virtualhost)
233
            && current_node->uid == procnode->uid
233
            && current_node->uid == procnode->uid
234
            && current_node->gid == procnode->gid)
234
            && current_node->gid == procnode->gid)
235
            break;
235
            break;
(-)a/modules/fcgid/mod_fcgid.c (-6 / +7 lines)
Lines 254-261 static int fcgidsort(fcgid_procnode **e1, fcgid_procnode **e2) Link Here
254
    cmp = strcmp((*e1)->cmdline, (*e2)->cmdline);
254
    cmp = strcmp((*e1)->cmdline, (*e2)->cmdline);
255
    if (cmp != 0)
255
    if (cmp != 0)
256
        return cmp;
256
        return cmp;
257
    if ((*e1)->virtualhost != (*e2)->virtualhost)
257
    cmp = strcmp((*e1)->virtualhost, (*e2)->virtualhost);
258
        return (*e1)->virtualhost > (*e2)->virtualhost ? 1 : -1;
258
    if (cmp != 0)
259
        return cmp;
259
    if ((*e1)->diewhy != (*e2)->diewhy)
260
    if ((*e1)->diewhy != (*e2)->diewhy)
260
        return (*e1)->diewhy > (*e2)->diewhy ? 1 : -1;
261
        return (*e1)->diewhy > (*e2)->diewhy ? 1 : -1;
261
    if ((*e1)->node_type != (*e2)->node_type)
262
    if ((*e1)->node_type != (*e2)->node_type)
Lines 302-308 static int fcgid_status_hook(request_rec *r, int flags) Link Here
302
    uid_t last_uid = 0;
303
    uid_t last_uid = 0;
303
    const char *last_cmdline = "";
304
    const char *last_cmdline = "";
304
    apr_time_t now;
305
    apr_time_t now;
305
    const char *last_virtualhost = NULL;
306
    const char *last_virtualhost = "";
306
    const char *basename, *tmpbasename;
307
    const char *basename, *tmpbasename;
307
    fcgid_procnode *proc_table = proctable_get_table_array();
308
    fcgid_procnode *proc_table = proctable_get_table_array();
308
    fcgid_procnode *error_list_header = proctable_get_error_list();
309
    fcgid_procnode *error_list_header = proctable_get_error_list();
Lines 375-381 static int fcgid_status_hook(request_rec *r, int flags) Link Here
375
        if (current_node->inode != last_inode || current_node->deviceid != last_deviceid
376
        if (current_node->inode != last_inode || current_node->deviceid != last_deviceid
376
            || current_node->gid != last_gid || current_node->uid != last_uid
377
            || current_node->gid != last_gid || current_node->uid != last_uid
377
            || strcmp(current_node->cmdline, last_cmdline)
378
            || strcmp(current_node->cmdline, last_cmdline)
378
            || current_node->virtualhost != last_virtualhost) {
379
            || strcmp(current_node->virtualhost, last_virtualhost)) {
379
            if (index != 0)
380
            if (index != 0)
380
                 ap_rputs("</table>\n\n", r);
381
                 ap_rputs("</table>\n\n", r);
381
           
382
           
Lines 388-395 static int fcgid_status_hook(request_rec *r, int flags) Link Here
388
                basename++;
389
                basename++;
389
	    else
390
	    else
390
                basename = tmpbasename;
391
                basename = tmpbasename;
391
            ap_rprintf(r, "<hr />\n<b>Process: %s</b>&nbsp;&nbsp;(%s)<br />\n",
392
            ap_rprintf(r, "<hr />\n<b>VHost: %s</b><br/>\n<b>Process: %s</b>&nbsp;&nbsp;(%s)<br />\n",
392
                       basename, current_node->cmdline);
393
                       current_node->virtualhost, basename, current_node->cmdline);
393
394
394
            /* Create a new table for this process info */
395
            /* Create a new table for this process info */
395
            ap_rputs("\n\n<table border=\"0\"><tr>"
396
            ap_rputs("\n\n<table border=\"0\"><tr>"

Return to bug 48769