Back to index

php5  5.3.10
fpm_events.c
Go to the documentation of this file.
00001 
00002        /* $Id: fpm_events.c,v 1.21.2.2 2008/12/13 03:21:18 anight Exp $ */
00003        /* (c) 2007,2008 Andrei Nigmatulin */
00004 
00005 #include "fpm_config.h"
00006 
00007 #include <unistd.h>
00008 #include <errno.h>
00009 #include <stdlib.h> /* for putenv */
00010 #include <string.h>
00011 
00012 #include <php.h>
00013 
00014 #include "fpm.h"
00015 #include "fpm_process_ctl.h"
00016 #include "fpm_events.h"
00017 #include "fpm_cleanup.h"
00018 #include "fpm_stdio.h"
00019 #include "fpm_signals.h"
00020 #include "fpm_children.h"
00021 #include "zlog.h"
00022 #include "fpm_clock.h"
00023 #include "fpm_log.h"
00024 
00025 #include "events/select.h"
00026 #include "events/poll.h"
00027 #include "events/epoll.h"
00028 #include "events/devpoll.h"
00029 #include "events/port.h"
00030 #include "events/kqueue.h"
00031 
00032 #define fpm_event_set_timeout(ev, now) timeradd(&(now), &(ev)->frequency, &(ev)->timeout);
00033 
00034 static void fpm_event_cleanup(int which, void *arg);
00035 static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg);
00036 static struct fpm_event_s *fpm_event_queue_isset(struct fpm_event_queue_s *queue, struct fpm_event_s *ev);
00037 static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev);
00038 static int fpm_event_queue_del(struct fpm_event_queue_s **queue, struct fpm_event_s *ev);
00039 static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue);
00040 
00041 static struct fpm_event_module_s *module;
00042 static struct fpm_event_queue_s *fpm_event_queue_timer = NULL;
00043 static struct fpm_event_queue_s *fpm_event_queue_fd = NULL;
00044 
00045 static void fpm_event_cleanup(int which, void *arg) /* {{{ */
00046 {
00047        fpm_event_queue_destroy(&fpm_event_queue_timer);
00048        fpm_event_queue_destroy(&fpm_event_queue_fd);
00049 }
00050 /* }}} */
00051 
00052 static void fpm_got_signal(struct fpm_event_s *ev, short which, void *arg) /* {{{ */
00053 {
00054        char c;
00055        int res, ret;
00056        int fd = ev->fd;
00057 
00058        do {
00059               do {
00060                      res = read(fd, &c, 1);
00061               } while (res == -1 && errno == EINTR);
00062 
00063               if (res <= 0) {
00064                      if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
00065                             zlog(ZLOG_SYSERROR, "unable to read from the signal pipe");
00066                      }
00067                      return;
00068               }
00069 
00070               switch (c) {
00071                      case 'C' :                  /* SIGCHLD */
00072                             zlog(ZLOG_DEBUG, "received SIGCHLD");
00073                             fpm_children_bury();
00074                             break;
00075                      case 'I' :                  /* SIGINT  */
00076                             zlog(ZLOG_DEBUG, "received SIGINT");
00077                             zlog(ZLOG_NOTICE, "Terminating ...");
00078                             fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
00079                             break;
00080                      case 'T' :                  /* SIGTERM */
00081                             zlog(ZLOG_DEBUG, "received SIGTERM");
00082                             zlog(ZLOG_NOTICE, "Terminating ...");
00083                             fpm_pctl(FPM_PCTL_STATE_TERMINATING, FPM_PCTL_ACTION_SET);
00084                             break;
00085                      case 'Q' :                  /* SIGQUIT */
00086                             zlog(ZLOG_DEBUG, "received SIGQUIT");
00087                             zlog(ZLOG_NOTICE, "Finishing ...");
00088                             fpm_pctl(FPM_PCTL_STATE_FINISHING, FPM_PCTL_ACTION_SET);
00089                             break;
00090                      case '1' :                  /* SIGUSR1 */
00091                             zlog(ZLOG_DEBUG, "received SIGUSR1");
00092                             if (0 == fpm_stdio_open_error_log(1)) {
00093                                    zlog(ZLOG_NOTICE, "error log file re-opened");
00094                             } else {
00095                                    zlog(ZLOG_ERROR, "unable to re-opened error log file");
00096                             }
00097 
00098                             ret = fpm_log_open(1);
00099                             if (ret == 0) {
00100                                    zlog(ZLOG_NOTICE, "access log file re-opened");
00101                             } else if (ret == -1) {
00102                                    zlog(ZLOG_ERROR, "unable to re-opened access log file");
00103                             }
00104                             /* else no access log are set */
00105 
00106                             break;
00107                      case '2' :                  /* SIGUSR2 */
00108                             zlog(ZLOG_DEBUG, "received SIGUSR2");
00109                             zlog(ZLOG_NOTICE, "Reloading in progress ...");
00110                             fpm_pctl(FPM_PCTL_STATE_RELOADING, FPM_PCTL_ACTION_SET);
00111                             break;
00112               }
00113 
00114               if (fpm_globals.is_child) {
00115                      break;
00116               }
00117        } while (1);
00118        return;
00119 }
00120 /* }}} */
00121 
00122 static struct fpm_event_s *fpm_event_queue_isset(struct fpm_event_queue_s *queue, struct fpm_event_s *ev) /* {{{ */
00123 {
00124        if (!ev) {
00125               return NULL;
00126        }
00127 
00128        while (queue) {
00129               if (queue->ev == ev) {
00130                      return ev;
00131               }
00132               queue = queue->next;
00133        }
00134 
00135        return NULL;
00136 }
00137 /* }}} */
00138 
00139 static int fpm_event_queue_add(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
00140 {
00141        struct fpm_event_queue_s *elt;
00142 
00143        if (!queue || !ev) {
00144               return -1;
00145        }
00146 
00147        if (fpm_event_queue_isset(*queue, ev)) {
00148               return 0;
00149        }
00150 
00151        if (!(elt = malloc(sizeof(struct fpm_event_queue_s)))) {
00152               zlog(ZLOG_SYSERROR, "Unable to add the event to queue: malloc() failed");
00153               return -1;
00154        }
00155        elt->prev = NULL;
00156        elt->next = NULL;
00157        elt->ev = ev;
00158 
00159        if (*queue) {
00160               (*queue)->prev = elt;
00161               elt->next = *queue;
00162        }
00163        *queue = elt;
00164 
00165        /* ask the event module to add the fd from its own queue */
00166        if (*queue == fpm_event_queue_fd && module->add) {
00167               module->add(ev);
00168        }
00169 
00170        return 0;     
00171 }
00172 /* }}} */
00173 
00174 static int fpm_event_queue_del(struct fpm_event_queue_s **queue, struct fpm_event_s *ev) /* {{{ */
00175 {
00176        struct fpm_event_queue_s *q;
00177        if (!queue || !ev) {
00178               return -1;
00179        }
00180        q = *queue;
00181        while (q) {
00182               if (q->ev == ev) {
00183                      if (q->prev) {
00184                             q->prev->next = q->next;
00185                      }
00186                      if (q->next) {
00187                             q->next->prev = q->prev;
00188                      }
00189                      if (q == *queue) {
00190                             *queue = q->next;
00191                             (*queue)->prev = NULL;
00192                      }
00193 
00194                      /* ask the event module to remove the fd from its own queue */
00195                      if (*queue == fpm_event_queue_fd && module->remove) {
00196                             module->remove(ev);
00197                      }
00198 
00199                      free(q);
00200                      return 0;
00201               }
00202               q = q->next;
00203        }
00204        return -1;
00205 }
00206 /* }}} */
00207 
00208 static void fpm_event_queue_destroy(struct fpm_event_queue_s **queue) /* {{{ */
00209 {
00210        struct fpm_event_queue_s *q, *tmp;
00211 
00212        if (!queue) {
00213               return;
00214        }
00215 
00216        if (*queue == fpm_event_queue_fd && module->clean) {
00217               module->clean();
00218        }
00219 
00220        q = *queue;
00221        while (q) {
00222               tmp = q;
00223               q = q->next;
00224               /* q->prev = NULL */
00225               free(tmp);
00226        }
00227        *queue = NULL;
00228 }
00229 /* }}} */
00230 
00231 int fpm_event_pre_init(char *machanism) /* {{{ */
00232 {
00233        /* kqueue */
00234        module = fpm_event_kqueue_module();
00235        if (module) {
00236               if (!machanism || strcasecmp(module->name, machanism) == 0) {
00237                      return 0;
00238               }
00239        }
00240 
00241        /* port */
00242        module = fpm_event_port_module();
00243        if (module) {
00244               if (!machanism || strcasecmp(module->name, machanism) == 0) {
00245                      return 0;
00246               }
00247        }
00248 
00249        /* epoll */
00250        module = fpm_event_epoll_module();
00251        if (module) {
00252               if (!machanism || strcasecmp(module->name, machanism) == 0) {
00253                      return 0;
00254               }
00255        }
00256 
00257        /* /dev/poll */
00258        module = fpm_event_devpoll_module();
00259        if (module) {
00260               if (!machanism || strcasecmp(module->name, machanism) == 0) {
00261                      return 0;
00262               }
00263        }
00264 
00265        /* poll */
00266        module = fpm_event_poll_module();
00267        if (module) {
00268               if (!machanism || strcasecmp(module->name, machanism) == 0) {
00269                      return 0;
00270               }
00271        }
00272 
00273        /* select */
00274        module = fpm_event_select_module();
00275        if (module) {
00276               if (!machanism || strcasecmp(module->name, machanism) == 0) {
00277                      return 0;
00278               }
00279        }
00280 
00281        if (machanism) {
00282               zlog(ZLOG_ERROR, "event mechanism '%s' is not available on this system", machanism);
00283        } else {
00284               zlog(ZLOG_ERROR, "unable to find a suitable event mechanism on this system");
00285        }
00286        return -1;
00287 }
00288 /* }} */
00289 
00290 const char *fpm_event_machanism_name() /* {{{ */
00291 {
00292        return module ? module->name : NULL;
00293 }
00294 /* }}} */
00295 
00296 int fpm_event_support_edge_trigger() /* {{{ */
00297 {
00298        return module ? module->support_edge_trigger : 0;
00299 }
00300 /* }}} */
00301 
00302 int fpm_event_init_main() /* {{{ */
00303 {
00304        struct fpm_worker_pool_s *wp;
00305        int max;
00306 
00307        if (!module) {
00308               zlog(ZLOG_ERROR, "no event module found");
00309               return -1;
00310        }
00311 
00312        if (!module->wait) {
00313               zlog(ZLOG_ERROR, "Incomplete event implementation. Please open a bug report on https://bugs.php.net.");
00314               return -1;
00315        }
00316 
00317        /* count the max number of necessary fds for polling */
00318        max = 1; /* only one FD is necessary at startup for the master process signal pipe */
00319        for (wp = fpm_worker_all_pools; wp; wp = wp->next) {
00320               if (!wp->config) continue;
00321               if (wp->config->catch_workers_output && wp->config->pm_max_children > 0) {
00322                      max += (wp->config->pm_max_children * 2);
00323               }
00324        }
00325 
00326        if (module->init(max) < 0) {
00327               zlog(ZLOG_ERROR, "Unable to initialize the event module %s", module->name);
00328               return -1;
00329        }
00330 
00331        zlog(ZLOG_DEBUG, "event module is %s and %d fds have been reserved", module->name, max);
00332 
00333        if (0 > fpm_cleanup_add(FPM_CLEANUP_ALL, fpm_event_cleanup, NULL)) {
00334               return -1;
00335        }
00336        return 0;
00337 }
00338 /* }}} */
00339 
00340 void fpm_event_loop(int err) /* {{{ */
00341 {
00342        static struct fpm_event_s signal_fd_event;
00343 
00344        /* sanity check */
00345        if (fpm_globals.parent_pid != getpid()) {
00346               return;
00347        }
00348 
00349        fpm_event_set(&signal_fd_event, fpm_signals_get_fd(), FPM_EV_READ, &fpm_got_signal, NULL);
00350        fpm_event_add(&signal_fd_event, 0);
00351 
00352        /* add timers */
00353        if (fpm_globals.heartbeat > 0) {
00354               fpm_pctl_heartbeat(NULL, 0, NULL);
00355        }
00356 
00357        if (!err) {
00358               fpm_pctl_perform_idle_server_maintenance_heartbeat(NULL, 0, NULL);
00359 
00360               zlog(ZLOG_DEBUG, "%zu bytes have been reserved in SHM", fpm_shm_get_size_allocated());
00361               zlog(ZLOG_NOTICE, "ready to handle connections");
00362        }
00363 
00364        while (1) {
00365               struct fpm_event_queue_s *q, *q2;
00366               struct timeval ms;
00367               struct timeval tmp;
00368               struct timeval now;
00369               unsigned long int timeout;
00370               int ret;
00371 
00372               /* sanity check */
00373               if (fpm_globals.parent_pid != getpid()) {
00374                      return;
00375               }
00376 
00377               fpm_clock_get(&now);
00378               timerclear(&ms);
00379 
00380               /* search in the timeout queue for the next timer to trigger */
00381               q = fpm_event_queue_timer;
00382               while (q) {
00383                      if (!timerisset(&ms)) {
00384                             ms = q->ev->timeout;
00385                      } else {
00386                             if (timercmp(&q->ev->timeout, &ms, <)) {
00387                                    ms = q->ev->timeout;
00388                             }
00389                      }
00390                      q = q->next;
00391               }
00392 
00393               /* 1s timeout if none has been set */
00394               if (!timerisset(&ms) || timercmp(&ms, &now, <) || timercmp(&ms, &now, ==)) {
00395                      timeout = 1000;
00396               } else {
00397                      timersub(&ms, &now, &tmp);
00398                      timeout = (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000) + 1;
00399               }
00400 
00401               ret = module->wait(fpm_event_queue_fd, timeout);
00402 
00403               /* is a child, nothing to do here */
00404               if (ret == -2) {
00405                      return;
00406               }
00407 
00408               if (ret > 0) {
00409                      zlog(ZLOG_DEBUG, "event module triggered %d events", ret);
00410               }
00411 
00412               /* trigger timers */
00413               q = fpm_event_queue_timer;
00414               while (q) {
00415                      fpm_clock_get(&now);
00416                      if (q->ev) {
00417                             if (timercmp(&now, &q->ev->timeout, >) || timercmp(&now, &q->ev->timeout, ==)) {
00418                                    fpm_event_fire(q->ev);
00419                                    /* sanity check */
00420                                    if (fpm_globals.parent_pid != getpid()) {
00421                                           return;
00422                                    }
00423                                    if (q->ev->flags & FPM_EV_PERSIST) {
00424                                           fpm_event_set_timeout(q->ev, now);
00425                                    } else { /* delete the event */
00426                                           q2 = q;
00427                                           if (q->prev) {
00428                                                  q->prev->next = q->next;
00429                                           }
00430                                           if (q->next) {
00431                                                  q->next->prev = q->prev;
00432                                           }
00433                                           if (q == fpm_event_queue_timer) {
00434                                                  fpm_event_queue_timer = q->next;
00435                                                  fpm_event_queue_timer->prev = NULL;
00436                                           }
00437                                           q = q->next;
00438                                           free(q2);
00439                                           continue;
00440                                    }
00441                             }
00442                      }
00443                      q = q->next;
00444               }
00445        }
00446 }
00447 /* }}} */
00448 
00449 void fpm_event_fire(struct fpm_event_s *ev) /* {{{ */
00450 {
00451        if (!ev || !ev->callback) {
00452               return;
00453        }
00454 
00455        (*ev->callback)( (struct fpm_event_s *) ev, ev->which, ev->arg);      
00456 }
00457 /* }}} */
00458 
00459 int fpm_event_set(struct fpm_event_s *ev, int fd, int flags, void (*callback)(struct fpm_event_s *, short, void *), void *arg) /* {{{ */
00460 {
00461        if (!ev || !callback || fd < -1) {
00462               return -1;
00463        }
00464        memset(ev, 0, sizeof(struct fpm_event_s));
00465        ev->fd = fd;
00466        ev->callback = callback;
00467        ev->arg = arg;
00468        ev->flags = flags;
00469        return 0;
00470 }
00471 /* }}} */
00472 
00473 int fpm_event_add(struct fpm_event_s *ev, unsigned long int frequency) /* {{{ */
00474 {
00475        struct timeval now;
00476        struct timeval tmp;
00477 
00478        if (!ev) {
00479               return -1;
00480        }
00481 
00482        ev->index = -1;
00483 
00484        /* it's a triggered event on incoming data */
00485        if (ev->flags & FPM_EV_READ) {
00486               ev->which = FPM_EV_READ;
00487               if (fpm_event_queue_add(&fpm_event_queue_fd, ev) != 0) {
00488                      return -1;
00489               }
00490               return 0;
00491        }
00492 
00493        /* it's a timer event */
00494        ev->which = FPM_EV_TIMEOUT;
00495 
00496        fpm_clock_get(&now);
00497        if (frequency >= 1000) {
00498               tmp.tv_sec = frequency / 1000;
00499               tmp.tv_usec = (frequency % 1000) * 1000;
00500        } else {
00501               tmp.tv_sec = 0;
00502               tmp.tv_usec = frequency * 1000;
00503        }
00504        ev->frequency = tmp;
00505        fpm_event_set_timeout(ev, now);
00506 
00507        if (fpm_event_queue_add(&fpm_event_queue_timer, ev) != 0) {
00508               return -1;
00509        }
00510 
00511        return 0;
00512 }
00513 /* }}} */
00514 
00515 int fpm_event_del(struct fpm_event_s *ev) /* {{{ */
00516 {
00517        if (ev->index >= 0 && fpm_event_queue_del(&fpm_event_queue_fd, ev) != 0) {
00518               return -1;
00519        }
00520 
00521        if (ev->index < 0 && fpm_event_queue_del(&fpm_event_queue_timer, ev) != 0) {
00522               return -1;
00523        }
00524 
00525        return 0;
00526 }
00527 /* }}} */
00528 
00529 /* }}} */