php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
fpm_events.c
Go to the documentation of this file.
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/port.h"
27#include "events/kqueue.h"
28
29#ifdef HAVE_SYSTEMD
30#include "fpm_systemd.h"
31#endif
32
33#define fpm_event_set_timeout(ev, now) timeradd(&(now), &(ev)->frequency, &(ev)->timeout);
34
35static void fpm_event_cleanup(int which, void *arg);
36static void fpm_postponed_children_bury(struct fpm_event_s *ev, short which, void *arg);
37static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg);
38static struct fpm_event_s *fpm_event_queue_isset(struct fpm_event_queue_s *queue, struct fpm_event_s *ev);
39static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev);
40static int fpm_event_queue_del(struct fpm_event_queue_s **queue, struct fpm_event_s *ev);
41static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue);
42
43static struct fpm_event_module_s *module;
44static struct fpm_event_queue_s *fpm_event_queue_timer = NULL;
45static struct fpm_event_queue_s *fpm_event_queue_fd = NULL;
46static struct fpm_event_s children_bury_timer;
47
48static 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
55static void fpm_postponed_children_bury(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
56{
58}
59/* }}} */
60
61static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
62{
63 char c;
64 int res, ret;
65 int fd = ev->fd;
66
67 do {
68 do {
69 res = read(fd, &c, 1);
70 } while (res == -1 && errno == EINTR);
71
72 if (res <= 0) {
73 if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
74 zlog(ZLOG_SYSERROR, "unable to read from the signal pipe");
75 }
76 return;
77 }
78
79 switch (c) {
80 case 'C' : /* SIGCHLD */
81 zlog(ZLOG_DEBUG, "received SIGCHLD");
82 /* epoll_wait() may report signal fd before read events for a finished child
83 * in the same bunch of events. Prevent immediate free of the child structure
84 * and so the fpm_event_s instance. Otherwise use after free happens during
85 * attempt to process following read event. */
86 fpm_event_set_timer(&children_bury_timer, 0, &fpm_postponed_children_bury, NULL);
87 fpm_event_add(&children_bury_timer, 0);
88 break;
89 case 'I' : /* SIGINT */
90 zlog(ZLOG_DEBUG, "received SIGINT");
91 zlog(ZLOG_NOTICE, "Terminating ...");
93 break;
94 case 'T' : /* SIGTERM */
95 zlog(ZLOG_DEBUG, "received SIGTERM");
96 zlog(ZLOG_NOTICE, "Terminating ...");
98 break;
99 case 'Q' : /* SIGQUIT */
100 zlog(ZLOG_DEBUG, "received SIGQUIT");
101 zlog(ZLOG_NOTICE, "Finishing ...");
103 break;
104 case '1' : /* SIGUSR1 */
105 zlog(ZLOG_DEBUG, "received SIGUSR1");
106
107 /* fpm_stdio_init_final tied STDERR fd with error_log fd. This affects logging to the
108 * access.log if it was configured to write to the stderr. Check #8885. */
110
111 if (0 == fpm_stdio_open_error_log(1)) {
112 zlog(ZLOG_NOTICE, "error log file re-opened");
113 } else {
114 zlog(ZLOG_ERROR, "unable to re-opened error log file");
115 }
116
117 ret = fpm_log_open(1);
118 if (ret == 0) {
119 zlog(ZLOG_NOTICE, "access log file re-opened");
120 } else if (ret == -1) {
121 zlog(ZLOG_ERROR, "unable to re-opened access log file");
122 }
123 /* else no access log are set */
124
125 /* We need to tie stderr with error_log in the master process after log files reload. Check #8885. */
127
128 break;
129 case '2' : /* SIGUSR2 */
130 zlog(ZLOG_DEBUG, "received SIGUSR2");
131 zlog(ZLOG_NOTICE, "Reloading in progress ...");
133 break;
134 }
135
136 if (fpm_globals.is_child) {
137 break;
138 }
139 } while (1);
140 return;
141}
142/* }}} */
143
144static struct fpm_event_s *fpm_event_queue_isset(struct fpm_event_queue_s *queue, struct fpm_event_s *ev) /* {{{ */
145{
146 if (!ev) {
147 return NULL;
148 }
149
150 while (queue) {
151 if (queue->ev == ev) {
152 return ev;
153 }
154 queue = queue->next;
155 }
156
157 return NULL;
158}
159/* }}} */
160
161static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
162{
163 struct fpm_event_queue_s *elt;
164
165 if (!queue || !ev) {
166 return -1;
167 }
168
169 if (fpm_event_queue_isset(*queue, ev)) {
170 return 0;
171 }
172
173 if (!(elt = malloc(sizeof(struct fpm_event_queue_s)))) {
174 zlog(ZLOG_SYSERROR, "Unable to add the event to queue: malloc() failed");
175 return -1;
176 }
177 elt->prev = NULL;
178 elt->next = NULL;
179 elt->ev = ev;
180
181 if (*queue) {
182 (*queue)->prev = elt;
183 elt->next = *queue;
184 }
185 *queue = elt;
186
187 /* ask the event module to add the fd from its own queue */
188 if (*queue == fpm_event_queue_fd && module->add) {
189 module->add(ev);
190 }
191
192 return 0;
193}
194/* }}} */
195
196static int fpm_event_queue_del(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
197{
198 struct fpm_event_queue_s *q;
199 if (!queue || !ev) {
200 return -1;
201 }
202 q = *queue;
203 while (q) {
204 if (q->ev == ev) {
205 if (q->prev) {
206 q->prev->next = q->next;
207 }
208 if (q->next) {
209 q->next->prev = q->prev;
210 }
211 if (q == *queue) {
212 *queue = q->next;
213 if (*queue) {
214 (*queue)->prev = NULL;
215 }
216 }
217
218 /* ask the event module to remove the fd from its own queue */
219 if (*queue == fpm_event_queue_fd && module->remove) {
220 module->remove(ev);
221 }
222
223 free(q);
224 return 0;
225 }
226 q = q->next;
227 }
228 return -1;
229}
230/* }}} */
231
232static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue) /* {{{ */
233{
234 struct fpm_event_queue_s *q, *tmp;
235
236 if (!queue) {
237 return;
238 }
239
240 if (*queue == fpm_event_queue_fd && module->clean) {
241 module->clean();
242 }
243
244 q = *queue;
245 while (q) {
246 tmp = q;
247 q = q->next;
248 /* q->prev = NULL */
249 free(tmp);
250 }
251 *queue = NULL;
252}
253/* }}} */
254
255int fpm_event_pre_init(char *mechanism) /* {{{ */
256{
257 /* kqueue */
258 module = fpm_event_kqueue_module();
259 if (module) {
260 if (!mechanism || strcasecmp(module->name, mechanism) == 0) {
261 return 0;
262 }
263 }
264
265 /* port */
266 module = fpm_event_port_module();
267 if (module) {
268 if (!mechanism || strcasecmp(module->name, mechanism) == 0) {
269 return 0;
270 }
271 }
272
273 /* epoll */
274 module = fpm_event_epoll_module();
275 if (module) {
276 if (!mechanism || strcasecmp(module->name, mechanism) == 0) {
277 return 0;
278 }
279 }
280
281 /* poll */
282 module = fpm_event_poll_module();
283 if (module) {
284 if (!mechanism || strcasecmp(module->name, mechanism) == 0) {
285 return 0;
286 }
287 }
288
289 /* select */
290 module = fpm_event_select_module();
291 if (module) {
292 if (!mechanism || strcasecmp(module->name, mechanism) == 0) {
293 return 0;
294 }
295 }
296
297 if (mechanism) {
298 zlog(ZLOG_ERROR, "event mechanism '%s' is not available on this system", mechanism);
299 } else {
300 zlog(ZLOG_ERROR, "unable to find a suitable event mechanism on this system");
301 }
302 return -1;
303}
304/* }}} */
305
307{
308 return module ? module->name : NULL;
309}
310
312{
313 return module ? module->support_edge_trigger : 0;
314}
315
317{
318 struct fpm_worker_pool_s *wp;
319 int max;
320
321 if (!module) {
322 zlog(ZLOG_ERROR, "no event module found");
323 return -1;
324 }
325
326 if (!module->wait) {
327 zlog(ZLOG_ERROR, "Incomplete event implementation. Please open a bug report on https://github.com/php/php-src/issues.");
328 return -1;
329 }
330
331 /* count the max number of necessary fds for polling */
332 max = 1; /* only one FD is necessary at startup for the master process signal pipe */
333 for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
334 if (!wp->config) continue;
335 if (wp->config->catch_workers_output && wp->config->pm_max_children > 0) {
336 max += (wp->config->pm_max_children * 2);
337 }
338 }
339
340 if (module->init(max) < 0) {
341 zlog(ZLOG_ERROR, "Unable to initialize the event module %s", module->name);
342 return -1;
343 }
344
345 zlog(ZLOG_DEBUG, "event module is %s and %d fds have been reserved", module->name, max);
346
347 if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, NULL)) {
348 return -1;
349 }
350 return 0;
351}
352
353void fpm_event_loop(int err) /* {{{ */
354{
355 static struct fpm_event_s signal_fd_event;
356
357 /* sanity check */
358 if (fpm_globals.parent_pid != getpid()) {
359 return;
360 }
361
362 fpm_event_set(&signal_fd_event, fpm_signals_get_fd(), FPM_EV_READ, &fpm_got_signal, NULL);
363 fpm_event_add(&signal_fd_event, 0);
364
365 /* add timers */
366 if (fpm_globals.heartbeat > 0) {
368 }
369
370 if (!err) {
372
373 zlog(ZLOG_DEBUG, "%zu bytes have been reserved in SHM", fpm_shm_get_size_allocated());
374 zlog(ZLOG_NOTICE, "ready to handle connections");
375
376#ifdef HAVE_SYSTEMD
378#endif
379 }
380
381 while (1) {
382 struct fpm_event_queue_s *q, *q2;
383 struct timeval ms;
384 struct timeval tmp;
385 struct timeval now;
386 unsigned long int timeout;
387 int ret;
388
389 /* sanity check */
390 if (fpm_globals.parent_pid != getpid()) {
391 return;
392 }
393
395 timerclear(&ms);
396
397 /* search in the timeout queue for the next timer to trigger */
398 q = fpm_event_queue_timer;
399 while (q) {
400 if (!timerisset(&ms)) {
401 ms = q->ev->timeout;
402 } else {
403 if (timercmp(&q->ev->timeout, &ms, <)) {
404 ms = q->ev->timeout;
405 }
406 }
407 q = q->next;
408 }
409
410 /* 1s timeout if none has been set */
411 if (!timerisset(&ms) || timercmp(&ms, &now, <) || timercmp(&ms, &now, ==)) {
412 timeout = 1000;
413 } else {
414 timersub(&ms, &now, &tmp);
415 timeout = (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000) + 1;
416 }
417
418 ret = module->wait(fpm_event_queue_fd, timeout);
419
420 /* is a child, nothing to do here */
421 if (ret == -2) {
422 return;
423 }
424
425 if (ret > 0) {
426 zlog(ZLOG_DEBUG, "event module triggered %d events", ret);
427 }
428
429 /* trigger timers */
430 q = fpm_event_queue_timer;
431 while (q) {
432 struct fpm_event_queue_s *next = q->next;
434 if (q->ev) {
435 if (timercmp(&now, &q->ev->timeout, >) || timercmp(&now, &q->ev->timeout, ==)) {
436 struct fpm_event_s *ev = q->ev;
437 if (ev->flags & FPM_EV_PERSIST) {
439 } else {
440 /* Delete the event. Make sure this happens before it is fired,
441 * so that the event callback may register the same timer again. */
442 q2 = q;
443 if (q->prev) {
444 q->prev->next = q->next;
445 }
446 if (q->next) {
447 q->next->prev = q->prev;
448 }
449 if (q == fpm_event_queue_timer) {
450 fpm_event_queue_timer = q->next;
451 if (fpm_event_queue_timer) {
452 fpm_event_queue_timer->prev = NULL;
453 }
454 }
455 free(q2);
456 }
457
458 fpm_event_fire(ev);
459
460 /* sanity check */
461 if (fpm_globals.parent_pid != getpid()) {
462 return;
463 }
464 }
465 }
466 q = next;
467 }
468 }
469}
470/* }}} */
471
472void 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
482int 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
496int 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
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;
529
530 if (fpm_event_queue_add(&fpm_event_queue_timer, ev) != 0) {
531 return -1;
532 }
533
534 return 0;
535}
536/* }}} */
537
538int 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/* }}} */
zval callback
Definition assert.c:25
#define max(a, b)
Definition exif.c:60
zend_string * res
Definition ffi.c:4692
char * err
Definition ffi.c:3029
zval * arg
Definition ffi.c:3975
memset(ptr, 0, type->size)
struct fpm_globals_s fpm_globals
Definition fpm.c:24
void fpm_children_bury(void)
int fpm_cleanup_add(int type, void(*cleanup)(int, void *), void *arg)
Definition fpm_cleanup.c:18
@ FPM_CLEANUP_ALL
Definition fpm_cleanup.h:15
int fpm_clock_get(struct timeval *tv)
Definition fpm_clock.c:110
#define timerisset(tvp)
Definition fpm_config.h:28
#define timercmp(a, b, CMP)
Definition fpm_config.h:62
#define timerclear(tvp)
Definition fpm_config.h:32
#define timersub(tvp, uvp, vvp)
Definition fpm_config.h:36
int fpm_event_set(struct fpm_event_s *ev, int fd, int flags, void(*callback)(struct fpm_event_s *, short, void *), void *arg)
Definition fpm_events.c:482
int fpm_event_pre_init(char *mechanism)
Definition fpm_events.c:255
int fpm_event_add(struct fpm_event_s *ev, unsigned long int frequency)
Definition fpm_events.c:496
int fpm_event_init_main(void)
Definition fpm_events.c:316
int fpm_event_support_edge_trigger(void)
Definition fpm_events.c:311
void fpm_event_fire(struct fpm_event_s *ev)
Definition fpm_events.c:472
#define fpm_event_set_timeout(ev, now)
Definition fpm_events.c:33
const char * fpm_event_mechanism_name(void)
Definition fpm_events.c:306
void fpm_event_loop(int err)
Definition fpm_events.c:353
int fpm_event_del(struct fpm_event_s *ev)
Definition fpm_events.c:538
#define fpm_event_set_timer(ev, flags, cb, arg)
Definition fpm_events.h:11
#define FPM_EV_TIMEOUT
Definition fpm_events.h:6
#define FPM_EV_READ
Definition fpm_events.h:7
#define FPM_EV_PERSIST
Definition fpm_events.h:8
int fpm_log_open(int reopen)
Definition fpm_log.c:30
void fpm_pctl(int new_state, int action)
void fpm_pctl_heartbeat(struct fpm_event_s *ev, short which, void *arg)
void fpm_pctl_perform_idle_server_maintenance_heartbeat(struct fpm_event_s *ev, short which, void *arg)
@ FPM_PCTL_STATE_TERMINATING
@ FPM_PCTL_STATE_FINISHING
@ FPM_PCTL_STATE_RELOADING
@ FPM_PCTL_ACTION_SET
size_t fpm_shm_get_size_allocated(void)
Definition fpm_shm.c:63
int fpm_signals_get_fd(void)
int fpm_stdio_redirect_stderr_to_error_log(void)
Definition fpm_stdio.c:109
int fpm_stdio_open_error_log(int reopen)
Definition fpm_stdio.c:368
int fpm_stdio_restore_original_stderr(int close_after_restore)
Definition fpm_stdio.c:91
void fpm_systemd_heartbeat(struct fpm_event_s *ev, short which, void *arg)
Definition fpm_systemd.c:47
struct fpm_worker_pool_s * fpm_worker_all_pools
#define NULL
Definition gdcache.h:45
#define next(ls)
Definition minilua.c:2661
#define EWOULDBLOCK
Definition php_network.h:47
int fd
Definition phpdbg.h:282
time_t now
Definition session.c:1281
struct fpm_event_queue_s * prev
Definition fpm_events.h:25
struct fpm_event_s * ev
Definition fpm_events.h:27
struct fpm_event_queue_s * next
Definition fpm_events.h:26
struct timeval timeout
Definition fpm_events.h:15
struct timeval frequency
Definition fpm_events.h:16
void(* callback)(struct fpm_event_s *, short, void *)
Definition fpm_events.h:17
short which
Definition fpm_events.h:21
void * arg
Definition fpm_events.h:18
struct fpm_worker_pool_config_s * config
struct fpm_worker_pool_s * next
#define errno
#define EAGAIN
#define strcasecmp(s1, s2)
zval * ret
#define ZLOG_SYSERROR
Definition zlog.h:53
@ ZLOG_DEBUG
Definition zlog.h:42
@ ZLOG_ERROR
Definition zlog.h:45
@ ZLOG_NOTICE
Definition zlog.h:43
#define zlog(flags,...)
Definition zlog.h:9