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