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