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