Browse Source

Signal handling enhancement

Yann Weber 4 years ago
parent
commit
a1f5517fe5
6 changed files with 139 additions and 32 deletions
  1. 2
    0
      include/conf.h
  2. 7
    0
      src/conf.c
  3. 53
    7
      src/main.c
  4. 21
    13
      src/monitor.c
  5. 2
    2
      src/pyworker.c
  6. 54
    10
      src/responder.c

+ 2
- 0
include/conf.h View File

@@ -299,4 +299,6 @@ void pyfcgi_wd_default_sighandler(int signum);
299 299
  */
300 300
 char *status2str(int);
301 301
 
302
+void pyfcgi_sighandler_drop(int signum);
303
+
302 304
 #endif

+ 7
- 0
src/conf.c View File

@@ -443,3 +443,10 @@ char *status2str(int status)
443 443
 	}
444 444
 	return strndup(buff, 1024);
445 445
 }
446
+
447
+void pyfcgi_sighandler_drop(int signum)
448
+{
449
+	pyfcgi_log(LOG_DEBUG, "Catching signal %s", strsignal(signum));
450
+	return;
451
+}
452
+

+ 53
- 7
src/main.c View File

@@ -58,7 +58,12 @@ pid_t monitor_serv_pid;
58 58
 
59 59
 void sighandler(int signum)
60 60
 {
61
-	int ret;
61
+	int status, ret, i;
62
+	struct timespec req;
63
+
64
+	req.tv_sec = 0;
65
+	req.tv_nsec = 100000000; //0.1s
66
+
62 67
 	if(signum == SIGALRM)
63 68
 	{
64 69
 		pyfcgi_log(LOG_WARNING, "Master process received SIGALRM !");
@@ -77,13 +82,53 @@ void sighandler(int signum)
77 82
 	}
78 83
 	if(pool_handler_pid)
79 84
 	{
85
+		pyfcgi_log(LOG_INFO, "Killing pool_handler(%d)",
86
+			pool_handler_pid);
80 87
 		kill(pool_handler_pid, SIGTERM);
81
-		waitpid(pool_handler_pid, &ret, 0);
88
+		for(i=0; i<5; i++)
89
+		{
90
+
91
+			ret = waitpid(pool_handler_pid, &status, WNOHANG);
92
+			if(ret <= 0)
93
+			{
94
+				nanosleep(&req, NULL);
95
+				continue;
96
+			}
97
+			pool_handler_pid = 0;
98
+			break;
99
+		}
82 100
 	}
83 101
 	if(monitor_serv_pid)
84 102
 	{
103
+		pyfcgi_log(LOG_INFO, "Killing monitor(%d)",
104
+			monitor_serv_pid);
85 105
 		kill(monitor_serv_pid, SIGTERM);
86
-		waitpid(monitor_serv_pid, &ret, 0);
106
+		for(i=0; i<5; i++)
107
+		{
108
+
109
+			ret = waitpid(monitor_serv_pid, &status, WNOHANG);
110
+			if(ret <= 0)
111
+			{
112
+				nanosleep(&req, NULL);
113
+				continue;
114
+			}
115
+			monitor_serv_pid = 0;
116
+			break;
117
+		}
118
+	}
119
+	if(pool_handler_pid)
120
+	{
121
+		pyfcgi_log(LOG_WARNING,
122
+			"pool_handler(%d) seems to freeze, sending SIGKILL",
123
+			pool_handler_pid);
124
+		kill(pool_handler_pid, SIGKILL);
125
+	}
126
+	if(monitor_serv_pid)
127
+	{
128
+		pyfcgi_log(LOG_WARNING,
129
+			"pool_handler(%d) seems to freeze, sending SIGKILL",
130
+			monitor_serv_pid);
131
+		kill(monitor_serv_pid, SIGKILL);
87 132
 	}
88 133
 	pyfcgi_log(LOG_INFO,
89 134
 		"Master process exiting.");
@@ -110,18 +155,19 @@ int main(int argc, char **argv)
110 155
 
111 156
 	act.sa_handler = sighandler;
112 157
 	sigemptyset(&act.sa_mask);
113
-	sigaddset(&act.sa_mask, SIGTERM);
114 158
 	act.sa_flags = 0;
115 159
 	act.sa_restorer = NULL;
116 160
 
161
+	if(sigaction(SIGTERM, &act, NULL))
162
+	{
163
+		perror("Sigaction error");
164
+		exit(4);
165
+	}
117 166
 	if(sigaction(SIGINT, &act, NULL))
118 167
 	{
119 168
 		perror("Sigaction error");
120 169
 		exit(4);
121 170
 	}
122
-	sigfillset(&act.sa_mask);
123
-	sigdelset(&act.sa_mask, SIGINT);
124
-	sigdelset(&act.sa_mask, SIGTERM);
125 171
 	act.sa_handler = debug_sighandler;
126 172
 	if(sigaction(SIGALRM, &act, NULL))
127 173
 	{

+ 21
- 13
src/monitor.c View File

@@ -37,16 +37,18 @@ static void clean_exit(int status)
37 37
 pid_t pyfcgi_spawn_monitor()
38 38
 {
39 39
 	pid_t res;
40
-	struct sigaction act;
41
-	const int signums[] = {SIGINT, SIGTERM, SIGALRM, 0};
42
-	const int *signum;
40
+	struct sigaction act, actdrop;
43 41
 	int err;
44 42
 
45
-	signum = signums;
46 43
 	act.sa_handler = pyfcgi_monitor_sighandler;
47 44
 	sigemptyset(&act.sa_mask);
48 45
 	act.sa_flags = 0;
49 46
 	act.sa_restorer = NULL;
47
+	
48
+	actdrop.sa_handler = pyfcgi_sighandler_drop;
49
+	sigemptyset(&act.sa_mask);
50
+	act.sa_flags = 0;
51
+	act.sa_restorer = NULL;
50 52
 
51 53
 	if(!PyFCGI_conf.mon_socket)
52 54
 	{
@@ -66,16 +68,22 @@ pid_t pyfcgi_spawn_monitor()
66 68
 	if(!res)
67 69
 	{ //child process
68 70
 		pyfcgi_logger_set_ident("StatServ");
69
-		while(*signum)
71
+		if(sigaction(SIGTERM, &act, NULL))
70 72
 		{
71
-			if(sigaction(*signum, &act, NULL))
72
-			{
73
-				err = errno;
74
-				pyfcgi_log(LOG_ERR, "Unable to run sigaction for %s : %s",
75
-					strsignal(*signum), strerror(err));
76
-				exit(PYFCGI_FATAL);
77
-			}
78
-			signum++;
73
+			err = errno;
74
+			pyfcgi_log(LOG_ERR, "Unable to run sigaction for SIGTERM : %s",
75
+				strerror(err));
76
+			exit(PYFCGI_FATAL);
77
+		}
78
+		if(sigaction(SIGINT, &actdrop, NULL))
79
+		{
80
+			pyfcgi_log(LOG_WARNING, "Unable run sigaction for SIGINT sigaction : %s",
81
+				strerror(errno));
82
+		}
83
+		if(sigaction(SIGALRM, &actdrop, NULL))
84
+		{
85
+			pyfcgi_log(LOG_WARNING, "Unable to restore ALARM sigaction : %s",
86
+				strerror(errno));
79 87
 		}
80 88
 		pyfcgi_monitor_loop();
81 89
 		pyfcgi_log(LOG_ALERT, "Monitor loop should never return but just did it...");

+ 2
- 2
src/pyworker.c View File

@@ -80,7 +80,7 @@ int work333(int wrk_id)
80 80
 		FCGX_Accept(&in_stream, &out_stream, &err_stream, &envp) >= 0)
81 81
 	{
82 82
 		pyfcgi_wd_arm();
83
-		sem_post(PyFCGI_SEM(SEM_WREQS).sem); // increment request counter
83
+		sem_post(PyFCGI_SEM(SEM_WREQS).sem); // increment request counter discarding OF
84 84
 		gettimeofday(&start, NULL);
85 85
 		worker_set_busy();
86 86
 		count++;
@@ -255,7 +255,7 @@ int work(int wrk_id)
255 255
 	while ((!count || count != max_reqs) && FCGX_Accept(&in_stream, &out_stream, &err_stream, &envp) >= 0)
256 256
 	{
257 257
 		pyfcgi_wd_arm();
258
-		sem_post(PyFCGI_SEM(SEM_WREQS).sem); // increment request counter
258
+		sem_post(PyFCGI_SEM(SEM_WREQS).sem); // increment request counter discarding OF
259 259
 		gettimeofday(&start, NULL);
260 260
 		worker_set_busy();
261 261
 

+ 54
- 10
src/responder.c View File

@@ -30,6 +30,12 @@ static void clean_exit(int status)
30 30
 pid_t spawn_pool_handler()
31 31
 {
32 32
 	pid_t res;
33
+	struct sigaction act;
34
+
35
+	act.sa_handler = pyfcgi_sighandler_drop;
36
+	sigemptyset(&act.sa_mask);
37
+	act.sa_flags = 0;
38
+	act.sa_restorer = NULL;
33 39
 
34 40
 	res = fork();
35 41
 	if(res < 0)
@@ -40,6 +46,12 @@ pid_t spawn_pool_handler()
40 46
 	}
41 47
 	if(!res)
42 48
 	{
49
+		if(sigaction(SIGINT, &act, NULL))
50
+		{
51
+			pyfcgi_log(LOG_WARNING,
52
+				"Unable to sigaction SIGINT handler : %s",
53
+				strerror(errno));
54
+		}
43 55
 		responder_loop();
44 56
 		exit((unsigned char)-1);
45 57
 	}
@@ -81,9 +93,11 @@ int responder_loop()
81 93
 	act.sa_flags = 0;
82 94
 	act.sa_restorer = NULL;
83 95
 
84
-	if(sigaction(SIGINT, &act, NULL))
96
+	if(sigaction(SIGTERM, &act, NULL))
85 97
 	{
86
-		perror("Sigaction error for pool process");
98
+		pyfcgi_log(LOG_ALERT,
99
+			"Sigaction error for SIGTERM pool process : %s",
100
+			strerror(errno));
87 101
 		exit(PYFCGI_FATAL);
88 102
 	}
89 103
 
@@ -314,14 +328,21 @@ pid_t spawn(int wrk_id)
314 328
 			exit(PYFCGI_FATAL);
315 329
 		}
316 330
 		// Set handler for SIGINT & SIGTERM
317
-		if(sigaction(SIGINT, &act, NULL))
331
+		/*
332
+		if(sigaction(SIGINT, &(PyFCGI_conf.context.master_old_sigint),
333
+			NULL))
318 334
 		{
319
-			perror("Sigaction error for pool process");
335
+			pyfcgi_log(LOG_ALERT,
336
+				"Sigaction error for worker process when restoring SIGINT handler: %s",
337
+				strerror(errno));
320 338
 			exit(PYFCGI_FATAL);
321 339
 		}
340
+		*/
322 341
 		if(sigaction(SIGTERM, &act, NULL))
323 342
 		{
324
-			perror("Sigaction2 error for pool process");
343
+			pyfcgi_log(LOG_ALERT,
344
+				"Sigaction error for worker process : %s",
345
+				strerror(errno));
325 346
 			exit(PYFCGI_FATAL);
326 347
 		}
327 348
 		// Set watchdog
@@ -409,10 +430,12 @@ int pyfcgi_pool_idle(const struct timespec *timeout)
409 430
 
410 431
 void pool_sighandler(int signum)
411 432
 {
412
-	unsigned int i;
433
+	unsigned int i, retry;
434
+	int status, ret;
413 435
 	struct timespec req;
414
-	req.tv_sec = 0;
415
-	req.tv_nsec = 200000000; //0.2s
436
+
437
+	pyfcgi_log(LOG_NOTICE, "Received signal %s, cleaning & exiting...",
438
+		strsignal(signum));
416 439
 	if(PyFCGI_conf.context.n_wrk < 1) { clean_exit(0); }
417 440
 
418 441
 	for(i=0; i<PyFCGI_conf.context.n_wrk; i++)
@@ -420,11 +443,32 @@ void pool_sighandler(int signum)
420 443
 		pyfcgi_log(LOG_INFO, "Sending SIGTERM to child #%d (pid %d)",
421 444
 			i,(*PyFCGI_conf.context.wrk_pids)[i]);
422 445
 		kill((*PyFCGI_conf.context.wrk_pids)[i], SIGTERM);
423
-		nanosleep(&req, NULL); //waiting 0.2s
446
+	}
447
+	retry = i = 0;
448
+	while(i<PyFCGI_conf.context.n_wrk)
449
+	{
450
+		ret = waitpid((*PyFCGI_conf.context.wrk_pids)[i], &status,
451
+			WNOHANG);
452
+		if(ret <= 0 && retry < 3)
453
+		{
454
+			retry++;
455
+			req.tv_sec = 0;
456
+			req.tv_nsec = 100000000; //0.1s
457
+			nanosleep(&req, NULL);
458
+		}
459
+		else
460
+		{
461
+			if(retry < 3)
462
+			{
463
+				(*PyFCGI_conf.context.wrk_pids)[i] = 0;
464
+			}
465
+			retry = 0;
466
+			i++;
467
+		}
424 468
 	}
425 469
 	for(i=0; i<PyFCGI_conf.context.n_wrk; i++)
426 470
 	{
427
-		if(kill((*PyFCGI_conf.context.wrk_pids)[i], SIGCONT))
471
+		if((*PyFCGI_conf.context.wrk_pids)[i])
428 472
 		{
429 473
 			pyfcgi_log(LOG_INFO, "Sending SIGKILL to child %d", i);
430 474
 			kill((*PyFCGI_conf.context.wrk_pids)[i], SIGKILL);

Loading…
Cancel
Save