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 * attempt 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
108 /* fpm_stdio_init_final tied STDERR fd with error_log fd. This affects logging to the
109 * access.log if it was configured to write to the stderr. Check #8885. */
110 fpm_stdio_restore_original_stderr(0);
111
112 if (0 == fpm_stdio_open_error_log(1)) {
113 zlog(ZLOG_NOTICE, "error log file re-opened");
114 } else {
115 zlog(ZLOG_ERROR, "unable to re-opened error log file");
116 }
117
118 ret = fpm_log_open(1);
119 if (ret == 0) {
120 zlog(ZLOG_NOTICE, "access log file re-opened");
121 } else if (ret == -1) {
122 zlog(ZLOG_ERROR, "unable to re-opened access log file");
123 }
124 /* else no access log are set */
125
126 /* We need to tie stderr with error_log in the master process after log files reload. Check #8885. */
127 fpm_stdio_redirect_stderr_to_error_log();
128
129 break;
130 case '2' : /* SIGUSR2 */
131 zlog(ZLOG_DEBUG, "received SIGUSR2");
132 zlog(ZLOG_NOTICE, "Reloading in progress ...");
133 fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET);
134 break;
135 }
136
137 if (fpm_globals.is_child) {
138 break;
139 }
140 } while (1);
141 return;
142 }
143 /* }}} */
144
fpm_event_queue_isset(struct fpm_event_queue_s * queue,struct fpm_event_s * ev)145 static struct fpm_event_s *fpm_event_queue_isset(struct fpm_event_queue_s *queue, struct fpm_event_s *ev) /* {{{ */
146 {
147 if (!ev) {
148 return NULL;
149 }
150
151 while (queue) {
152 if (queue->ev == ev) {
153 return ev;
154 }
155 queue = queue->next;
156 }
157
158 return NULL;
159 }
160 /* }}} */
161
fpm_event_queue_add(struct fpm_event_queue_s ** queue,struct fpm_event_s * ev)162 static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
163 {
164 struct fpm_event_queue_s *elt;
165
166 if (!queue || !ev) {
167 return -1;
168 }
169
170 if (fpm_event_queue_isset(*queue, ev)) {
171 return 0;
172 }
173
174 if (!(elt = malloc(sizeof(struct fpm_event_queue_s)))) {
175 zlog(ZLOG_SYSERROR, "Unable to add the event to queue: malloc() failed");
176 return -1;
177 }
178 elt->prev = NULL;
179 elt->next = NULL;
180 elt->ev = ev;
181
182 if (*queue) {
183 (*queue)->prev = elt;
184 elt->next = *queue;
185 }
186 *queue = elt;
187
188 /* ask the event module to add the fd from its own queue */
189 if (*queue == fpm_event_queue_fd && module->add) {
190 module->add(ev);
191 }
192
193 return 0;
194 }
195 /* }}} */
196
fpm_event_queue_del(struct fpm_event_queue_s ** queue,struct fpm_event_s * ev)197 static int fpm_event_queue_del(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
198 {
199 struct fpm_event_queue_s *q;
200 if (!queue || !ev) {
201 return -1;
202 }
203 q = *queue;
204 while (q) {
205 if (q->ev == ev) {
206 if (q->prev) {
207 q->prev->next = q->next;
208 }
209 if (q->next) {
210 q->next->prev = q->prev;
211 }
212 if (q == *queue) {
213 *queue = q->next;
214 if (*queue) {
215 (*queue)->prev = NULL;
216 }
217 }
218
219 /* ask the event module to remove the fd from its own queue */
220 if (*queue == fpm_event_queue_fd && module->remove) {
221 module->remove(ev);
222 }
223
224 free(q);
225 return 0;
226 }
227 q = q->next;
228 }
229 return -1;
230 }
231 /* }}} */
232
fpm_event_queue_destroy(struct fpm_event_queue_s ** queue)233 static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue) /* {{{ */
234 {
235 struct fpm_event_queue_s *q, *tmp;
236
237 if (!queue) {
238 return;
239 }
240
241 if (*queue == fpm_event_queue_fd && module->clean) {
242 module->clean();
243 }
244
245 q = *queue;
246 while (q) {
247 tmp = q;
248 q = q->next;
249 /* q->prev = NULL */
250 free(tmp);
251 }
252 *queue = NULL;
253 }
254 /* }}} */
255
fpm_event_pre_init(char * mechanism)256 int fpm_event_pre_init(char *mechanism) /* {{{ */
257 {
258 /* kqueue */
259 module = fpm_event_kqueue_module();
260 if (module) {
261 if (!mechanism || strcasecmp(module->name, mechanism) == 0) {
262 return 0;
263 }
264 }
265
266 /* port */
267 module = fpm_event_port_module();
268 if (module) {
269 if (!mechanism || strcasecmp(module->name, mechanism) == 0) {
270 return 0;
271 }
272 }
273
274 /* epoll */
275 module = fpm_event_epoll_module();
276 if (module) {
277 if (!mechanism || strcasecmp(module->name, mechanism) == 0) {
278 return 0;
279 }
280 }
281
282 /* /dev/poll */
283 module = fpm_event_devpoll_module();
284 if (module) {
285 if (!mechanism || strcasecmp(module->name, mechanism) == 0) {
286 return 0;
287 }
288 }
289
290 /* poll */
291 module = fpm_event_poll_module();
292 if (module) {
293 if (!mechanism || strcasecmp(module->name, mechanism) == 0) {
294 return 0;
295 }
296 }
297
298 /* select */
299 module = fpm_event_select_module();
300 if (module) {
301 if (!mechanism || strcasecmp(module->name, mechanism) == 0) {
302 return 0;
303 }
304 }
305
306 if (mechanism) {
307 zlog(ZLOG_ERROR, "event mechanism '%s' is not available on this system", mechanism);
308 } else {
309 zlog(ZLOG_ERROR, "unable to find a suitable event mechanism on this system");
310 }
311 return -1;
312 }
313 /* }}} */
314
fpm_event_mechanism_name(void)315 const char *fpm_event_mechanism_name(void)
316 {
317 return module ? module->name : NULL;
318 }
319
fpm_event_support_edge_trigger(void)320 int fpm_event_support_edge_trigger(void)
321 {
322 return module ? module->support_edge_trigger : 0;
323 }
324
fpm_event_init_main(void)325 int fpm_event_init_main(void)
326 {
327 struct fpm_worker_pool_s *wp;
328 int max;
329
330 if (!module) {
331 zlog(ZLOG_ERROR, "no event module found");
332 return -1;
333 }
334
335 if (!module->wait) {
336 zlog(ZLOG_ERROR, "Incomplete event implementation. Please open a bug report on https://bugs.php.net.");
337 return -1;
338 }
339
340 /* count the max number of necessary fds for polling */
341 max = 1; /* only one FD is necessary at startup for the master process signal pipe */
342 for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
343 if (!wp->config) continue;
344 if (wp->config->catch_workers_output && wp->config->pm_max_children > 0) {
345 max += (wp->config->pm_max_children * 2);
346 }
347 }
348
349 if (module->init(max) < 0) {
350 zlog(ZLOG_ERROR, "Unable to initialize the event module %s", module->name);
351 return -1;
352 }
353
354 zlog(ZLOG_DEBUG, "event module is %s and %d fds have been reserved", module->name, max);
355
356 if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, NULL)) {
357 return -1;
358 }
359 return 0;
360 }
361
fpm_event_loop(int err)362 void fpm_event_loop(int err) /* {{{ */
363 {
364 static struct fpm_event_s signal_fd_event;
365
366 /* sanity check */
367 if (fpm_globals.parent_pid != getpid()) {
368 return;
369 }
370
371 fpm_event_set(&signal_fd_event, fpm_signals_get_fd(), FPM_EV_READ, &fpm_got_signal, NULL);
372 fpm_event_add(&signal_fd_event, 0);
373
374 /* add timers */
375 if (fpm_globals.heartbeat > 0) {
376 fpm_pctl_heartbeat(NULL, 0, NULL);
377 }
378
379 if (!err) {
380 fpm_pctl_perform_idle_server_maintenance_heartbeat(NULL, 0, NULL);
381
382 zlog(ZLOG_DEBUG, "%zu bytes have been reserved in SHM", fpm_shm_get_size_allocated());
383 zlog(ZLOG_NOTICE, "ready to handle connections");
384
385 #ifdef HAVE_SYSTEMD
386 fpm_systemd_heartbeat(NULL, 0, NULL);
387 #endif
388 }
389
390 while (1) {
391 struct fpm_event_queue_s *q, *q2;
392 struct timeval ms;
393 struct timeval tmp;
394 struct timeval now;
395 unsigned long int timeout;
396 int ret;
397
398 /* sanity check */
399 if (fpm_globals.parent_pid != getpid()) {
400 return;
401 }
402
403 fpm_clock_get(&now);
404 timerclear(&ms);
405
406 /* search in the timeout queue for the next timer to trigger */
407 q = fpm_event_queue_timer;
408 while (q) {
409 if (!timerisset(&ms)) {
410 ms = q->ev->timeout;
411 } else {
412 if (timercmp(&q->ev->timeout, &ms, <)) {
413 ms = q->ev->timeout;
414 }
415 }
416 q = q->next;
417 }
418
419 /* 1s timeout if none has been set */
420 if (!timerisset(&ms) || timercmp(&ms, &now, <) || timercmp(&ms, &now, ==)) {
421 timeout = 1000;
422 } else {
423 timersub(&ms, &now, &tmp);
424 timeout = (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000) + 1;
425 }
426
427 ret = module->wait(fpm_event_queue_fd, timeout);
428
429 /* is a child, nothing to do here */
430 if (ret == -2) {
431 return;
432 }
433
434 if (ret > 0) {
435 zlog(ZLOG_DEBUG, "event module triggered %d events", ret);
436 }
437
438 /* trigger timers */
439 q = fpm_event_queue_timer;
440 while (q) {
441 struct fpm_event_queue_s *next = q->next;
442 fpm_clock_get(&now);
443 if (q->ev) {
444 if (timercmp(&now, &q->ev->timeout, >) || timercmp(&now, &q->ev->timeout, ==)) {
445 struct fpm_event_s *ev = q->ev;
446 if (ev->flags & FPM_EV_PERSIST) {
447 fpm_event_set_timeout(ev, now);
448 } else {
449 /* Delete the event. Make sure this happens before it is fired,
450 * so that the event callback may register the same timer again. */
451 q2 = q;
452 if (q->prev) {
453 q->prev->next = q->next;
454 }
455 if (q->next) {
456 q->next->prev = q->prev;
457 }
458 if (q == fpm_event_queue_timer) {
459 fpm_event_queue_timer = q->next;
460 if (fpm_event_queue_timer) {
461 fpm_event_queue_timer->prev = NULL;
462 }
463 }
464 free(q2);
465 }
466
467 fpm_event_fire(ev);
468
469 /* sanity check */
470 if (fpm_globals.parent_pid != getpid()) {
471 return;
472 }
473 }
474 }
475 q = next;
476 }
477 }
478 }
479 /* }}} */
480
fpm_event_fire(struct fpm_event_s * ev)481 void fpm_event_fire(struct fpm_event_s *ev) /* {{{ */
482 {
483 if (!ev || !ev->callback) {
484 return;
485 }
486
487 (*ev->callback)( (struct fpm_event_s *) ev, ev->which, ev->arg);
488 }
489 /* }}} */
490
fpm_event_set(struct fpm_event_s * ev,int fd,int flags,void (* callback)(struct fpm_event_s *,short,void *),void * arg)491 int fpm_event_set(struct fpm_event_s *ev, int fd, int flags, void (*callback)(struct fpm_event_s *, short, void *), void *arg) /* {{{ */
492 {
493 if (!ev || !callback || fd < -1) {
494 return -1;
495 }
496 memset(ev, 0, sizeof(struct fpm_event_s));
497 ev->fd = fd;
498 ev->callback = callback;
499 ev->arg = arg;
500 ev->flags = flags;
501 return 0;
502 }
503 /* }}} */
504
fpm_event_add(struct fpm_event_s * ev,unsigned long int frequency)505 int fpm_event_add(struct fpm_event_s *ev, unsigned long int frequency) /* {{{ */
506 {
507 struct timeval now;
508 struct timeval tmp;
509
510 if (!ev) {
511 return -1;
512 }
513
514 ev->index = -1;
515
516 /* it's a triggered event on incoming data */
517 if (ev->flags & FPM_EV_READ) {
518 ev->which = FPM_EV_READ;
519 if (fpm_event_queue_add(&fpm_event_queue_fd, ev) != 0) {
520 return -1;
521 }
522 return 0;
523 }
524
525 /* it's a timer event */
526 ev->which = FPM_EV_TIMEOUT;
527
528 fpm_clock_get(&now);
529 if (frequency >= 1000) {
530 tmp.tv_sec = frequency / 1000;
531 tmp.tv_usec = (frequency % 1000) * 1000;
532 } else {
533 tmp.tv_sec = 0;
534 tmp.tv_usec = frequency * 1000;
535 }
536 ev->frequency = tmp;
537 fpm_event_set_timeout(ev, now);
538
539 if (fpm_event_queue_add(&fpm_event_queue_timer, ev) != 0) {
540 return -1;
541 }
542
543 return 0;
544 }
545 /* }}} */
546
fpm_event_del(struct fpm_event_s * ev)547 int fpm_event_del(struct fpm_event_s *ev) /* {{{ */
548 {
549 if (ev->index >= 0 && fpm_event_queue_del(&fpm_event_queue_fd, ev) != 0) {
550 return -1;
551 }
552
553 if (ev->index < 0 && fpm_event_queue_del(&fpm_event_queue_timer, ev) != 0) {
554 return -1;
555 }
556
557 return 0;
558 }
559 /* }}} */
560