root/sapi/fpm/fpm/fpm_events.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fpm_event_cleanup
  2. fpm_got_signal
  3. fpm_event_queue_isset
  4. fpm_event_queue_add
  5. fpm_event_queue_del
  6. fpm_event_queue_destroy
  7. fpm_event_pre_init
  8. fpm_event_machanism_name
  9. fpm_event_support_edge_trigger
  10. fpm_event_init_main
  11. fpm_event_loop
  12. fpm_event_fire
  13. fpm_event_set
  14. fpm_event_add
  15. fpm_event_del

   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 
  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 
  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 
 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 
 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 
 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 
 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 
 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 
 296 const char *fpm_event_machanism_name() /* {{{ */
 297 {
 298         return module ? module->name : NULL;
 299 }
 300 /* }}} */
 301 
 302 int fpm_event_support_edge_trigger() /* {{{ */
 303 {
 304         return module ? module->support_edge_trigger : 0;
 305 }
 306 /* }}} */
 307 
 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 
 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 
 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 
 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 
 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 
 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 /* }}} */

/* [<][>][^][v][top][bottom][index][help] */