Skip to content

Commit d5cf0ab

Browse files
author
Ben Mansell
committed
Make the FastCGI module behave nicer when trying to shut it down. If you
kill the parent process, then it will kill all its kiddies for you. Also, now refuses to run as a CGI (since it doesn't work that way), and corrected a few debug messages.
1 parent 35c3102 commit d5cf0ab

File tree

1 file changed

+104
-26
lines changed

1 file changed

+104
-26
lines changed

sapi/fastcgi/fastcgi.c

Lines changed: 104 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,21 @@
4343
#include "fcgi_config.h"
4444
#include "fcgiapp.h"
4545
#include <stdio.h>
46+
#if HAVE_STDLIB_H
4647
#include <stdlib.h>
48+
#endif
49+
#if HAVE_UNISTD_H
4750
#include <unistd.h>
51+
#endif
4852
#include <sys/wait.h>
4953
#include <sys/stat.h>
5054

55+
#if HAVE_SYS_TYPES_H
56+
#include <sys/types.h>
57+
#endif
58+
#if HAVE_SIGNAL_H
59+
#include <signal.h>
60+
#endif
5161

5262
#define TLS_D
5363
#define TLS_DC
@@ -59,6 +69,7 @@
5969
FCGX_Stream *in, *out, *err;
6070
FCGX_ParamArray envp;
6171
char *path_info = NULL;
72+
struct sigaction act, old_term, old_quit, old_int;
6273

6374
/* Our original environment from when the FastCGI first started */
6475
char **orig_env;
@@ -71,6 +82,21 @@ char **cgi_env;
7182
*/
7283
char **merge_env;
7384

85+
/**
86+
* Number of child processes that will get created to service requests
87+
*/
88+
static int children = 8;
89+
90+
/**
91+
* Set to non-zero if we are the parent process
92+
*/
93+
static int parent = 1;
94+
95+
/**
96+
* Process group
97+
*/
98+
static pid_t pgroup;
99+
74100

75101
static int sapi_fastcgi_ub_write(const char *str, uint str_length)
76102
{
@@ -127,12 +153,12 @@ static void sapi_fastcgi_register_variables(zval *track_vars_array ELS_DC SLS_DC
127153
char *ptr = strchr( self, '?' );
128154

129155
/*
130-
* note that the environment will already have been set up
131-
* via fastcgi_module_main(), below.
132-
*
133-
* fastcgi_module_main() -> php_request_startup() ->
134-
* php_hash_environment() -> php_import_environment_variables()
135-
*/
156+
* note that the environment will already have been set up
157+
* via fastcgi_module_main(), below.
158+
*
159+
* fastcgi_module_main() -> php_request_startup() ->
160+
* php_hash_environment() -> php_import_environment_variables()
161+
*/
136162

137163
/* strip query string off this */
138164
if ( ptr ) *ptr = 0;
@@ -271,6 +297,24 @@ void fastcgi_php_shutdown(void)
271297
}
272298

273299

300+
/**
301+
* Clean up child processes upon exit
302+
*/
303+
void fastcgi_cleanup(int signal)
304+
{
305+
int i;
306+
307+
#ifdef DEBUG_FASTCGI
308+
fprintf( stderr, "FastCGI shutdown, pid %d\n", getpid() );
309+
#endif
310+
311+
sigaction( SIGTERM, &old_term, 0 );
312+
313+
/* Kill all the processes in our process group */
314+
kill( -pgroup, SIGTERM );
315+
}
316+
317+
274318
int main(int argc, char *argv[])
275319
{
276320
int exit_status = SUCCESS;
@@ -280,16 +324,21 @@ int main(int argc, char *argv[])
280324
char *argv0=NULL;
281325
char *script_file=NULL;
282326
zend_llist global_vars;
283-
int children = 8;
284327
int max_requests = 500;
285328
int requests = 0;
286329
int status;
287330
int env_size, cgi_env_size;
288331

289-
#ifdef FASTCGI_DEBUG
290-
fprintf( stderr, "Initialising now!\n" );
332+
#ifdef DEBUG_FASTCGI
333+
fprintf( stderr, "Initialising now, pid %d!\n", getpid() );
291334
#endif
292335

336+
if( FCGX_IsCGI() ) {
337+
fprintf( stderr, "The FastCGI version of PHP cannot be "
338+
"run as a CGI application\n" );
339+
exit( 1 );
340+
}
341+
293342
/* Calculate environment size */
294343
env_size = 0;
295344
while( environ[ env_size ] ) { env_size++; }
@@ -342,21 +391,46 @@ int main(int argc, char *argv[])
342391
}
343392

344393
if( children ) {
345-
int parent = 1;
346394
int running = 0;
395+
int i;
396+
pid_t pid;
397+
398+
/* Create a process group for ourself & children */
399+
setsid();
400+
pgroup = getpgrp();
401+
#ifdef DEBUG_FASTCGI
402+
fprintf( stderr, "Process group %d\n", pgroup );
403+
#endif
404+
405+
/* Set up handler to kill children upon exit */
406+
act.sa_flags = 0;
407+
act.sa_handler = fastcgi_cleanup;
408+
if( sigaction( SIGTERM, &act, &old_term ) ||
409+
sigaction( SIGINT, &act, &old_int ) ||
410+
sigaction( SIGQUIT, &act, &old_quit )) {
411+
perror( "Can't set signals" );
412+
exit( 1 );
413+
}
414+
347415
while( parent ) {
348416
do {
349-
#ifdef FASTCGI_DEBUG
417+
#ifdef DEBUG_FASTCGI
350418
fprintf( stderr, "Forking, %d running\n",
351419
running );
352420
#endif
353-
switch( fork() ) {
421+
pid = fork();
422+
switch( pid ) {
354423
case 0:
355424
/* One of the children.
356425
* Make sure we don't go round the
357426
* fork loop any more
358427
*/
359428
parent = 0;
429+
430+
/* don't catch our signals */
431+
sigaction( SIGTERM, &old_term, 0 );
432+
sigaction( SIGQUIT, &old_quit, 0 );
433+
sigaction( SIGINT, &old_int, 0 );
360434
break;
361435
case -1:
362436
perror( "php (pre-forking)" );
@@ -370,34 +444,38 @@ int main(int argc, char *argv[])
370444
} while( parent && ( running < children ));
371445

372446
if( parent ) {
447+
#ifdef DEBUG_FASTCGI
448+
fprintf( stderr, "Wait for kids, pid %d\n",
449+
getpid() );
450+
#endif
373451
wait( &status );
374452
running--;
375453
}
376454
}
377455
}
378456

379457
/* Main FastCGI loop */
380-
#ifdef FASTCGI_DEBUG
458+
#ifdef DEBUG_FASTCGI
381459
fprintf( stderr, "Going into accept loop\n" );
382460
#endif
383461

384462
while( FCGX_Accept( &in, &out, &err, &cgi_env ) >= 0 ) {
385463

386-
#ifdef FASTCGI_DEBUG
464+
#ifdef DEBUG_FASTCGI
387465
fprintf( stderr, "Got accept\n" );
388466
#endif
389467

390-
cgi_env_size = 0;
391-
while( cgi_env[ cgi_env_size ] ) { cgi_env_size++; }
392-
merge_env = malloc( (env_size+cgi_env_size)*sizeof(char*) );
393-
if( !merge_env ) {
394-
perror( "Can't malloc environment" );
395-
exit( 1 );
396-
}
397-
memcpy( merge_env, orig_env, (env_size-1)*sizeof(char *) );
398-
memcpy( merge_env + env_size - 1,
399-
cgi_env, (cgi_env_size+1)*sizeof(char *) );
400-
environ = merge_env;
468+
cgi_env_size = 0;
469+
while( cgi_env[ cgi_env_size ] ) { cgi_env_size++; }
470+
merge_env = malloc( (env_size+cgi_env_size)*sizeof(char*) );
471+
if( !merge_env ) {
472+
perror( "Can't malloc environment" );
473+
exit( 1 );
474+
}
475+
memcpy( merge_env, orig_env, (env_size-1)*sizeof(char *) );
476+
memcpy( merge_env + env_size - 1,
477+
cgi_env, (cgi_env_size+1)*sizeof(char *) );
478+
environ = merge_env;
401479

402480
init_request_info( TLS_C SLS_CC );
403481
SG(server_context) = (void *) 1; /* avoid server_context==NULL checks */
@@ -424,7 +502,7 @@ int main(int argc, char *argv[])
424502
}
425503
}
426504

427-
#ifdef FASTCGI_DEBUG
505+
#ifdef DEBUG_FASTCGI
428506
fprintf( stderr, "Exiting...\n" );
429507
#endif
430508
return 0;

0 commit comments

Comments
 (0)