Exemple #1
0
void ngx_event_expire_timers(ngx_msec_t timer)
{
  ngx_event_t   *ev;
  ngx_rbtree_t  *node;

  if (timer < 0) {
    /* avoid the endless loop if the time goes backward for some reason */
    timer = 0;
  }

  for ( ;; ) {

    if (ngx_event_timer_rbtree == &ngx_event_timer_sentinel) {
      return;
    }

    if (ngx_mutex_lock(ngx_event_timer_mutex) == NGX_ERROR) {
      return;
    }

    node = ngx_rbtree_min((ngx_rbtree_t *) ngx_event_timer_rbtree,
                &ngx_event_timer_sentinel);

    if (node->key <= (ngx_msec_t)
             (ngx_old_elapsed_msec + timer) / NGX_TIMER_RESOLUTION)
    {
      ev = (ngx_event_t *)
               ((char *) node - offsetof(ngx_event_t, rbtree_key));


      ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
               "event timer del: %d: %d",
              ngx_event_ident(ev->data), ev->rbtree_key);

      ngx_rbtree_delete((ngx_rbtree_t **) &ngx_event_timer_rbtree,
                &ngx_event_timer_sentinel,
                (ngx_rbtree_t *) &ev->rbtree_key);

      ngx_mutex_unlock(ngx_event_timer_mutex);

#if (NGX_DEBUG)
      ev->rbtree_left = NULL;
      ev->rbtree_right = NULL;
      ev->rbtree_parent = NULL;
#endif

      ev->timer_set = 0;


      ev->timedout = 1;

      ev->event_handler(ev);

      continue;
    }

    break;
  }

  ngx_mutex_unlock(ngx_event_timer_mutex);
}
ngx_int_t
ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
    ngx_uint_t flags)
{
    int                 n, revents;
    u_int               events;
    ngx_err_t           err;
    ngx_int_t           instance;
    ngx_uint_t          i, level;
    ngx_event_t        *ev, *rev, *wev, **queue;
    ngx_connection_t   *c;
    struct timespec     ts, *tp;

    if (timer == NGX_TIMER_INFINITE) {
        tp = NULL;

    } else {
        ts.tv_sec = timer / 1000;
        ts.tv_nsec = (timer % 1000) * 1000000;
        tp = &ts;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "eventport timer: %M", timer);

    events = 1;

    n = port_getn(ep, event_list, (u_int) nevents, &events, tp);

    err = ngx_errno;

    if (flags & NGX_UPDATE_TIME) {
        ngx_time_update();
    }

    if (n == -1) {
        if (err == ETIME) {
            if (timer != NGX_TIMER_INFINITE) {
                return NGX_OK;
            }

            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "port_getn() returned no events without timeout");
            return NGX_ERROR;
        }

        level = (err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT;
        ngx_log_error(level, cycle->log, err, "port_getn() failed");
        return NGX_ERROR;
    }

    if (events == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "port_getn() returned no events without timeout");
        return NGX_ERROR;
    }

    ngx_mutex_lock(ngx_posted_events_mutex);

    for (i = 0; i < events; i++) {

        if (event_list[i].portev_source == PORT_SOURCE_TIMER) {
            ngx_time_update();
            continue;
        }

        ev = event_list[i].portev_user;

        switch (event_list[i].portev_source) {

        case PORT_SOURCE_FD:

            instance = (uintptr_t) ev & 1;
            ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);

            if (ev->closed || ev->instance != instance) {

                /*
                 * the stale event from a file descriptor
                 * that was just closed in this iteration
                 */

                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "eventport: stale event %p", ev);
                continue;
            }

            revents = event_list[i].portev_events;

            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "eventport: fd:%d, ev:%04Xd",
                           event_list[i].portev_object, revents);

            if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
                ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "port_getn() error fd:%d ev:%04Xd",
                               event_list[i].portev_object, revents);
            }

            if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
                ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                              "strange port_getn() events fd:%d ev:%04Xd",
                              event_list[i].portev_object, revents);
            }

            if ((revents & (POLLERR|POLLHUP|POLLNVAL))
                 && (revents & (POLLIN|POLLOUT)) == 0)
            {
                /*
                 * if the error events were returned without POLLIN or POLLOUT,
                 * then add these flags to handle the events at least in one
                 * active handler
                 */

                revents |= POLLIN|POLLOUT;
            }

            c = ev->data;
            rev = c->read;
            wev = c->write;

            rev->active = 0;
            wev->active = 0;

            if (revents & POLLIN) {

                if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
                    rev->posted_ready = 1;

                } else {
                    rev->ready = 1;
                }

                if (flags & NGX_POST_EVENTS) {
                    queue = (ngx_event_t **) (rev->accept ?
                               &ngx_posted_accept_events : &ngx_posted_events);

                    ngx_locked_post_event(rev, queue);

                } else {
                    rev->handler(rev);

                    if (ev->closed) {
                        continue;
                    }
                }

                if (rev->accept) {
                    if (ngx_use_accept_mutex) {
                        ngx_accept_events = 1;
                        continue;
                    }

                    if (port_associate(ep, PORT_SOURCE_FD, c->fd, POLLIN,
                                       (void *) ((uintptr_t) ev | ev->instance))
                        == -1)
                    {
                        ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno,
                                      "port_associate() failed");
                        return NGX_ERROR;
                    }
                }
            }

            if (revents & POLLOUT) {

                if (flags & NGX_POST_THREAD_EVENTS) {
                    wev->posted_ready = 1;

                } else {
                    wev->ready = 1;
                }

                if (flags & NGX_POST_EVENTS) {
                    ngx_locked_post_event(wev, &ngx_posted_events);

                } else {
                    wev->handler(wev);
                }
            }

            continue;

        default:
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "unexpected even_port object %d",
                          event_list[i].portev_object);
            continue;
        }
    }

    ngx_mutex_unlock(ngx_posted_events_mutex);

    return NGX_OK;
}
int ngx_epoll_process_events(ngx_cycle_t *cycle)
{
    int                events;
    size_t             n;
    ngx_int_t          instance, i;
    ngx_uint_t         lock, accept_lock, expire;
    ngx_err_t          err;
    ngx_log_t         *log;
    ngx_msec_t         timer;
    ngx_event_t       *rev, *wev;
    struct timeval     tv;
    ngx_connection_t  *c;
    ngx_epoch_msec_t   delta;

    for ( ;; ) { 
        timer = ngx_event_find_timer();

#if (NGX_THREADS)

        if (timer == NGX_TIMER_ERROR) {
            return NGX_ERROR;
        }

        if (timer == NGX_TIMER_INFINITE || timer > 500) {
            timer = 500;
            break;
        }

#endif

        if (timer != 0) {
            break;
        }

        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "epoll expired timer");

        ngx_event_expire_timers((ngx_msec_t)
                                    (ngx_elapsed_msec - ngx_old_elapsed_msec));

        if (ngx_posted_events && ngx_threaded) {
            ngx_wakeup_worker_thread(cycle);
        }
    }

    /* NGX_TIMER_INFINITE == INFTIM */

    if (timer == NGX_TIMER_INFINITE) {
        expire = 0;

    } else {
        expire = 1;
    }

    ngx_old_elapsed_msec = ngx_elapsed_msec;
    accept_lock = 0;

    if (ngx_accept_mutex) {
        if (ngx_accept_disabled > 0) {
            ngx_accept_disabled--;

        } else {
            if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
                return NGX_ERROR;
            }

            if (ngx_accept_mutex_held) {
                accept_lock = 1;

            } else if (timer == NGX_TIMER_INFINITE
                       || timer > ngx_accept_mutex_delay)
            {
                timer = ngx_accept_mutex_delay;
                expire = 0;
            }
        }
    }

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "epoll timer: %d", timer);

    events = epoll_wait(ep, event_list, nevents, timer);

    if (events == -1) {
        err = ngx_errno;
    } else {
        err = 0;
    }

    ngx_gettimeofday(&tv);
    ngx_time_update(tv.tv_sec);

    delta = ngx_elapsed_msec;
    ngx_elapsed_msec = (ngx_epoch_msec_t) tv.tv_sec * 1000
                                          + tv.tv_usec / 1000 - ngx_start_msec;

    if (timer != NGX_TIMER_INFINITE) {
        delta = ngx_elapsed_msec - delta;

        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "epoll timer: %d, delta: %d", timer, (int) delta);
    } else {
        if (events == 0) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "epoll_wait() returned no events without timeout");
            ngx_accept_mutex_unlock();
            return NGX_ERROR;
        }
    }

    if (err) {
        ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
                      cycle->log, err, "epoll_wait() failed");
        ngx_accept_mutex_unlock();
        return NGX_ERROR;
    }

    if (events > 0) {
        if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
            ngx_accept_mutex_unlock();
            return NGX_ERROR;
        } 

        lock = 1;

    } else {
        lock =0;
    }

    log = cycle->log;

    for (i = 0; i < events; i++) {
        c = event_list[i].data.ptr;

        instance = (uintptr_t) c & 1;
        c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);

        rev = c->read;

        if (c->fd == -1 || rev->instance != instance) {

            /*
             * the stale event from a file descriptor
             * that was just closed in this iteration
             */

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "epoll: stale event " PTR_FMT, c);
            continue;
        }

#if (NGX_DEBUG0)
        log = c->log ? c->log : cycle->log;
#endif

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
                       "epoll: fd:%d ev:%04X d:" PTR_FMT,
                       c->fd, event_list[i].events, event_list[i].data);

        if (event_list[i].events & (EPOLLERR|EPOLLHUP)) {
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
                           "epoll_wait() error on fd:%d ev:%04X",
                           c->fd, event_list[i].events);
        }

        if (event_list[i].events & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
            ngx_log_error(NGX_LOG_ALERT, log, 0,
                          "strange epoll_wait() events fd:%d ev:%04X",
                          c->fd, event_list[i].events);
        }

        wev = c->write;

        if ((event_list[i].events & (EPOLLOUT|EPOLLERR|EPOLLHUP))
            && wev->active)
        {
            if (ngx_threaded) {
                wev->posted_ready = 1;
                ngx_post_event(wev);

            } else {
                wev->ready = 1;

                if (!ngx_accept_mutex_held) {
                    wev->event_handler(wev);

                } else {
                    ngx_post_event(wev);
                }
            }
        }

        /*
         * EPOLLIN must be handled after EPOLLOUT because we use
         * the optimization to avoid the unnecessary mutex locking/unlocking
         * if the accept event is the last one.
         */

        if ((event_list[i].events & (EPOLLIN|EPOLLERR|EPOLLHUP))
            && rev->active)
        {
            if (ngx_threaded && !rev->accept) {
                rev->posted_ready = 1;

                ngx_post_event(rev);

                continue;
            }

            rev->ready = 1;

            if (!ngx_threaded && !ngx_accept_mutex_held) {
                rev->event_handler(rev);

            } else if (!rev->accept) {
                ngx_post_event(rev);

            } else if (ngx_accept_disabled <= 0) {

                ngx_mutex_unlock(ngx_posted_events_mutex);

                rev->event_handler(rev);

                if (ngx_accept_disabled > 0) {
                    ngx_accept_mutex_unlock();
                    accept_lock = 0;
                }

                if (i + 1 == events) {
                    lock = 0;
                    break;
                }

                if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
                    if (accept_lock) {
                        ngx_accept_mutex_unlock();
                    }
                    return NGX_ERROR;
                }
            }
        }
    }

    if (accept_lock) {
        ngx_accept_mutex_unlock();
    }

    if (lock) {
        ngx_mutex_unlock(ngx_posted_events_mutex);
    }

    if (expire && delta) {
        ngx_event_expire_timers((ngx_msec_t) delta);
    }

    if (ngx_posted_events) {
        if (ngx_threaded) {
            ngx_wakeup_worker_thread(cycle);

        } else {
            ngx_event_process_posted(cycle);
        }
    }

    return NGX_OK;
}
Exemple #4
0
static ngx_int_t
ngx_poll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
    int                 ready, revents;
    ngx_err_t           err;
    ngx_int_t           i, nready;
    ngx_uint_t          found, level;
    ngx_event_t        *ev, **queue;
    ngx_connection_t   *c;

    /* NGX_TIMER_INFINITE == INFTIM */

#if (NGX_DEBUG0)
    if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
        for (i = 0; i < nevents; i++) {
            ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "poll: %d: fd:%d ev:%04Xd",
                           i, event_list[i].fd, event_list[i].events);
        }
    }
#endif

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "poll timer: %M", timer);

    ready = poll(event_list, (u_int) nevents, (int) timer);

    if (ready == -1) {
        err = ngx_errno;
    } else {
        err = 0;
    }

    if (flags & NGX_UPDATE_TIME) {
        ngx_time_update(0, 0);
    }

    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "poll ready %d of %d", ready, nevents);

    if (err) {
        if (err == NGX_EINTR) {

            if (ngx_event_timer_alarm) {
                ngx_event_timer_alarm = 0;
                return NGX_OK;
            }

            level = NGX_LOG_INFO;

        } else {
            level = NGX_LOG_ALERT;
        }

        ngx_log_error(level, cycle->log, err, "poll() failed");
        return NGX_ERROR;
    }

    if (ready == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "poll() returned no events without timeout");
        return NGX_ERROR;
    }

    ngx_mutex_lock(ngx_posted_events_mutex);

    nready = 0;

    for (i = 0; i < nevents && ready; i++) {

        revents = event_list[i].revents;

#if 1
        ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "poll: %d: fd:%d ev:%04Xd rev:%04Xd",
                       i, event_list[i].fd, event_list[i].events, revents);
#else
        if (revents) {
            ngx_log_debug4(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "poll: %d: fd:%d ev:%04Xd rev:%04Xd",
                           i, event_list[i].fd, event_list[i].events, revents);
        }
#endif

        if (revents & POLLNVAL) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "poll() error fd:%d ev:%04Xd rev:%04Xd",
                          event_list[i].fd, event_list[i].events, revents);
        }

        if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "strange poll() events fd:%d ev:%04Xd rev:%04Xd",
                          event_list[i].fd, event_list[i].events, revents);
        }

        if (event_list[i].fd == -1) {
            /*
             * the disabled event, a workaround for our possible bug,
             * see the comment below
             */
            continue;
        }

        c = ngx_cycle->files[event_list[i].fd];

        if (c->fd == -1) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "unexpected event");

            /*
             * it is certainly our fault and it should be investigated,
             * in the meantime we disable this event to avoid a CPU spinning
             */

            if (i == nevents - 1) {
                nevents--;
            } else {
                event_list[i].fd = -1;
            }

            continue;
        }

        if ((revents & (POLLERR|POLLHUP|POLLNVAL))
             && (revents & (POLLIN|POLLOUT)) == 0)
        {
            /*
             * if the error events were returned without POLLIN or POLLOUT,
             * then add these flags to handle the events at least in one
             * active handler
             */

            revents |= POLLIN|POLLOUT;
        }

        found = 0;

        if (revents & POLLIN) {
            found = 1;

            ev = c->read;

            if ((flags & NGX_POST_THREAD_EVENTS) && !ev->accept) {
                ev->posted_ready = 1;

            } else {
                ev->ready = 1;
            }

            queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events:
                                                   &ngx_posted_events);
            ngx_locked_post_event(ev, queue);
        }

        if (revents & POLLOUT) {
            found = 1;
            ev = c->write;

            if (flags & NGX_POST_THREAD_EVENTS) {
                ev->posted_ready = 1;

            } else {
                ev->ready = 1;
            }

            ngx_locked_post_event(ev, &ngx_posted_events);
        }

        if (found) {
            ready--;
            continue;
        }
    }

    ngx_mutex_unlock(ngx_posted_events_mutex);

    if (ready != 0) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "poll ready != events");
    }

    return nready;
}
Exemple #5
0
int ngx_devpoll_process_events(ngx_cycle_t *cycle)
{
    int                 events;
    ngx_int_t           i;
    ngx_uint_t          j, lock, accept_lock, expire;
    size_t              n;
    ngx_msec_t          timer;
    ngx_err_t           err;
    ngx_cycle_t       **old_cycle;
    ngx_event_t        *rev, *wev;
    ngx_connection_t   *c;
    ngx_epoch_msec_t    delta;
    struct dvpoll       dvp;
    struct timeval      tv;

    for ( ;; )
    {
        timer = ngx_event_find_timer();

        if (timer != 0)
        {
            break;
        }

        ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "devpoll expired timer");

        ngx_event_expire_timers((ngx_msec_t)
                                (ngx_elapsed_msec - ngx_old_elapsed_msec));
    }

    /* NGX_TIMER_INFINITE == INFTIM */

    if (timer == NGX_TIMER_INFINITE)
    {
        expire = 0;

    }
    else
    {
        expire = 1;
    }

    ngx_old_elapsed_msec = ngx_elapsed_msec;
    accept_lock = 0;

    if (ngx_accept_mutex)
    {
        if (ngx_accept_disabled > 0)
        {
            ngx_accept_disabled--;

        }
        else
        {
            if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR)
            {
                return NGX_ERROR;
            }

            if (ngx_accept_mutex_held)
            {
                accept_lock = 1;

            }
            else if (timer == NGX_TIMER_INFINITE
                     || timer > ngx_accept_mutex_delay)
            {
                timer = ngx_accept_mutex_delay;
                expire = 0;
            }
        }
    }

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "devpoll timer: %d", timer);

    if (nchanges)
    {
        n = nchanges * sizeof(struct pollfd);
        if (write(dp, change_list, n) != (ssize_t) n)
        {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "write(/dev/poll) failed");
            ngx_accept_mutex_unlock();
            return NGX_ERROR;
        }
    }

    dvp.dp_fds = event_list;
    dvp.dp_nfds = nevents;
    dvp.dp_timeout = timer;
    events = ioctl(dp, DP_POLL, &dvp);

    if (events == -1)
    {
        err = ngx_errno;
    }
    else
    {
        err = 0;
    }

    nchanges = 0;

    ngx_gettimeofday(&tv);
    ngx_time_update(tv.tv_sec);

    delta = ngx_elapsed_msec;
    ngx_elapsed_msec = (ngx_epoch_msec_t) tv.tv_sec * 1000
                       + tv.tv_usec / 1000 - ngx_start_msec;

    if (err)
    {
        ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
                      cycle->log, err, "ioctl(DP_POLL) failed");
        ngx_accept_mutex_unlock();
        return NGX_ERROR;
    }

    if (timer != NGX_TIMER_INFINITE)
    {
        delta = ngx_elapsed_msec - delta;

        ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "devpoll timer: %d, delta: %d", timer, (int) delta);
    }
    else
    {
        if (events == 0)
        {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "ioctl(DP_POLL) returned no events without timeout");
            ngx_accept_mutex_unlock();
            return NGX_ERROR;
        }
    }

    if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR)
    {
        ngx_accept_mutex_unlock();
        return NGX_ERROR;
    }

    lock = 1;

    for (i = 0; i < events; i++)
    {
        c = &ngx_cycle->connections[event_list[i].fd];

        if (c->fd == -1)
        {
            old_cycle = ngx_old_cycles.elts;
            for (j = 0; j < ngx_old_cycles.nelts; j++)
            {
                if (old_cycle[j] == NULL)
                {
                    continue;
                }
                c = &old_cycle[j]->connections[event_list[i].fd];
                if (c->fd != -1)
                {
                    break;
                }
            }
        }

        if (c->fd == -1)
        {
            ngx_log_error(NGX_LOG_EMERG, cycle->log, 0, "unknown cycle");
            exit(1);
        }

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "devpoll: fd:%d, ev:%04X, rev:%04X",
                       event_list[i].fd,
                       event_list[i].events, event_list[i].revents);

        if (event_list[i].revents & (POLLERR|POLLHUP|POLLNVAL))
        {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "ioctl(DP_POLL) error fd:%d ev:%04X rev:%04X",
                          event_list[i].fd,
                          event_list[i].events, event_list[i].revents);
        }

        if (event_list[i].revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL))
        {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "strange ioctl(DP_POLL) events "
                          "fd:%d ev:%04X rev:%04X",
                          event_list[i].fd,
                          event_list[i].events, event_list[i].revents);
        }

        wev = c->write;

        if ((event_list[i].events & (POLLOUT|POLLERR|POLLHUP)) && wev->active)
        {
            wev->ready = 1;

            if (!ngx_threaded && !ngx_accept_mutex_held)
            {
                wev->event_handler(wev);

            }
            else
            {
                ngx_post_event(wev);
            }
        }

        /*
         * POLLIN must be handled after POLLOUT because we use
         * the optimization to avoid the unnecessary mutex locking/unlocking
         * if the accept event is the last one.
         */

        rev = c->read;

        if ((event_list[i].events & (POLLIN|POLLERR|POLLHUP)) && rev->active)
        {
            rev->ready = 1;

            if (!ngx_threaded && !ngx_accept_mutex_held)
            {
                rev->event_handler(rev);

            }
            else if (!rev->accept)
            {
                ngx_post_event(rev);

            }
            else if (ngx_accept_disabled <= 0)
            {
                ngx_mutex_unlock(ngx_posted_events_mutex);

                c->read->event_handler(rev);

                if (ngx_accept_disabled > 0)
                {
                    ngx_accept_mutex_unlock();
                    accept_lock = 0;
                }

                if (i + 1 == events)
                {
                    lock = 0;
                    break;
                }

                if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR)
                {
                    if (accept_lock)
                    {
                        ngx_accept_mutex_unlock();
                    }
                    return NGX_ERROR;
                }
            }
        }
    }

    if (accept_lock)
    {
        ngx_accept_mutex_unlock();
    }

    if (lock)
    {
        ngx_mutex_unlock(ngx_posted_events_mutex);
    }

    if (expire && delta)
    {
        ngx_event_expire_timers((ngx_msec_t) delta);
    }

    if (!ngx_threaded)
    {
        ngx_event_process_posted(cycle);
    }

    return NGX_OK;
}
static ngx_int_t
ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
    ngx_uint_t flags)
{
    int                ready, nready;
    ngx_err_t          err;
    ngx_uint_t         i, found;
    ngx_event_t       *ev, **queue;
    struct timeval     tv, *tp;
    ngx_connection_t  *c;

    if (max_fd == -1) {
        for (i = 0; i < nevents; i++) {
            c = event_index[i]->data;
            if (max_fd < c->fd) {
                max_fd = c->fd;
            }
        }

        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "change max_fd: %d", max_fd);
    }

#if (NGX_DEBUG)
    if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
        for (i = 0; i < nevents; i++) {
            ev = event_index[i];
            c = ev->data;
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "select event: fd:%d wr:%d", c->fd, ev->write);
        }

        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "max_fd: %d", max_fd);
    }
#endif

    if (timer == NGX_TIMER_INFINITE) {
        tp = NULL;

    } else {
        tv.tv_sec = (long) (timer / 1000);
        tv.tv_usec = (long) ((timer % 1000) * 1000);
        tp = &tv;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "select timer: %M", timer);

    work_read_fd_set = master_read_fd_set;
    work_write_fd_set = master_write_fd_set;

    ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);

    err = (ready == -1) ? ngx_errno : 0;

    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
        ngx_time_update();
    }

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "select ready %d", ready);

    if (err) {
        ngx_uint_t  level;

        if (err == NGX_EINTR) {

            if (ngx_event_timer_alarm) {
                ngx_event_timer_alarm = 0;
                return NGX_OK;
            }

            level = NGX_LOG_INFO;

        } else {
            level = NGX_LOG_ALERT;
        }

        ngx_log_error(level, cycle->log, err, "select() failed");

        if (err == NGX_EBADF) {
            ngx_select_repair_fd_sets(cycle);
        }

        return NGX_ERROR;
    }

    if (ready == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "select() returned no events without timeout");
        return NGX_ERROR;
    }

    ngx_mutex_lock(ngx_posted_events_mutex);

    nready = 0;

    for (i = 0; i < nevents; i++) {
        ev = event_index[i];
        c = ev->data;
        found = 0;

        if (ev->write) {
            if (FD_ISSET(c->fd, &work_write_fd_set)) {
                found = 1;
                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "select write %d", c->fd);
            }

        } else {
            if (FD_ISSET(c->fd, &work_read_fd_set)) {
                found = 1;
                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "select read %d", c->fd);
            }
        }

        if (found) {
            ev->ready = 1;

            queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events:
                                                   &ngx_posted_events);
            ngx_locked_post_event(ev, queue);

            nready++;
        }
    }

    ngx_mutex_unlock(ngx_posted_events_mutex);

    if (ready != nready) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "select ready != events: %d:%d", ready, nready);

        ngx_select_repair_fd_sets(cycle);
    }

    return NGX_OK;
}
Exemple #7
0
void
ngx_close_connection(ngx_connection_t *c)
{
    ngx_err_t     err;
    ngx_uint_t    log_error, level;
    ngx_socket_t  fd;

    if (c->multiplexed != 1 && c->fd == -1) {
        ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
        return;
    }

    if (c->read->timer_set) {
        ngx_del_timer(c->read);
    }

    if (c->write->timer_set) {
        ngx_del_timer(c->write);
    }

    if (c->multiplexed != 1) {
      if (ngx_del_conn) {
          ngx_del_conn(c, NGX_CLOSE_EVENT);

      } else {
          if (c->read->active || c->read->disabled) {
              ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
          }

          if (c->write->active || c->write->disabled) {
              ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
          }
      }
    }

#if (NGX_THREADS)

    /*
     * we have to clean the connection information before the closing
     * because another thread may reopen the same file descriptor
     * before we clean the connection
     */

    ngx_mutex_lock(ngx_posted_events_mutex);

    if (c->read->prev) {
        ngx_delete_posted_event(c->read);
    }

    if (c->write->prev) {
        ngx_delete_posted_event(c->write);
    }

    c->read->closed = 1;
    c->write->closed = 1;

    if (c->single_connection) {
        ngx_unlock(&c->lock);
        c->read->locked = 0;
        c->write->locked = 0;
    }

    ngx_mutex_unlock(ngx_posted_events_mutex);

#else

    if (c->read->prev) {
        ngx_delete_posted_event(c->read);
    }

    if (c->write->prev) {
        ngx_delete_posted_event(c->write);
    }

    c->read->closed = 1;
    c->write->closed = 1;

#endif

    ngx_reusable_connection(c, 0);

    log_error = c->log_error;

    ngx_free_connection(c);

    fd = c->fd;
    c->fd = (ngx_socket_t) -1;

    if (c->multiplexed != 1 && ngx_close_socket(fd) == -1) {

        err = ngx_socket_errno;

        if (err == NGX_ECONNRESET || err == NGX_ENOTCONN) {

            switch (log_error) {

            case NGX_ERROR_INFO:
                level = NGX_LOG_INFO;
                break;

            case NGX_ERROR_ERR:
                level = NGX_LOG_ERR;
                break;

            default:
                level = NGX_LOG_CRIT;
            }

        } else {
            level = NGX_LOG_CRIT;
        }

        /* we use ngx_cycle->log because c->log was in c->pool */

        ngx_log_error(level, ngx_cycle->log, err,
                      ngx_close_socket_n " %d failed", fd);
    }
}
Exemple #8
0
ngx_int_t
ngx_devpoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
    ngx_uint_t flags)
{
    int                 events, revents, rc;
    size_t              n;
    ngx_fd_t            fd;
    ngx_err_t           err;
    ngx_int_t           i;
    ngx_uint_t          level;
    ngx_event_t        *rev, *wev, **queue;
    ngx_connection_t   *c;
    struct pollfd       pfd;
    struct dvpoll       dvp;

    /* NGX_TIMER_INFINITE == INFTIM */

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "devpoll timer: %M", timer);

    if (nchanges) {
        n = nchanges * sizeof(struct pollfd);
        if (write(dp, change_list, n) != (ssize_t) n) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                          "write(/dev/poll) failed");
            return NGX_ERROR;
        }

        nchanges = 0;
    }

    dvp.dp_fds = event_list;
    dvp.dp_nfds = (int) nevents;
    dvp.dp_timeout = timer;
    events = ioctl(dp, DP_POLL, &dvp);

    if (events == -1) {
        err = ngx_errno;
    } else {
        err = 0;
    }

    if (flags & NGX_UPDATE_TIME) {
        ngx_time_update(0, 0);
    }

    if (err) {
        if (err == NGX_EINTR) {

            if (ngx_event_timer_alarm) {
                ngx_event_timer_alarm = 0;
                return NGX_OK;
            }

            level = NGX_LOG_INFO;

        } else {
            level = NGX_LOG_ALERT;
        }

        ngx_log_error(level, cycle->log, err, "ioctl(DP_POLL) failed");
        return NGX_ERROR;
    }

    if (events == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "ioctl(DP_POLL) returned no events without timeout");
        return NGX_ERROR;
    }

    ngx_mutex_lock(ngx_posted_events_mutex);

    for (i = 0; i < events; i++) {

        fd = event_list[i].fd;
        revents = event_list[i].revents;

        c = ngx_cycle->files[fd];

        if (c == NULL || c->fd == -1) {

            pfd.fd = fd;
            pfd.events = 0;
            pfd.revents = 0;

            rc = ioctl(dp, DP_ISPOLLED, &pfd);

            switch (rc) {

            case -1:
                ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                    "ioctl(DP_ISPOLLED) failed for socket %d, event",
                    fd, revents);
                break;

            case 0:
                ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                    "phantom event %04Xd for closed and removed socket %d",
                    revents, fd);
                break;

            default:
                ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                    "unexpected event %04Xd for closed and removed socket %d, ",
                    "ioctl(DP_ISPOLLED) returned rc:%d, fd:%d, event %04Xd",
                    revents, fd, rc, pfd.fd, pfd.revents);

                pfd.fd = fd;
                pfd.events = POLLREMOVE;
                pfd.revents = 0;

                if (write(dp, &pfd, sizeof(struct pollfd))
                    != (ssize_t) sizeof(struct pollfd))
                {
                    ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                                  "write(/dev/poll) for %d failed, fd");
                }

                if (close(fd) == -1) {
                    ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                                  "close(%d) failed", fd);
                }

                break;
            }

            continue;
        }

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "devpoll: fd:%d, ev:%04Xd, rev:%04Xd",
                       fd, event_list[i].events, revents);

        if (revents & (POLLERR|POLLHUP|POLLNVAL)) {
            ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                          "ioctl(DP_POLL) error fd:%d ev:%04Xd rev:%04Xd",
                          fd, event_list[i].events, revents);
        }

        if (revents & ~(POLLIN|POLLOUT|POLLERR|POLLHUP|POLLNVAL)) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "strange ioctl(DP_POLL) events "
                          "fd:%d ev:%04Xd rev:%04Xd",
                          fd, event_list[i].events, revents);
        }

        if ((revents & (POLLERR|POLLHUP|POLLNVAL))
             && (revents & (POLLIN|POLLOUT)) == 0)
        {
            /*
             * if the error events were returned without POLLIN or POLLOUT,
             * then add these flags to handle the events at least in one
             * active handler
             */

            revents |= POLLIN|POLLOUT;
        }

        rev = c->read;

        if ((revents & POLLIN) && rev->active) {

            if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
                rev->posted_ready = 1;

            } else {
                rev->ready = 1;
            }

            if (flags & NGX_POST_EVENTS) {
                queue = (ngx_event_t **) (rev->accept ?
                               &ngx_posted_accept_events : &ngx_posted_events);

                ngx_locked_post_event(rev, queue);

            } else {
                rev->handler(rev);
            }
        }

        wev = c->write;

        if ((revents & POLLOUT) && wev->active) {

            if (flags & NGX_POST_THREAD_EVENTS) {
                wev->posted_ready = 1;

            } else {
                wev->ready = 1;
            }

            if (flags & NGX_POST_EVENTS) {
                ngx_locked_post_event(wev, &ngx_posted_events);

            } else {
                wev->handler(wev);
            }
        }
    }

    ngx_mutex_unlock(ngx_posted_events_mutex);

    return NGX_OK;
}
ngx_int_t
ngx_event_thread_process_posted(ngx_cycle_t *cycle)
{
    ngx_event_t  *ev;

    for ( ;; ) {

        ev = (ngx_event_t *) ngx_posted_events;

        for ( ;; ) {

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                          "posted event %p", ev);

            if (ev == NULL) {
                return NGX_OK;
            }

            if (ngx_trylock(ev->lock) == 0) {

                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "posted event %p is busy", ev);

                ev = ev->next;
                continue;
            }

            if (ev->lock != ev->own_lock) {
                if (*(ev->own_lock)) {
                    ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                             "the own lock of the posted event %p is busy", ev);
                    ngx_unlock(ev->lock);
                    ev = ev->next;
                    continue;
                }
                *(ev->own_lock) = 1;
            }

            ngx_delete_posted_event(ev);

            ev->locked = 1;

            ev->ready |= ev->posted_ready;
            ev->timedout |= ev->posted_timedout;
            ev->pending_eof |= ev->posted_eof;
#if (NGX_HAVE_KQUEUE)
            ev->kq_errno |= ev->posted_errno;
#endif
            if (ev->posted_available) {
                ev->available = ev->posted_available;
            }

            ev->posted_ready = 0;
            ev->posted_timedout = 0;
            ev->posted_eof = 0;
#if (NGX_HAVE_KQUEUE)
            ev->posted_errno = 0;
#endif
            ev->posted_available = 0;

            ngx_mutex_unlock(ngx_posted_events_mutex);

            ev->handler(ev);

            ngx_mutex_lock(ngx_posted_events_mutex);

            if (ev->locked) {
                ngx_unlock(ev->lock);

                if (ev->lock != ev->own_lock) {
                    ngx_unlock(ev->own_lock);
                }
            }

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "posted event %p is done", ev);

            break;
        }
    }
}
static ngx_int_t
ngx_kqueue_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
    ngx_uint_t flags)
{
    int               events, n;
    ngx_int_t         i, instance;
    ngx_uint_t        level;
    ngx_err_t         err;
    ngx_event_t      *ev, **queue;
    struct timespec   ts, *tp;

    if (ngx_threaded) {
        if (ngx_kqueue_process_changes(cycle, 0) == NGX_ERROR) {
            return NGX_ERROR;
        }

        n = 0;

    } else {
        n = (int) nchanges;
        nchanges = 0;
    }

    if (timer == NGX_TIMER_INFINITE) {
        tp = NULL;

    } else {

        ts.tv_sec = timer / 1000;
        ts.tv_nsec = (timer % 1000) * 1000000;

        /*
         * 64-bit Darwin kernel has the bug: kernel level ts.tv_nsec is
         * the int32_t while user level ts.tv_nsec is the long (64-bit),
         * so on the big endian PowerPC all nanoseconds are lost.
         */

#if (NGX_DARWIN_KEVENT_BUG)
        ts.tv_nsec <<= 32;
#endif

        tp = &ts;
    }

    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "kevent timer: %M, changes: %d", timer, n);

    events = kevent(ngx_kqueue, change_list, n, event_list, (int) nevents, tp);

    err = (events == -1) ? ngx_errno : 0;

    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
        ngx_time_update();
    }

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "kevent events: %d", events);

    if (err) {
        if (err == NGX_EINTR) {

            if (ngx_event_timer_alarm) {
                ngx_event_timer_alarm = 0;
                return NGX_OK;
            }

            level = NGX_LOG_INFO;

        } else {
            level = NGX_LOG_ALERT;
        }

        ngx_log_error(level, cycle->log, err, "kevent() failed");
        return NGX_ERROR;
    }

    if (events == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "kevent() returned no events without timeout");
        return NGX_ERROR;
    }

    ngx_mutex_lock(ngx_posted_events_mutex);

    for (i = 0; i < events; i++) {

        ngx_kqueue_dump_event(cycle->log, &event_list[i]);

        if (event_list[i].flags & EV_ERROR) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, event_list[i].data,
                          "kevent() error on %d filter:%d flags:%04Xd",
                          event_list[i].ident, event_list[i].filter,
                          event_list[i].flags);
            continue;
        }

#if (NGX_HAVE_TIMER_EVENT)

        if (event_list[i].filter == EVFILT_TIMER) {
            ngx_time_update();
            continue;
        }

#endif

        ev = (ngx_event_t *) event_list[i].udata;

        switch (event_list[i].filter) {

        case EVFILT_READ:
        case EVFILT_WRITE:

            instance = (uintptr_t) ev & 1;
            ev = (ngx_event_t *) ((uintptr_t) ev & (uintptr_t) ~1);

            if (ev->closed || ev->instance != instance) {

                /*
                 * the stale event from a file descriptor
                 * that was just closed in this iteration
                 */

                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "kevent: stale event %p", ev);
                continue;
            }

            if (ev->log && (ev->log->log_level & NGX_LOG_DEBUG_CONNECTION)) {
                ngx_kqueue_dump_event(ev->log, &event_list[i]);
            }

            if (ev->oneshot) {
                ev->active = 0;
            }

#if (NGX_THREADS)

            if ((flags & NGX_POST_THREAD_EVENTS) && !ev->accept) {
                ev->posted_ready = 1;
                ev->posted_available = event_list[i].data;

                if (event_list[i].flags & EV_EOF) {
                    ev->posted_eof = 1;
                    ev->posted_errno = event_list[i].fflags;
                }

                ngx_locked_post_event(ev, &ngx_posted_events);

                continue;
            }

#endif

            ev->available = event_list[i].data;

            if (event_list[i].flags & EV_EOF) {
                ev->pending_eof = 1;
                ev->kq_errno = event_list[i].fflags;
            }

            ev->ready = 1;

            break;

        case EVFILT_VNODE:
            ev->kq_vnode = 1;

            break;

        case EVFILT_AIO:
            ev->complete = 1;
            ev->ready = 1;

            break;

        default:
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "unexpected kevent() filter %d",
                          event_list[i].filter);
            continue;
        }

        if (flags & NGX_POST_EVENTS) {
            queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events:
                                                   &ngx_posted_events);
            ngx_locked_post_event(ev, queue);

            continue;
        }

        ev->handler(ev);
    }

    ngx_mutex_unlock(ngx_posted_events_mutex);

    return NGX_OK;
}
Exemple #11
0
ngx_int_t ngx_event_busy_unlock(ngx_event_busy_lock_t *bl,
                                ngx_event_busy_lock_ctx_t *ctx)
{
    ngx_event_t                *ev;
    ngx_event_busy_lock_ctx_t  *wakeup;

    if (ngx_mutex_lock(bl->mutex) == NGX_ERROR)
    {
        return NGX_ERROR;
    }

    if (bl->events)
    {
        wakeup = bl->events;
        bl->events = bl->events->next;

    }
    else
    {
        wakeup = NULL;
        bl->busy--;
    }

    /*
     * MP: all ctx's and their queue must be in shared memory,
     *     each ctx has pid to wake up
     */

    if (wakeup == NULL)
    {
        ngx_mutex_unlock(bl->mutex);
        return NGX_OK;
    }

    if (ctx->md5)
    {
        for (wakeup = bl->events; wakeup; wakeup = wakeup->next)
        {
            if (wakeup->md5 == NULL || wakeup->slot != ctx->slot)
            {
                continue;
            }

            wakeup->handler = ngx_event_busy_lock_posted_handler;
            wakeup->cache_updated = 1;

            ev = wakeup->event;

            if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR)
            {
                return NGX_ERROR;
            }

            ngx_post_event(ev);

            ngx_mutex_unlock(ngx_posted_events_mutex);
        }

        ngx_mutex_unlock(bl->mutex);

    }
    else
    {
        bl->waiting--;

        ngx_mutex_unlock(bl->mutex);

        wakeup->handler = ngx_event_busy_lock_posted_handler;
        wakeup->locked = 1;

        ev = wakeup->event;

        if (ev->timer_set)
        {
            ngx_del_timer(ev);
        }

        if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR)
        {
            return NGX_ERROR;
        }

        ngx_post_event(ev);

        ngx_mutex_unlock(ngx_posted_events_mutex);
    }

    return NGX_OK;
}
static ngx_int_t
ngx_kqueue_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
{
    ngx_int_t          rc;
#if 0
    ngx_event_t       *e;
    ngx_connection_t  *c;
#endif

    ev->active = 1;
    ev->disabled = 0;
    ev->oneshot = (flags & NGX_ONESHOT_EVENT) ? 1 : 0;

    ngx_mutex_lock(list_mutex);

#if 0

    if (ev->index < nchanges
        && ((uintptr_t) change_list[ev->index].udata & (uintptr_t) ~1)
            == (uintptr_t) ev)
    {
        if (change_list[ev->index].flags == EV_DISABLE) {

            /*
             * if the EV_DISABLE is still not passed to a kernel
             * we will not pass it
             */

            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, ev->log, 0,
                           "kevent activated: %d: ft:%i",
                           ngx_event_ident(ev->data), event);

            if (ev->index < --nchanges) {
                e = (ngx_event_t *)
                    ((uintptr_t) change_list[nchanges].udata & (uintptr_t) ~1);
                change_list[ev->index] = change_list[nchanges];
                e->index = ev->index;
            }

            ngx_mutex_unlock(list_mutex);

            return NGX_OK;
        }

        c = ev->data;

        ngx_log_error(NGX_LOG_ALERT, ev->log, 0,
                      "previous event on #%d were not passed in kernel", c->fd);

        ngx_mutex_unlock(list_mutex);

        return NGX_ERROR;
    }

#endif

    rc = ngx_kqueue_set_event(ev, event, EV_ADD|EV_ENABLE|flags);

    ngx_mutex_unlock(list_mutex);

    return rc;
}
static ngx_int_t
ngx_rtsig_process_overflow(ngx_cycle_t *cycle, ngx_msec_t timer,
    ngx_uint_t flags)
{
    int                name[2], rtsig_max, rtsig_nr, events, ready;
    size_t             len;
    ngx_err_t          err;
    ngx_uint_t         tested, n, i;
    ngx_event_t       *rev, *wev, **queue;
    ngx_connection_t  *c;
    ngx_rtsig_conf_t  *rtscf;

    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "rtsig process overflow");

    rtscf = ngx_event_get_conf(ngx_cycle->conf_ctx, ngx_rtsig_module);

    tested = 0;

    for ( ;; ) {

        n = 0;
        while (n < rtscf->overflow_events) {

            if (overflow_current == cycle->connection_n) {
                break;
            }

            c = cycle->files[overflow_current++];

            if (c == NULL || c->fd == -1) {
                continue;
            }

            events = 0;

            if (c->read->active && c->read->handler) {
                events |= POLLIN;
            }

            if (c->write->active && c->write->handler) {
                events |= POLLOUT;
            }

            if (events == 0) {
                continue;
            }

            overflow_list[n].fd = c->fd;
            overflow_list[n].events = events;
            overflow_list[n].revents = 0;
            n++;
        }

        if (n == 0) {
            break;
        }

        for ( ;; ) {
            ready = poll(overflow_list, n, 0);

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "rtsig overflow poll:%d", ready);

            if (ready == -1) {
                err = ngx_errno;
                ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
                              cycle->log, 0,
                              "poll() failed while the overflow recover");

                if (err == NGX_EINTR) {
                    continue;
                }
            }

            break;
        }

        if (ready <= 0) {
            continue;
        }

        ngx_mutex_lock(ngx_posted_events_mutex);

        for (i = 0; i < n; i++) {
            c = cycle->files[overflow_list[i].fd];

            if (c == NULL) {
                continue;
            }

            rev = c->read;

            if (rev->active
                && !rev->closed
                && rev->handler
                && (overflow_list[i].revents
                                          & (POLLIN|POLLERR|POLLHUP|POLLNVAL)))
            {
                tested++;

                if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
                    rev->posted_ready = 1;

                } else {
                    rev->ready = 1;
                }

                if (flags & NGX_POST_EVENTS) {
                    queue = (ngx_event_t **) (rev->accept ?
                               &ngx_posted_accept_events : &ngx_posted_events);

                    ngx_locked_post_event(rev, queue);

                } else {
                    rev->handler(rev);
                }
            }

            wev = c->write;

            if (wev->active
                && !wev->closed
                && wev->handler
                && (overflow_list[i].revents
                                         & (POLLOUT|POLLERR|POLLHUP|POLLNVAL)))
            {
                tested++;

                if (flags & NGX_POST_THREAD_EVENTS) {
                    wev->posted_ready = 1;

                } else {
                    wev->ready = 1;
                }

                if (flags & NGX_POST_EVENTS) {
                    ngx_locked_post_event(wev, &ngx_posted_events);

                } else {
                    wev->handler(wev);
                }
            }
        }

        ngx_mutex_unlock(ngx_posted_events_mutex);

        if (tested >= rtscf->overflow_test) {

            if (ngx_linux_rtsig_max) {

                /*
                 * Check the current rt queue length to prevent
                 * the new overflow.
                 *
                 * learn the "/proc/sys/kernel/rtsig-max" value because
                 * it can be changed since the last checking
                 */

                name[0] = CTL_KERN;
                name[1] = KERN_RTSIGMAX;
                len = sizeof(rtsig_max);

                if (sysctl(name, 2, &rtsig_max, &len, NULL, 0) == -1) {
                    ngx_log_error(NGX_LOG_ALERT, cycle->log, errno,
                                  "sysctl(KERN_RTSIGMAX) failed");
                    return NGX_ERROR;
                }

                /* name[0] = CTL_KERN; */
                name[1] = KERN_RTSIGNR;
                len = sizeof(rtsig_nr);

                if (sysctl(name, 2, &rtsig_nr, &len, NULL, 0) == -1) {
                    ngx_log_error(NGX_LOG_ALERT, cycle->log, errno,
                                  "sysctl(KERN_RTSIGNR) failed");
                    return NGX_ERROR;
                }

                /*
                 * drain the rt signal queue if the /"proc/sys/kernel/rtsig-nr"
                 * is bigger than
                 *    "/proc/sys/kernel/rtsig-max" / "rtsig_overflow_threshold"
                 */

                if (rtsig_max / (int) rtscf->overflow_threshold < rtsig_nr) {
                    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                                   "rtsig queue state: %d/%d",
                                   rtsig_nr, rtsig_max);
                    while (ngx_rtsig_process_events(cycle, 0, flags) == NGX_OK)
                    {
                        /* void */
                    }
                }

            } else {

                /*
                 * Linux has not KERN_RTSIGMAX since 2.6.6-mm2
                 * so drain the rt signal queue unconditionally
                 */

                while (ngx_rtsig_process_events(cycle, 0, flags) == NGX_OK) {
                    /* void */
                }
            }

            tested = 0;
        }
    }

    if (flags & NGX_UPDATE_TIME) {
        ngx_time_update();
    }

    ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                  "rt signal queue overflow recovered");

    overflow = 0;
    ngx_event_actions.process_events = ngx_rtsig_process_events;

    return NGX_OK;
}
Exemple #14
0
void ngx_close_connection(ngx_connection_t *c)
{
    ngx_socket_t  fd;

    if (c->pool == NULL)
    {
        ngx_log_error(NGX_LOG_ALERT, c->log, 0, "connection already closed");
        return;
    }

#if (NGX_OPENSSL)

    if (c->ssl)
    {
        if (ngx_ssl_shutdown(c) == NGX_AGAIN)
        {
            c->read->event_handler = ngx_ssl_close_handler;
            c->write->event_handler = ngx_ssl_close_handler;
            return;
        }
    }

#endif

    if (c->read->timer_set)
    {
        ngx_del_timer(c->read);
    }

    if (c->write->timer_set)
    {
        ngx_del_timer(c->write);
    }

    if (ngx_del_conn)
    {
        ngx_del_conn(c, NGX_CLOSE_EVENT);

    }
    else
    {
        if (c->read->active || c->read->disabled)
        {
            ngx_del_event(c->read, NGX_READ_EVENT, NGX_CLOSE_EVENT);
        }

        if (c->write->active || c->write->disabled)
        {
            ngx_del_event(c->write, NGX_WRITE_EVENT, NGX_CLOSE_EVENT);
        }
    }

#if (NGX_THREADS)

    /*
     * we have to clean the connection information before the closing
     * because another thread may reopen the same file descriptor
     * before we clean the connection
     */

    if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_OK)
    {

        if (c->read->prev)
        {
            ngx_delete_posted_event(c->read);
        }

        if (c->write->prev)
        {
            ngx_delete_posted_event(c->write);
        }

        c->read->closed = 1;
        c->write->closed = 1;

        if (c->single_connection)
        {
            ngx_unlock(&c->lock);
            c->read->locked = 0;
            c->write->locked = 0;
        }

        ngx_mutex_unlock(ngx_posted_events_mutex);
    }

#else

    if (c->read->prev)
    {
        ngx_delete_posted_event(c->read);
    }

    if (c->write->prev)
    {
        ngx_delete_posted_event(c->write);
    }

    c->read->closed = 1;
    c->write->closed = 1;

#endif

    fd = c->fd;
    c->fd = (ngx_socket_t) -1;
    c->data = NULL;

    ngx_destroy_pool(c->pool);

    if (ngx_close_socket(fd) == -1)
    {

        /* we use ngx_cycle->log because c->log was in c->pool */

        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
                      ngx_close_socket_n " failed");
    }
}
static ngx_int_t
ngx_select_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
    ngx_uint_t flags)
{
    int                ready, nready;
    ngx_err_t          err;
    ngx_uint_t         i, found;
    ngx_event_t       *ev, **queue;
    struct timeval     tv, *tp;
    ngx_connection_t  *c;

#if (NGX_DEBUG)
    if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
        for (i = 0; i < nevents; i++) {
            ev = event_index[i];
            c = ev->data;
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "select event: fd:%d wr:%d", c->fd, ev->write);
        }
    }
#endif

    if (timer == NGX_TIMER_INFINITE) {
        tp = NULL;

    } else {
        tv.tv_sec = (long) (timer / 1000);
        tv.tv_usec = (long) ((timer % 1000) * 1000);
        tp = &tv;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "select timer: %M", timer);

    work_read_fd_set = master_read_fd_set;
    work_write_fd_set = master_write_fd_set;

    if (max_read || max_write) {
        ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp);

    } else {

        /*
         * Winsock select() requires that at least one descriptor set must be
         * be non-null, and any non-null descriptor set must contain at least
         * one handle to a socket.  Otherwise select() returns WSAEINVAL.
         */

        ngx_msleep(timer);

        ready = 0;
    }

    err = (ready == -1) ? ngx_socket_errno : 0;

    if (flags & NGX_UPDATE_TIME) {
        ngx_time_update();
    }

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "select ready %d", ready);

    if (err) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed");

        if (err == WSAENOTSOCK) {
            ngx_select_repair_fd_sets(cycle);
        }

        return NGX_ERROR;
    }

    if (ready == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "select() returned no events without timeout");
        return NGX_ERROR;
    }

    ngx_mutex_lock(ngx_posted_events_mutex);

    nready = 0;

    for (i = 0; i < nevents; i++) {
        ev = event_index[i];
        c = ev->data;
        found = 0;

        if (ev->write) {
            if (FD_ISSET(c->fd, &work_write_fd_set)) {
                found = 1;
                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "select write %d", c->fd);
            }

        } else {
            if (FD_ISSET(c->fd, &work_read_fd_set)) {
                found = 1;
                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "select read %d", c->fd);
            }
        }

        if (found) {
            ev->ready = 1;

            queue = (ngx_event_t **) (ev->accept ? &ngx_posted_accept_events:
                                                   &ngx_posted_events);
            ngx_locked_post_event(ev, queue);

            nready++;
        }
    }

    ngx_mutex_unlock(ngx_posted_events_mutex);

    if (ready != nready) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "select ready != events: %d:%d", ready, nready);

        ngx_select_repair_fd_sets(cycle);
    }

    return NGX_OK;
}
Exemple #16
0
ngx_http_cache_t *ngx_http_cache_alloc(ngx_http_cache_hash_t *hash,
                                       ngx_http_cache_t *cache,
                                       ngx_http_cleanup_t *cleanup,
                                       ngx_str_t *key, uint32_t crc,
                                       ngx_str_t *value, ngx_log_t *log)
{
    time_t             old;
    ngx_uint_t         i;
    ngx_http_cache_t  *c;

    old = ngx_cached_time + 1;

    c = hash->elts + crc % hash->hash * hash->nelts;

    if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) {
        return (void *) NGX_ERROR;
    }

    if (cache == NULL) {

        /* allocate a new entry */

        for (i = 0; i < hash->nelts; i++) {
            if (c[i].refs > 0) {
                /* a busy entry */
                continue;
            }

            if (c[i].key.len == 0) {
                /* a free entry is found */
                cache = &c[i];
                break;
            }

            /* looking for the oldest cache entry */

            if (old > c[i].accessed) {

                old = c[i].accessed;
                cache = &c[i];
            }
        }

        if (cache == NULL) {
            ngx_mutex_unlock(&hash->mutex);
            return NULL;
        }

        ngx_http_cache_free(cache, key, value, log);

        if (cache->key.data == NULL) {
            cache->key.data = ngx_alloc(key->len, log);
            if (cache->key.data == NULL) {
                ngx_http_cache_free(cache, NULL, NULL, log);
                ngx_mutex_unlock(&hash->mutex);
                return NULL;
            }
        }

        cache->key.len = key->len;
        ngx_memcpy(cache->key.data, key->data, key->len);

    } else if (value) {
        ngx_http_cache_free(cache, key, value, log);
    }

    if (value) {
        if (cache->data.value.data == NULL) {
            cache->data.value.data = ngx_alloc(value->len, log);
            if (cache->data.value.data == NULL) {
                ngx_http_cache_free(cache, NULL, NULL, log);
                ngx_mutex_unlock(&hash->mutex);
                return NULL;
            }
        }

        cache->data.value.len = value->len;
        ngx_memcpy(cache->data.value.data, value->data, value->len);
    }

    cache->crc = crc;
    cache->key.len = key->len;

    cache->refs = 1;
    cache->count = 0;

    cache->deleted = 0;
    cache->expired = 0;
    cache->memory = 0;
    cache->mmap = 0;
    cache->notify = 0;

    if (cleanup) {
        cleanup->data.cache.hash = hash;
        cleanup->data.cache.cache = cache;
        cleanup->valid = 1;
        cleanup->cache = 1;
    }

    ngx_mutex_unlock(&hash->mutex);

    return cache;
}
static ngx_thread_value_t
ngx_worker_thread_cycle(void *data)
{
    ngx_thread_t  *thr = data;

    sigset_t          set;
    ngx_err_t         err;
    ngx_core_tls_t   *tls;
    ngx_cycle_t      *cycle;

    cycle = (ngx_cycle_t *) ngx_cycle;

    sigemptyset(&set);
    sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));

    err = ngx_thread_sigmask(SIG_BLOCK, &set, NULL);
    if (err) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
                      ngx_thread_sigmask_n " failed");
        return (ngx_thread_value_t) 1;
    }

    ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                   "thread " NGX_TID_T_FMT " started", ngx_thread_self());

    ngx_setthrtitle("worker thread");

    tls = ngx_calloc(sizeof(ngx_core_tls_t), cycle->log);
    if (tls == NULL) {
        return (ngx_thread_value_t) 1;
    }

    err = ngx_thread_set_tls(ngx_core_tls_key, tls);
    if (err != 0) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
                      ngx_thread_set_tls_n " failed");
        return (ngx_thread_value_t) 1;
    }

    ngx_mutex_lock(ngx_posted_events_mutex);

    for ( ;; ) {
        thr->state = NGX_THREAD_FREE;

        if (ngx_cond_wait(thr->cv, ngx_posted_events_mutex) == NGX_ERROR) {
            return (ngx_thread_value_t) 1;
        }

        if (ngx_terminate) {
            thr->state = NGX_THREAD_EXIT;

            ngx_mutex_unlock(ngx_posted_events_mutex);

            ngx_log_debug1(NGX_LOG_DEBUG_CORE, cycle->log, 0,
                           "thread " NGX_TID_T_FMT " is done",
                           ngx_thread_self());

            return (ngx_thread_value_t) 0;
        }

        thr->state = NGX_THREAD_BUSY;

        if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) {
            return (ngx_thread_value_t) 1;
        }

        if (ngx_event_thread_process_posted(cycle) == NGX_ERROR) {
            return (ngx_thread_value_t) 1;
        }

        if (ngx_process_changes) {
            if (ngx_process_changes(cycle, 1) == NGX_ERROR) {
                return (ngx_thread_value_t) 1;
            }
        }
    }
}
Exemple #18
0
void ngx_http_cache_lock(ngx_http_cache_hash_t *hash, ngx_http_cache_t *cache)
{
    if (ngx_mutex_lock(&hash->mutex) == NGX_ERROR) {
        return;
    }
}
/* called ngx_process_events_and_timers */
static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
    int                events;
    uint32_t           revents;
    ngx_int_t          instance, i;
    ngx_uint_t         level;
    ngx_err_t          err;
    ngx_log_t         *log;
    ngx_event_t       *rev, *wev, **queue;
    ngx_connection_t  *c;

    /* NGX_TIMER_INFINITE == INFTIM */

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "epoll timer: %M", timer);

    events = epoll_wait(ep, event_list, (int) nevents, timer);

    err = (events == -1) ? ngx_errno : 0;

    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) { /* 这里判断是否需要更新系统时间变量 ngx_current_msec */
        ngx_time_update(); /* 更新系统时间变量 ngx_current_msec */
    }

    if (err) {
        if (err == NGX_EINTR) {

            if (ngx_event_timer_alarm) {
                ngx_event_timer_alarm = 0;
                return NGX_OK;
            }

            level = NGX_LOG_INFO;

        } else {
            level = NGX_LOG_ALERT;
        }

        ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
        return NGX_ERROR;
    }

    if (events == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "epoll_wait() returned no events without timeout");
        return NGX_ERROR;
    }

    ngx_mutex_lock(ngx_posted_events_mutex);

    log = cycle->log;

    for (i = 0; i < events; i++) {
        c = event_list[i].data.ptr;

        instance = (uintptr_t) c & 1; //获取stale的标识
        c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);//获取链接的指针

        rev = c->read;
		/*如果c-fd为-1则说明fd被关闭,如果rev->instance != instance则表示当前的fd已经被重新使用过了,
		也就是说这个event已经是stale的了,所以跳过这个事件,然后进行下一个*/
        if (c->fd == -1 || rev->instance != instance) {

            /*
             * the stale event from a file descriptor
             * that was just closed in this iteration
             */

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "epoll: stale event %p", c);
            continue;
        }

#if (NGX_DEBUG0)
        log = c->log ? c->log : cycle->log;
#endif

        revents = event_list[i].events;

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, log, 0,
                       "epoll: fd:%d ev:%04XD d:%p",
                       c->fd, revents, event_list[i].data.ptr);

        if (revents & (EPOLLERR|EPOLLHUP)) {
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, log, 0,
                           "epoll_wait() error on fd:%d ev:%04XD",
                           c->fd, revents);
        }

#if 0
        if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
            ngx_log_error(NGX_LOG_ALERT, log, 0,
                          "strange epoll_wait() events fd:%d ev:%04XD",
                          c->fd, revents);
        }
#endif

        if ((revents & (EPOLLERR|EPOLLHUP))
             && (revents & (EPOLLIN|EPOLLOUT)) == 0)
        {
            /*
             * if the error events were returned without EPOLLIN or EPOLLOUT,
             * then add these flags to handle the events at least in one
             * active handler
             */

            revents |= EPOLLIN|EPOLLOUT;
        }

        if ((revents & EPOLLIN) && rev->active) { /* 这里需要判断是否connection是否激活了读事件,如果没有这里不需要进行处理 */

            if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
                rev->posted_ready = 1;

            } else {
                rev->ready = 1;
            }

            if (flags & NGX_POST_EVENTS) { /* event 是否需要POSTED */
                queue = (ngx_event_t **) (rev->accept ?
                               &ngx_posted_accept_events : &ngx_posted_events);/* 根据 accept 来判断,将事件放入到哪个事件队列 */

                ngx_locked_post_event(rev, queue);/* 将事件添加队列中*/

            } else {
                rev->handler(rev); /* 调用事件处理函数 */
            }
        }

        wev = c->write;

		/* 这里需要判断是否connection是否激活了读事件,如果没有这里不需要进行处理 
			fd本身的状态变化可能在没有关注EPOLLIN的情况下由于缓冲区的状态变化触发写事件
		*/
        if ((revents & EPOLLOUT) && wev->active) {

            if (flags & NGX_POST_THREAD_EVENTS) {
                wev->posted_ready = 1;

            } else {
                wev->ready = 1;
            }

            if (flags & NGX_POST_EVENTS) { /* 写事件只有ngx_posted_events 事件队列 */
                ngx_locked_post_event(wev, &ngx_posted_events);

            } else {
                wev->handler(wev);
            }
        }
    }

    ngx_mutex_unlock(ngx_posted_events_mutex);

    return NGX_OK;
}
Exemple #20
0
static ngx_int_t ngx_select_process_events(ngx_cycle_t *cycle)
{
  int                       ready, nready;
  ngx_uint_t                i, found, lock, expire;
  ngx_err_t                 err;
  ngx_msec_t                timer;
  ngx_event_t              *ev;
  ngx_connection_t         *c;
  ngx_epoch_msec_t          delta;
  struct timeval            tv, *tp;
#if (HAVE_SELECT_CHANGE_TIMEOUT)
  static ngx_epoch_msec_t   deltas = 0;
#endif

  for ( ;; ) {
    timer = ngx_event_find_timer();

    if (timer != 0) {
      break;
    }

    ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
             "select expired timer");

    ngx_event_expire_timers((ngx_msec_t)
                  (ngx_elapsed_msec - ngx_old_elapsed_msec));
  }

  ngx_old_elapsed_msec = ngx_elapsed_msec;

  expire = 1;

#if !(WIN32)

  if (ngx_accept_mutex) {
    if (ngx_accept_disabled > 0) {
      ngx_accept_disabled--;

    } else {
      if (ngx_trylock_accept_mutex(cycle) == NGX_ERROR) {
        return NGX_ERROR;
      }

      if (ngx_accept_mutex_held == 0
        && (timer == NGX_TIMER_INFINITE
          || timer > ngx_accept_mutex_delay))
      {
        timer = ngx_accept_mutex_delay;
        expire = 0;
      }
    }
  }

  if (max_fd == -1) {
    for (i = 0; i < nevents; i++) {
      c = event_index[i]->data;
      if (max_fd < c->fd) {
        max_fd = c->fd;
      }
    }

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
             "change max_fd: %d", max_fd);
  }

#endif

#if (NGX_DEBUG)
  if (cycle->log->log_level & NGX_LOG_DEBUG_ALL) {
    for (i = 0; i < nevents; i++) {
      ev = event_index[i];
      c = ev->data;
      ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
               "select event: fd:%d wr:%d", c->fd, ev->write);
    }

#if !(WIN32)
    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
             "max_fd: %d", max_fd);
#endif
  }
#endif

  if (timer == NGX_TIMER_INFINITE) {
    tp = NULL;
    expire = 0;

  } else {
    tv.tv_sec = timer / 1000;
    tv.tv_usec = (timer % 1000) * 1000;
    tp = &tv;
  }

  ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
           "select timer: %d", timer);

  work_read_fd_set = master_read_fd_set;
  work_write_fd_set = master_write_fd_set;

  ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
           "select read fd_set: %08X", *(int *) &work_read_fd_set);

#if (WIN32)
  ready = select(0, &work_read_fd_set, &work_write_fd_set, NULL, tp);
#else
  ready = select(max_fd + 1, &work_read_fd_set, &work_write_fd_set, NULL, tp);
#endif

  if (ready == -1) {
    err = ngx_socket_errno;
  } else {
    err = 0;
  }

#if (HAVE_SELECT_CHANGE_TIMEOUT)

  if (timer != NGX_TIMER_INFINITE) {
    delta = timer - (tv.tv_sec * 1000 + tv.tv_usec / 1000);

    /*
     * learn the real time and update the cached time
     * if the sum of the last deltas overcomes 1 second
     */

    deltas += delta;
    if (deltas > 1000) {
      ngx_gettimeofday(&tv);
      ngx_time_update(tv.tv_sec);
      deltas = tv.tv_usec / 1000;

      ngx_elapsed_msec = (ngx_epoch_msec_t) tv.tv_sec * 1000
                      + tv.tv_usec / 1000 - ngx_start_msec;
    } else {
      ngx_elapsed_msec += delta;
    }

    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
             "select timer: %d, delta: %d", timer, (int) delta);

  } else {
    delta = 0;
    ngx_gettimeofday(&tv);
    ngx_time_update(tv.tv_sec);

    ngx_elapsed_msec = (ngx_epoch_msec_t) tv.tv_sec * 1000
                      + tv.tv_usec / 1000 - ngx_start_msec;

    if (ready == 0) {
      ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
              "select() returned no events without timeout");
      ngx_accept_mutex_unlock();
      return NGX_ERROR;
    }
  }

#else /* !(HAVE_SELECT_CHANGE_TIMEOUT) */

  ngx_gettimeofday(&tv);
  ngx_time_update(tv.tv_sec);

  delta = ngx_elapsed_msec;
  ngx_elapsed_msec = (ngx_epoch_msec_t) tv.tv_sec * 1000
                      + tv.tv_usec / 1000 - ngx_start_msec;

  if (timer != NGX_TIMER_INFINITE) {
    delta = ngx_elapsed_msec - delta;

    ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
             "select timer: %d, delta: %d", timer, (int) delta);

  } else {
    if (ready == 0) {
      ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
              "select() returned no events without timeout");
      ngx_accept_mutex_unlock();
      return NGX_ERROR;
    }
  }

#endif /* HAVE_SELECT_CHANGE_TIMEOUT */

  ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
           "select ready %d", ready);

  if (err) {
#if (WIN32)
    ngx_log_error(NGX_LOG_ALERT, cycle->log, err, "select() failed");
#else
    ngx_log_error((err == NGX_EINTR) ? NGX_LOG_INFO : NGX_LOG_ALERT,
            cycle->log, err, "select() failed");
#endif
    ngx_accept_mutex_unlock();
    return NGX_ERROR;
  }


  if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
    ngx_accept_mutex_unlock();
    return NGX_ERROR;
  }

  lock = 1;
  nready = 0;

  for (i = 0; i < nevents; i++) {
    ev = event_index[i];
    c = ev->data;
    found = 0;

    if (ev->write) {
      if (FD_ISSET(c->fd, &work_write_fd_set)) {
        found = 1;
        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                 "select write %d", c->fd);
      }

    } else {
      if (FD_ISSET(c->fd, &work_read_fd_set)) {
        found = 1;
        ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                 "select read %d", c->fd);
      }
    }

    if (found) {
      ev->ready = 1;

      if (ev->oneshot) {
        if (ev->timer_set) {
          ngx_del_timer(ev);
        }

        if (ev->write) {
          ngx_select_del_event(ev, NGX_WRITE_EVENT, 0);
        } else {
          ngx_select_del_event(ev, NGX_READ_EVENT, 0);
        }
      }

      if (ev->accept) {
        ev->next = accept_events;
        accept_events = ev;
      } else {
        ngx_post_event(ev);
      }

      nready++;


    }
  }



  ev = accept_events;

  for ( ;; ) {

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
            "accept event " PTR_FMT, ev);

    if (ev == NULL) {
      break;
    }

    ngx_mutex_unlock(ngx_posted_events_mutex);

    ev->event_handler(ev);

    if (ngx_accept_disabled > 0) {
      lock = 0;
      break;
    }

    ev = ev->next;

    if (ev == NULL) {
      lock = 0;
      break;
    }

    if (ngx_mutex_lock(ngx_posted_events_mutex) == NGX_ERROR) {
      ngx_accept_mutex_unlock();
      return NGX_ERROR;
    }
  }

  ngx_accept_mutex_unlock();
  accept_events = NULL;

  if (lock) {
    ngx_mutex_unlock(ngx_posted_events_mutex);
  }

  if (ready != nready) {
    ngx_log_error(NGX_LOG_ALERT, cycle->log, 0, "select ready != events");
  }

  if (expire && delta) {
    ngx_event_expire_timers((ngx_msec_t) delta);
  }

  if (!ngx_threaded) {
    ngx_event_process_posted(cycle);
  }

  return NGX_OK;
}
static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
    int                events;
    uint32_t           revents;
    ngx_int_t          instance, i;
    ngx_uint_t         level;
    ngx_err_t          err;
    ngx_event_t       *rev, *wev, **queue;
    ngx_connection_t  *c;

    /* NGX_TIMER_INFINITE == INFTIM */

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0, "epoll timer: %M", timer);
//Here,we start to epoll wait!!!
    events = epoll_wait(ep, event_list, (int) nevents, timer);

    err = (events == -1) ? ngx_errno : 0;

    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
        ngx_time_update();
    }

    if (err) {
        if (err == NGX_EINTR) {

            if (ngx_event_timer_alarm) {
                ngx_event_timer_alarm = 0;
                return NGX_OK;
            }

            level = NGX_LOG_INFO;

        } else {
            level = NGX_LOG_ALERT;
        }

        ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
        return NGX_ERROR;
    }

    if (events == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "epoll_wait() returned no events without timeout");
        return NGX_ERROR;
    }

    ngx_mutex_lock(ngx_posted_events_mutex);

    for (i = 0; i < events; i++) {//Here,traverse all the events!!!
        c = event_list[i].data.ptr;

        instance = (uintptr_t) c & 1;
        c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);

        rev = c->read;

        if (c->fd == -1 || rev->instance != instance) {

            /*
             * the stale event from a file descriptor
             * that was just closed in this iteration
             */

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "epoll: stale event %p", c);
            continue;
        }

        revents = event_list[i].events;

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "epoll: fd:%d ev:%04XD d:%p",
                       c->fd, revents, event_list[i].data.ptr);

        if (revents & (EPOLLERR|EPOLLHUP)) {
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "epoll_wait() error on fd:%d ev:%04XD",
                           c->fd, revents);
        }

#if 0
        if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "strange epoll_wait() events fd:%d ev:%04XD",
                          c->fd, revents);
        }
#endif

        if ((revents & (EPOLLERR|EPOLLHUP)) && (revents & (EPOLLIN|EPOLLOUT)) == 0)
        {
            /*
             * if the error events were returned without EPOLLIN or EPOLLOUT,
             * then add these flags to handle the events at least in one
             * active handler
             */

            revents |= EPOLLIN|EPOLLOUT;
        }
//------------------------------------->Test Isn't  read event ready!!!
        if ((revents & EPOLLIN) && rev->active) {

            if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
                rev->posted_ready = 1;

            } else {
                rev->ready = 1;//Set we the read_event has been ready!!!
            }

            if (flags & NGX_POST_EVENTS) {//Here,If the read_event is used for accept,we should push the event to ngx_posted_accept_events queue!!!
                queue = (ngx_event_t **) (rev->accept ? &ngx_posted_accept_events : &ngx_posted_events);
                ngx_locked_post_event(rev, queue);//Here,post the readly event to ngx_posted_events list!!we will desposit it lately!!

            } else {
                rev->handler(rev);
            }
        }

        wev = c->write;
//------------------------------------->Test Isn't write event ready!!!
        if ((revents & EPOLLOUT) && wev->active) {

            if (flags & NGX_POST_THREAD_EVENTS) {
                wev->posted_ready = 1;

            } else {
                wev->ready = 1;
            }

            if (flags & NGX_POST_EVENTS) {
                ngx_locked_post_event(wev, &ngx_posted_events);//Here,we post the events!!!

            } else {
                wev->handler(wev);
            }
        }
    }

    ngx_mutex_unlock(ngx_posted_events_mutex);

    return NGX_OK;
}
/*epoll事件驱动模型的实现*/
static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
    int                events;
    uint32_t           revents;
    ngx_int_t          instance, i;
    ngx_uint_t         level;
    ngx_err_t          err;
    ngx_event_t       *rev, *wev, **queue;
    ngx_connection_t  *c;

    /* NGX_TIMER_INFINITE == INFTIM */

    ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                   "epoll timer: %M", timer);
    //一开始就是等待事件,最长等待时间为timer;nginx为事件专门用红黑树维护了一个计时器
    events = epoll_wait(ep, event_list, (int) nevents, timer);

    err = (events == -1) ? ngx_errno : 0;

    if (flags & NGX_UPDATE_TIME || ngx_event_timer_alarm) {
        ngx_time_update(); //执行一次时间更新,nginx将时间缓存到一组全局变量中,方便程序高效的获取事件
    }
    //处理wait错误
    if (err) {
        if (err == NGX_EINTR) {

            if (ngx_event_timer_alarm) {
                ngx_event_timer_alarm = 0;
                return NGX_OK;
            }

            level = NGX_LOG_INFO;

        } else {
            level = NGX_LOG_ALERT;
        }

        ngx_log_error(level, cycle->log, err, "epoll_wait() failed");
        return NGX_ERROR;
    }
    //wait返回事件数0,可能是timeout返回,也可能是非timeout返回,非timeout返回则是error
    if (events == 0) {
        if (timer != NGX_TIMER_INFINITE) {
            return NGX_OK;
        }

        ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                      "epoll_wait() returned no events without timeout");
        return NGX_ERROR;
    }

    ngx_mutex_lock(ngx_posted_events_mutex);
    //循环开始处理收到的所有事件
    for (i = 0; i < events; i++) {
        c = event_list[i].data.ptr;

        instance = (uintptr_t) c & 1;
        c = (ngx_connection_t *) ((uintptr_t) c & (uintptr_t) ~1);

        rev = c->read;

        if (c->fd == -1 || rev->instance != instance) {

            /*
             * the stale event from a file descriptor
             * that was just closed in this iteration
             */

            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "epoll: stale event %p", c);
            continue;
        }
        //取得发生一个事件
        revents = event_list[i].events;

        ngx_log_debug3(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                       "epoll: fd:%d ev:%04XD d:%p",
                       c->fd, revents, event_list[i].data.ptr);
        //记录wait的错误返回状态
        if (revents & (EPOLLERR|EPOLLHUP)) {
            ngx_log_debug2(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                           "epoll_wait() error on fd:%d ev:%04XD",
                           c->fd, revents);
        }

#if 0
        if (revents & ~(EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP)) {
            ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
                          "strange epoll_wait() events fd:%d ev:%04XD",
                          c->fd, revents);
        }
#endif
        //该事件是一个读事件,并该连接上注册的读事件是active的
        if ((revents & (EPOLLERR|EPOLLHUP))
             && (revents & (EPOLLIN|EPOLLOUT)) == 0)
        {
            /*
             * if the error events were returned without EPOLLIN or EPOLLOUT,
             * then add these flags to handle the events at least in one
             * active handler
             */

            revents |= EPOLLIN|EPOLLOUT;
        }

        if ((revents & EPOLLIN) && rev->active) {

            if ((flags & NGX_POST_THREAD_EVENTS) && !rev->accept) {
                rev->posted_ready = 1;

            } else {
                rev->ready = 1;
            }
            //事件放入到相应的队列中
            if (flags & NGX_POST_EVENTS) {
                queue = (ngx_event_t **) (rev->accept ?
                               &ngx_posted_accept_events : &ngx_posted_events);

                ngx_locked_post_event(rev, queue);

            } else {
                rev->handler(rev);
            }
        }

        wev = c->write;

        if ((revents & EPOLLOUT) && wev->active) {

            if (c->fd == -1 || wev->instance != instance) {

                /*
                 * the stale event from a file descriptor
                 * that was just closed in this iteration
                 */

                ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
                               "epoll: stale event %p", c);
                continue;
            }

            if (flags & NGX_POST_THREAD_EVENTS) {
                wev->posted_ready = 1;

            } else {
                wev->ready = 1;
            }

            if (flags & NGX_POST_EVENTS) {
                ngx_locked_post_event(wev, &ngx_posted_events);

            } else {
                wev->handler(wev);
            }
        }
    }

    ngx_mutex_unlock(ngx_posted_events_mutex);

    return NGX_OK;
}