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
  */
299
  */
300
 char *status2str(int);
300
 char *status2str(int);
301
 
301
 
302
+void pyfcgi_sighandler_drop(int signum);
303
+
302
 #endif
304
 #endif

+ 7
- 0
src/conf.c View File

443
 	}
443
 	}
444
 	return strndup(buff, 1024);
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
 
58
 
59
 void sighandler(int signum)
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
 	if(signum == SIGALRM)
67
 	if(signum == SIGALRM)
63
 	{
68
 	{
64
 		pyfcgi_log(LOG_WARNING, "Master process received SIGALRM !");
69
 		pyfcgi_log(LOG_WARNING, "Master process received SIGALRM !");
77
 	}
82
 	}
78
 	if(pool_handler_pid)
83
 	if(pool_handler_pid)
79
 	{
84
 	{
85
+		pyfcgi_log(LOG_INFO, "Killing pool_handler(%d)",
86
+			pool_handler_pid);
80
 		kill(pool_handler_pid, SIGTERM);
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
 	if(monitor_serv_pid)
101
 	if(monitor_serv_pid)
84
 	{
102
 	{
103
+		pyfcgi_log(LOG_INFO, "Killing monitor(%d)",
104
+			monitor_serv_pid);
85
 		kill(monitor_serv_pid, SIGTERM);
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
 	pyfcgi_log(LOG_INFO,
133
 	pyfcgi_log(LOG_INFO,
89
 		"Master process exiting.");
134
 		"Master process exiting.");
110
 
155
 
111
 	act.sa_handler = sighandler;
156
 	act.sa_handler = sighandler;
112
 	sigemptyset(&act.sa_mask);
157
 	sigemptyset(&act.sa_mask);
113
-	sigaddset(&act.sa_mask, SIGTERM);
114
 	act.sa_flags = 0;
158
 	act.sa_flags = 0;
115
 	act.sa_restorer = NULL;
159
 	act.sa_restorer = NULL;
116
 
160
 
161
+	if(sigaction(SIGTERM, &act, NULL))
162
+	{
163
+		perror("Sigaction error");
164
+		exit(4);
165
+	}
117
 	if(sigaction(SIGINT, &act, NULL))
166
 	if(sigaction(SIGINT, &act, NULL))
118
 	{
167
 	{
119
 		perror("Sigaction error");
168
 		perror("Sigaction error");
120
 		exit(4);
169
 		exit(4);
121
 	}
170
 	}
122
-	sigfillset(&act.sa_mask);
123
-	sigdelset(&act.sa_mask, SIGINT);
124
-	sigdelset(&act.sa_mask, SIGTERM);
125
 	act.sa_handler = debug_sighandler;
171
 	act.sa_handler = debug_sighandler;
126
 	if(sigaction(SIGALRM, &act, NULL))
172
 	if(sigaction(SIGALRM, &act, NULL))
127
 	{
173
 	{

+ 21
- 13
src/monitor.c View File

37
 pid_t pyfcgi_spawn_monitor()
37
 pid_t pyfcgi_spawn_monitor()
38
 {
38
 {
39
 	pid_t res;
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
 	int err;
41
 	int err;
44
 
42
 
45
-	signum = signums;
46
 	act.sa_handler = pyfcgi_monitor_sighandler;
43
 	act.sa_handler = pyfcgi_monitor_sighandler;
47
 	sigemptyset(&act.sa_mask);
44
 	sigemptyset(&act.sa_mask);
48
 	act.sa_flags = 0;
45
 	act.sa_flags = 0;
49
 	act.sa_restorer = NULL;
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
 	if(!PyFCGI_conf.mon_socket)
53
 	if(!PyFCGI_conf.mon_socket)
52
 	{
54
 	{
66
 	if(!res)
68
 	if(!res)
67
 	{ //child process
69
 	{ //child process
68
 		pyfcgi_logger_set_ident("StatServ");
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
 		pyfcgi_monitor_loop();
88
 		pyfcgi_monitor_loop();
81
 		pyfcgi_log(LOG_ALERT, "Monitor loop should never return but just did it...");
89
 		pyfcgi_log(LOG_ALERT, "Monitor loop should never return but just did it...");

+ 2
- 2
src/pyworker.c View File

80
 		FCGX_Accept(&in_stream, &out_stream, &err_stream, &envp) >= 0)
80
 		FCGX_Accept(&in_stream, &out_stream, &err_stream, &envp) >= 0)
81
 	{
81
 	{
82
 		pyfcgi_wd_arm();
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
 		gettimeofday(&start, NULL);
84
 		gettimeofday(&start, NULL);
85
 		worker_set_busy();
85
 		worker_set_busy();
86
 		count++;
86
 		count++;
255
 	while ((!count || count != max_reqs) && FCGX_Accept(&in_stream, &out_stream, &err_stream, &envp) >= 0)
255
 	while ((!count || count != max_reqs) && FCGX_Accept(&in_stream, &out_stream, &err_stream, &envp) >= 0)
256
 	{
256
 	{
257
 		pyfcgi_wd_arm();
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
 		gettimeofday(&start, NULL);
259
 		gettimeofday(&start, NULL);
260
 		worker_set_busy();
260
 		worker_set_busy();
261
 
261
 

+ 54
- 10
src/responder.c View File

30
 pid_t spawn_pool_handler()
30
 pid_t spawn_pool_handler()
31
 {
31
 {
32
 	pid_t res;
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
 	res = fork();
40
 	res = fork();
35
 	if(res < 0)
41
 	if(res < 0)
40
 	}
46
 	}
41
 	if(!res)
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
 		responder_loop();
55
 		responder_loop();
44
 		exit((unsigned char)-1);
56
 		exit((unsigned char)-1);
45
 	}
57
 	}
81
 	act.sa_flags = 0;
93
 	act.sa_flags = 0;
82
 	act.sa_restorer = NULL;
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
 		exit(PYFCGI_FATAL);
101
 		exit(PYFCGI_FATAL);
88
 	}
102
 	}
89
 
103
 
314
 			exit(PYFCGI_FATAL);
328
 			exit(PYFCGI_FATAL);
315
 		}
329
 		}
316
 		// Set handler for SIGINT & SIGTERM
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
 			exit(PYFCGI_FATAL);
338
 			exit(PYFCGI_FATAL);
321
 		}
339
 		}
340
+		*/
322
 		if(sigaction(SIGTERM, &act, NULL))
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
 			exit(PYFCGI_FATAL);
346
 			exit(PYFCGI_FATAL);
326
 		}
347
 		}
327
 		// Set watchdog
348
 		// Set watchdog
409
 
430
 
410
 void pool_sighandler(int signum)
431
 void pool_sighandler(int signum)
411
 {
432
 {
412
-	unsigned int i;
433
+	unsigned int i, retry;
434
+	int status, ret;
413
 	struct timespec req;
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
 	if(PyFCGI_conf.context.n_wrk < 1) { clean_exit(0); }
439
 	if(PyFCGI_conf.context.n_wrk < 1) { clean_exit(0); }
417
 
440
 
418
 	for(i=0; i<PyFCGI_conf.context.n_wrk; i++)
441
 	for(i=0; i<PyFCGI_conf.context.n_wrk; i++)
420
 		pyfcgi_log(LOG_INFO, "Sending SIGTERM to child #%d (pid %d)",
443
 		pyfcgi_log(LOG_INFO, "Sending SIGTERM to child #%d (pid %d)",
421
 			i,(*PyFCGI_conf.context.wrk_pids)[i]);
444
 			i,(*PyFCGI_conf.context.wrk_pids)[i]);
422
 		kill((*PyFCGI_conf.context.wrk_pids)[i], SIGTERM);
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
 	for(i=0; i<PyFCGI_conf.context.n_wrk; i++)
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
 			pyfcgi_log(LOG_INFO, "Sending SIGKILL to child %d", i);
473
 			pyfcgi_log(LOG_INFO, "Sending SIGKILL to child %d", i);
430
 			kill((*PyFCGI_conf.context.wrk_pids)[i], SIGKILL);
474
 			kill((*PyFCGI_conf.context.wrk_pids)[i], SIGKILL);

Loading…
Cancel
Save