示例#1
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;
}
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;
}
示例#3
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;
}