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