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 fpm_clock_get(&now);
437 if (q->ev) {
438 if (timercmp(&now, &q->ev->timeout, >) || timercmp(&now, &q->ev->timeout, ==)) {
439 fpm_event_fire(q->ev);
440 /* sanity check */
441 if (fpm_globals.parent_pid != getpid()) {
442 return;
443 }
444 if (q->ev->flags & FPM_EV_PERSIST) {
445 fpm_event_set_timeout(q->ev, now);
446 } else { /* delete the event */
447 q2 = q;
448 if (q->prev) {
449 q->prev->next = q->next;
450 }
451 if (q->next) {
452 q->next->prev = q->prev;
453 }
454 if (q == fpm_event_queue_timer) {
455 fpm_event_queue_timer = q->next;
456 if (fpm_event_queue_timer) {
457 fpm_event_queue_timer->prev = NULL;
458 }
459 }
460 q = q->next;
461 free(q2);
462 continue;
463 }
464 }
465 }
466 q = q->next;
467 }
468 }
469 }
470 /* }}} */
471
fpm_event_fire(struct fpm_event_s * ev)472 void fpm_event_fire(struct fpm_event_s *ev) /* {{{ */
473 {
474 if (!ev || !ev->callback) {
475 return;
476 }
477
478 (*ev->callback)( (struct fpm_event_s *) ev, ev->which, ev->arg);
479 }
480 /* }}} */
481
fpm_event_set(struct fpm_event_s * ev,int fd,int flags,void (* callback)(struct fpm_event_s *,short,void *),void * arg)482 int fpm_event_set(struct fpm_event_s *ev, int fd, int flags, void (*callback)(struct fpm_event_s *, short, void *), void *arg) /* {{{ */
483 {
484 if (!ev || !callback || fd < -1) {
485 return -1;
486 }
487 memset(ev, 0, sizeof(struct fpm_event_s));
488 ev->fd = fd;
489 ev->callback = callback;
490 ev->arg = arg;
491 ev->flags = flags;
492 return 0;
493 }
494 /* }}} */
495
fpm_event_add(struct fpm_event_s * ev,unsigned long int frequency)496 int fpm_event_add(struct fpm_event_s *ev, unsigned long int frequency) /* {{{ */
497 {
498 struct timeval now;
499 struct timeval tmp;
500
501 if (!ev) {
502 return -1;
503 }
504
505 ev->index = -1;
506
507 /* it's a triggered event on incoming data */
508 if (ev->flags & FPM_EV_READ) {
509 ev->which = FPM_EV_READ;
510 if (fpm_event_queue_add(&fpm_event_queue_fd, ev) != 0) {
511 return -1;
512 }
513 return 0;
514 }
515
516 /* it's a timer event */
517 ev->which = FPM_EV_TIMEOUT;
518
519 fpm_clock_get(&now);
520 if (frequency >= 1000) {
521 tmp.tv_sec = frequency / 1000;
522 tmp.tv_usec = (frequency % 1000) * 1000;
523 } else {
524 tmp.tv_sec = 0;
525 tmp.tv_usec = frequency * 1000;
526 }
527 ev->frequency = tmp;
528 fpm_event_set_timeout(ev, now);
529
530 if (fpm_event_queue_add(&fpm_event_queue_timer, ev) != 0) {
531 return -1;
532 }
533
534 return 0;
535 }
536 /* }}} */
537
fpm_event_del(struct fpm_event_s * ev)538 int fpm_event_del(struct fpm_event_s *ev) /* {{{ */
539 {
540 if (ev->index >= 0 && fpm_event_queue_del(&fpm_event_queue_fd, ev) != 0) {
541 return -1;
542 }
543
544 if (ev->index < 0 && fpm_event_queue_del(&fpm_event_queue_timer, ev) != 0) {
545 return -1;
546 }
547
548 return 0;
549 }
550 /* }}} */
551