xref: /PHP-7.4/sapi/fpm/fpm/fpm_events.c (revision 0ed6c371)
1 	/* (c) 2007,2008 Andrei Nigmatulin */
2 
3 #include "fpm_config.h"
4 
5 #include <unistd.h>
6 #include <errno.h>
7 #include <stdlib.h> /* for putenv */
8 #include <string.h>
9 
10 #include <php.h>
11 
12 #include "fpm.h"
13 #include "fpm_process_ctl.h"
14 #include "fpm_events.h"
15 #include "fpm_cleanup.h"
16 #include "fpm_stdio.h"
17 #include "fpm_signals.h"
18 #include "fpm_children.h"
19 #include "zlog.h"
20 #include "fpm_clock.h"
21 #include "fpm_log.h"
22 
23 #include "events/select.h"
24 #include "events/poll.h"
25 #include "events/epoll.h"
26 #include "events/devpoll.h"
27 #include "events/port.h"
28 #include "events/kqueue.h"
29 
30 #ifdef HAVE_SYSTEMD
31 #include "fpm_systemd.h"
32 #endif
33 
34 #define fpm_event_set_timeout(ev, now) timeradd(&(now), &(ev)->frequency, &(ev)->timeout);
35 
36 static void fpm_event_cleanup(int which, void *arg);
37 static void fpm_postponed_children_bury(struct fpm_event_s *ev, short which, void *arg);
38 static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg);
39 static struct fpm_event_s *fpm_event_queue_isset(struct fpm_event_queue_s *queue, struct fpm_event_s *ev);
40 static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev);
41 static int fpm_event_queue_del(struct fpm_event_queue_s **queue, struct fpm_event_s *ev);
42 static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue);
43 
44 static struct fpm_event_module_s *module;
45 static struct fpm_event_queue_s *fpm_event_queue_timer = NULL;
46 static struct fpm_event_queue_s *fpm_event_queue_fd = NULL;
47 static struct fpm_event_s children_bury_timer;
48 
fpm_event_cleanup(int which,void * arg)49 static void fpm_event_cleanup(int which, void *arg) /* {{{ */
50 {
51 	fpm_event_queue_destroy(&fpm_event_queue_timer);
52 	fpm_event_queue_destroy(&fpm_event_queue_fd);
53 }
54 /* }}} */
55 
fpm_postponed_children_bury(struct fpm_event_s * ev,short which,void * arg)56 static void fpm_postponed_children_bury(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
57 {
58 	fpm_children_bury();
59 }
60 /* }}} */
61 
fpm_got_signal(struct fpm_event_s * ev,short which,void * arg)62 static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
63 {
64 	char c;
65 	int res, ret;
66 	int fd = ev->fd;
67 
68 	do {
69 		do {
70 			res = read(fd, &c, 1);
71 		} while (res == -1 && errno == EINTR);
72 
73 		if (res <= 0) {
74 			if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
75 				zlog(ZLOG_SYSERROR, "unable to read from the signal pipe");
76 			}
77 			return;
78 		}
79 
80 		switch (c) {
81 			case 'C' :                  /* SIGCHLD */
82 				zlog(ZLOG_DEBUG, "received SIGCHLD");
83 				/* epoll_wait() may report signal fd before read events for a finished child
84 				 * in the same bunch of events. Prevent immediate free of the child structure
85 				 * and so the fpm_event_s instance. Otherwise use after free happens during
86 				 * attemp to process following read event. */
87 				fpm_event_set_timer(&children_bury_timer, 0, &fpm_postponed_children_bury, NULL);
88 				fpm_event_add(&children_bury_timer, 0);
89 				break;
90 			case 'I' :                  /* SIGINT  */
91 				zlog(ZLOG_DEBUG, "received SIGINT");
92 				zlog(ZLOG_NOTICE, "Terminating ...");
93 				fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
94 				break;
95 			case 'T' :                  /* SIGTERM */
96 				zlog(ZLOG_DEBUG, "received SIGTERM");
97 				zlog(ZLOG_NOTICE, "Terminating ...");
98 				fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
99 				break;
100 			case 'Q' :                  /* SIGQUIT */
101 				zlog(ZLOG_DEBUG, "received SIGQUIT");
102 				zlog(ZLOG_NOTICE, "Finishing ...");
103 				fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET);
104 				break;
105 			case '1' :                  /* SIGUSR1 */
106 				zlog(ZLOG_DEBUG, "received SIGUSR1");
107 				if (0 == fpm_stdio_open_error_log(1)) {
108 					zlog(ZLOG_NOTICE, "error log file re-opened");
109 				} else {
110 					zlog(ZLOG_ERROR, "unable to re-opened error log file");
111 				}
112 
113 				ret = fpm_log_open(1);
114 				if (ret == 0) {
115 					zlog(ZLOG_NOTICE, "access log file re-opened");
116 				} else if (ret == -1) {
117 					zlog(ZLOG_ERROR, "unable to re-opened access log file");
118 				}
119 				/* else no access log are set */
120 
121 				break;
122 			case '2' :                  /* SIGUSR2 */
123 				zlog(ZLOG_DEBUG, "received SIGUSR2");
124 				zlog(ZLOG_NOTICE, "Reloading in progress ...");
125 				fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET);
126 				break;
127 		}
128 
129 		if (fpm_globals.is_child) {
130 			break;
131 		}
132 	} while (1);
133 	return;
134 }
135 /* }}} */
136 
fpm_event_queue_isset(struct fpm_event_queue_s * queue,struct fpm_event_s * ev)137 static struct fpm_event_s *fpm_event_queue_isset(struct fpm_event_queue_s *queue, struct fpm_event_s *ev) /* {{{ */
138 {
139 	if (!ev) {
140 		return NULL;
141 	}
142 
143 	while (queue) {
144 		if (queue->ev == ev) {
145 			return ev;
146 		}
147 		queue = queue->next;
148 	}
149 
150 	return NULL;
151 }
152 /* }}} */
153 
fpm_event_queue_add(struct fpm_event_queue_s ** queue,struct fpm_event_s * ev)154 static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
155 {
156 	struct fpm_event_queue_s *elt;
157 
158 	if (!queue || !ev) {
159 		return -1;
160 	}
161 
162 	if (fpm_event_queue_isset(*queue, ev)) {
163 		return 0;
164 	}
165 
166 	if (!(elt = malloc(sizeof(struct fpm_event_queue_s)))) {
167 		zlog(ZLOG_SYSERROR, "Unable to add the event to queue: malloc() failed");
168 		return -1;
169 	}
170 	elt->prev = NULL;
171 	elt->next = NULL;
172 	elt->ev = ev;
173 
174 	if (*queue) {
175 		(*queue)->prev = elt;
176 		elt->next = *queue;
177 	}
178 	*queue = elt;
179 
180 	/* ask the event module to add the fd from its own queue */
181 	if (*queue == fpm_event_queue_fd && module->add) {
182 		module->add(ev);
183 	}
184 
185 	return 0;
186 }
187 /* }}} */
188 
fpm_event_queue_del(struct fpm_event_queue_s ** queue,struct fpm_event_s * ev)189 static int fpm_event_queue_del(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
190 {
191 	struct fpm_event_queue_s *q;
192 	if (!queue || !ev) {
193 		return -1;
194 	}
195 	q = *queue;
196 	while (q) {
197 		if (q->ev == ev) {
198 			if (q->prev) {
199 				q->prev->next = q->next;
200 			}
201 			if (q->next) {
202 				q->next->prev = q->prev;
203 			}
204 			if (q == *queue) {
205 				*queue = q->next;
206 				if (*queue) {
207 					(*queue)->prev = NULL;
208 				}
209 			}
210 
211 			/* ask the event module to remove the fd from its own queue */
212 			if (*queue == fpm_event_queue_fd && module->remove) {
213 				module->remove(ev);
214 			}
215 
216 			free(q);
217 			return 0;
218 		}
219 		q = q->next;
220 	}
221 	return -1;
222 }
223 /* }}} */
224 
fpm_event_queue_destroy(struct fpm_event_queue_s ** queue)225 static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue) /* {{{ */
226 {
227 	struct fpm_event_queue_s *q, *tmp;
228 
229 	if (!queue) {
230 		return;
231 	}
232 
233 	if (*queue == fpm_event_queue_fd && module->clean) {
234 		module->clean();
235 	}
236 
237 	q = *queue;
238 	while (q) {
239 		tmp = q;
240 		q = q->next;
241 		/* q->prev = NULL */
242 		free(tmp);
243 	}
244 	*queue = NULL;
245 }
246 /* }}} */
247 
fpm_event_pre_init(char * machanism)248 int fpm_event_pre_init(char *machanism) /* {{{ */
249 {
250 	/* kqueue */
251 	module = fpm_event_kqueue_module();
252 	if (module) {
253 		if (!machanism || strcasecmp(module->name, machanism) == 0) {
254 			return 0;
255 		}
256 	}
257 
258 	/* port */
259 	module = fpm_event_port_module();
260 	if (module) {
261 		if (!machanism || strcasecmp(module->name, machanism) == 0) {
262 			return 0;
263 		}
264 	}
265 
266 	/* epoll */
267 	module = fpm_event_epoll_module();
268 	if (module) {
269 		if (!machanism || strcasecmp(module->name, machanism) == 0) {
270 			return 0;
271 		}
272 	}
273 
274 	/* /dev/poll */
275 	module = fpm_event_devpoll_module();
276 	if (module) {
277 		if (!machanism || strcasecmp(module->name, machanism) == 0) {
278 			return 0;
279 		}
280 	}
281 
282 	/* poll */
283 	module = fpm_event_poll_module();
284 	if (module) {
285 		if (!machanism || strcasecmp(module->name, machanism) == 0) {
286 			return 0;
287 		}
288 	}
289 
290 	/* select */
291 	module = fpm_event_select_module();
292 	if (module) {
293 		if (!machanism || strcasecmp(module->name, machanism) == 0) {
294 			return 0;
295 		}
296 	}
297 
298 	if (machanism) {
299 		zlog(ZLOG_ERROR, "event mechanism '%s' is not available on this system", machanism);
300 	} else {
301 		zlog(ZLOG_ERROR, "unable to find a suitable event mechanism on this system");
302 	}
303 	return -1;
304 }
305 /* }}} */
306 
fpm_event_machanism_name()307 const char *fpm_event_machanism_name() /* {{{ */
308 {
309 	return module ? module->name : NULL;
310 }
311 /* }}} */
312 
fpm_event_support_edge_trigger()313 int fpm_event_support_edge_trigger() /* {{{ */
314 {
315 	return module ? module->support_edge_trigger : 0;
316 }
317 /* }}} */
318 
fpm_event_init_main()319 int fpm_event_init_main() /* {{{ */
320 {
321 	struct fpm_worker_pool_s *wp;
322 	int max;
323 
324 	if (!module) {
325 		zlog(ZLOG_ERROR, "no event module found");
326 		return -1;
327 	}
328 
329 	if (!module->wait) {
330 		zlog(ZLOG_ERROR, "Incomplete event implementation. Please open a bug report on https://bugs.php.net.");
331 		return -1;
332 	}
333 
334 	/* count the max number of necessary fds for polling */
335 	max = 1; /* only one FD is necessary at startup for the master process signal pipe */
336 	for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
337 		if (!wp->config) continue;
338 		if (wp->config->catch_workers_output && wp->config->pm_max_children > 0) {
339 			max += (wp->config->pm_max_children * 2);
340 		}
341 	}
342 
343 	if (module->init(max) < 0) {
344 		zlog(ZLOG_ERROR, "Unable to initialize the event module %s", module->name);
345 		return -1;
346 	}
347 
348 	zlog(ZLOG_DEBUG, "event module is %s and %d fds have been reserved", module->name, max);
349 
350 	if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, NULL)) {
351 		return -1;
352 	}
353 	return 0;
354 }
355 /* }}} */
356 
fpm_event_loop(int err)357 void fpm_event_loop(int err) /* {{{ */
358 {
359 	static struct fpm_event_s signal_fd_event;
360 
361 	/* sanity check */
362 	if (fpm_globals.parent_pid != getpid()) {
363 		return;
364 	}
365 
366 	fpm_event_set(&signal_fd_event, fpm_signals_get_fd(), FPM_EV_READ, &fpm_got_signal, NULL);
367 	fpm_event_add(&signal_fd_event, 0);
368 
369 	/* add timers */
370 	if (fpm_globals.heartbeat > 0) {
371 		fpm_pctl_heartbeat(NULL, 0, NULL);
372 	}
373 
374 	if (!err) {
375 		fpm_pctl_perform_idle_server_maintenance_heartbeat(NULL, 0, NULL);
376 
377 		zlog(ZLOG_DEBUG, "%zu bytes have been reserved in SHM", fpm_shm_get_size_allocated());
378 		zlog(ZLOG_NOTICE, "ready to handle connections");
379 
380 #ifdef HAVE_SYSTEMD
381 		fpm_systemd_heartbeat(NULL, 0, NULL);
382 #endif
383 	}
384 
385 	while (1) {
386 		struct fpm_event_queue_s *q, *q2;
387 		struct timeval ms;
388 		struct timeval tmp;
389 		struct timeval now;
390 		unsigned long int timeout;
391 		int ret;
392 
393 		/* sanity check */
394 		if (fpm_globals.parent_pid != getpid()) {
395 			return;
396 		}
397 
398 		fpm_clock_get(&now);
399 		timerclear(&ms);
400 
401 		/* search in the timeout queue for the next timer to trigger */
402 		q = fpm_event_queue_timer;
403 		while (q) {
404 			if (!timerisset(&ms)) {
405 				ms = q->ev->timeout;
406 			} else {
407 				if (timercmp(&q->ev->timeout, &ms, <)) {
408 					ms = q->ev->timeout;
409 				}
410 			}
411 			q = q->next;
412 		}
413 
414 		/* 1s timeout if none has been set */
415 		if (!timerisset(&ms) || timercmp(&ms, &now, <) || timercmp(&ms, &now, ==)) {
416 			timeout = 1000;
417 		} else {
418 			timersub(&ms, &now, &tmp);
419 			timeout = (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000) + 1;
420 		}
421 
422 		ret = module->wait(fpm_event_queue_fd, timeout);
423 
424 		/* is a child, nothing to do here */
425 		if (ret == -2) {
426 			return;
427 		}
428 
429 		if (ret > 0) {
430 			zlog(ZLOG_DEBUG, "event module triggered %d events", ret);
431 		}
432 
433 		/* trigger timers */
434 		q = fpm_event_queue_timer;
435 		while (q) {
436 			struct fpm_event_queue_s *next = q->next;
437 			fpm_clock_get(&now);
438 			if (q->ev) {
439 				if (timercmp(&now, &q->ev->timeout, >) || timercmp(&now, &q->ev->timeout, ==)) {
440 					struct fpm_event_s *ev = q->ev;
441 					if (ev->flags & FPM_EV_PERSIST) {
442 						fpm_event_set_timeout(ev, now);
443 					} else {
444 						/* Delete the event. Make sure this happens before it is fired,
445 						 * so that the event callback may register the same timer again. */
446 						q2 = q;
447 						if (q->prev) {
448 							q->prev->next = q->next;
449 						}
450 						if (q->next) {
451 							q->next->prev = q->prev;
452 						}
453 						if (q == fpm_event_queue_timer) {
454 							fpm_event_queue_timer = q->next;
455 							if (fpm_event_queue_timer) {
456 								fpm_event_queue_timer->prev = NULL;
457 							}
458 						}
459 						free(q2);
460 					}
461 
462 					fpm_event_fire(ev);
463 
464 					/* sanity check */
465 					if (fpm_globals.parent_pid != getpid()) {
466 						return;
467 					}
468 				}
469 			}
470 			q = next;
471 		}
472 	}
473 }
474 /* }}} */
475 
fpm_event_fire(struct fpm_event_s * ev)476 void fpm_event_fire(struct fpm_event_s *ev) /* {{{ */
477 {
478 	if (!ev || !ev->callback) {
479 		return;
480 	}
481 
482 	(*ev->callback)( (struct fpm_event_s *) ev, ev->which, ev->arg);
483 }
484 /* }}} */
485 
fpm_event_set(struct fpm_event_s * ev,int fd,int flags,void (* callback)(struct fpm_event_s *,short,void *),void * arg)486 int fpm_event_set(struct fpm_event_s *ev, int fd, int flags, void (*callback)(struct fpm_event_s *, short, void *), void *arg) /* {{{ */
487 {
488 	if (!ev || !callback || fd < -1) {
489 		return -1;
490 	}
491 	memset(ev, 0, sizeof(struct fpm_event_s));
492 	ev->fd = fd;
493 	ev->callback = callback;
494 	ev->arg = arg;
495 	ev->flags = flags;
496 	return 0;
497 }
498 /* }}} */
499 
fpm_event_add(struct fpm_event_s * ev,unsigned long int frequency)500 int fpm_event_add(struct fpm_event_s *ev, unsigned long int frequency) /* {{{ */
501 {
502 	struct timeval now;
503 	struct timeval tmp;
504 
505 	if (!ev) {
506 		return -1;
507 	}
508 
509 	ev->index = -1;
510 
511 	/* it's a triggered event on incoming data */
512 	if (ev->flags & FPM_EV_READ) {
513 		ev->which = FPM_EV_READ;
514 		if (fpm_event_queue_add(&fpm_event_queue_fd, ev) != 0) {
515 			return -1;
516 		}
517 		return 0;
518 	}
519 
520 	/* it's a timer event */
521 	ev->which = FPM_EV_TIMEOUT;
522 
523 	fpm_clock_get(&now);
524 	if (frequency >= 1000) {
525 		tmp.tv_sec = frequency / 1000;
526 		tmp.tv_usec = (frequency % 1000) * 1000;
527 	} else {
528 		tmp.tv_sec = 0;
529 		tmp.tv_usec = frequency * 1000;
530 	}
531 	ev->frequency = tmp;
532 	fpm_event_set_timeout(ev, now);
533 
534 	if (fpm_event_queue_add(&fpm_event_queue_timer, ev) != 0) {
535 		return -1;
536 	}
537 
538 	return 0;
539 }
540 /* }}} */
541 
fpm_event_del(struct fpm_event_s * ev)542 int fpm_event_del(struct fpm_event_s *ev) /* {{{ */
543 {
544 	if (ev->index >= 0 && fpm_event_queue_del(&fpm_event_queue_fd, ev) != 0) {
545 		return -1;
546 	}
547 
548 	if (ev->index < 0 && fpm_event_queue_del(&fpm_event_queue_timer, ev) != 0) {
549 		return -1;
550 	}
551 
552 	return 0;
553 }
554 /* }}} */
555