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