static ret_t _add (cherokee_fdpoll_select_t *fdp, int fd, int rw) { cherokee_fdpoll_t *nfd = FDPOLL(fdp); /* Check the fd limit */ if (cherokee_fdpoll_is_full(FDPOLL(fdp))) { PRINT_ERROR_S("win32_add: fdpoll is full !\n"); return ret_error; } fdp->select_fds[nfd->npollfds] = fd; switch (rw) { case FDPOLL_MODE_READ: FD_SET (fd, &fdp->master_rfdset); break; case FDPOLL_MODE_WRITE: FD_SET (fd, &fdp->master_wfdset); break; default: break; } if (fd > fdp->maxfd) { fdp->maxfd = fd; } nfd->npollfds++; return ret_ok; }
static ret_t _del (cherokee_fdpoll_epoll_t *fdp, int fd) { struct epoll_event ev; ev.events = 0; ev.data.u64 = 0; /* <- I just wanna be sure there aren't */ ev.data.fd = fd; /* <- 4 bytes uninitialized */ /* Check the fd limit */ if (unlikely (cherokee_fdpoll_is_empty (FDPOLL(fdp)))) { SHOULDNT_HAPPEN; return ret_error; } if (epoll_ctl(fdp->ep_fd, EPOLL_CTL_DEL, fd, &ev) < 0) { LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_FDPOLL_EPOLL_CTL_DEL, fdp->ep_fd, fd); return ret_error; } FDPOLL(fdp)->npollfds--; return ret_ok; }
static ret_t _del (cherokee_fdpoll_select_t *fdp, int fd) { cherokee_fdpoll_t *nfd = FDPOLL(fdp); int idx = fdp->select_fdidx[fd]; if ((idx < 0) || (idx >= FDPOLL(fdp)->nfiles)) { PRINT_ERROR ("Bad idx (%d) in select_del_fd!\n", idx); return ret_error; } nfd->npollfds--; fdp->select_fds[idx] = fdp->select_fds[nfd->npollfds]; fdp->select_fdidx[fdp->select_fds[idx]] = idx; fdp->select_fds[nfd->npollfds] = -1; fdp->select_fdidx[fd] = -1; fdp->fd_rw[fd] = -1; FD_CLR (fd, &fdp->master_rfdset); FD_CLR (fd, &fdp->master_wfdset); if (fd >= fdp->maxfd) { fdp->maxfd_recompute = 1; } return ret_ok; }
static int _watch (cherokee_fdpoll_port_t *fdp, int timeout_msecs) { int i, rc, fd; struct timespec timeout; timeout.tv_sec = timeout_msecs/1000L; timeout.tv_nsec = ( timeout_msecs % 1000L ) * 1000000L; for (i=0; i<FDPOLL(fdp)->system_nfiles; i++) { fdp->port_activefd[i] = -1; } /* First call to get the number of file descriptors with activity */ rc = port_getn (fdp->port, fdp->port_events, 0, (uint_t *)&fdp->port_readyfds, &timeout); if ( rc < 0 ) { LOG_ERRNO_S (errno, cherokee_err_error, CHEROKEE_ERROR_FDPOLL_PORTS_GETN); return 0; } if ( fdp->port_readyfds == 0 ) { /* Get at least 1 fd to wait for activity */ fdp->port_readyfds = 1; } /* Second call to get the events of the file descriptors with * activity */ rc = port_getn (fdp->port, fdp->port_events,FDPOLL(fdp)->nfiles, &fdp->port_readyfds, &timeout); if ( ( (rc < 0) && (errno != ETIME) ) || (fdp->port_readyfds == -1)) { LOG_ERRNO_S (errno, cherokee_err_error, CHEROKEE_ERROR_FDPOLL_PORTS_GETN); return 0; } for ( i = 0; i < fdp->port_readyfds; ++i ) { int nfd; nfd = fdp->port_events[i].portev_object; fdp->port_activefd[nfd] = fdp->port_events[i].portev_events; rc = fd_associate( fdp, nfd, fdp->port_events[i].portev_user); if ( rc < 0 ) { LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_FDPOLL_PORTS_FD_ASSOCIATE, nfd); } } return fdp->port_readyfds; }
static int _watch (cherokee_fdpoll_kqueue_t *fdp, int timeout_msecs) { struct timespec timeout; int i; int n_events; timeout.tv_sec = timeout_msecs/1000L; timeout.tv_nsec = ( timeout_msecs % 1000L ) * 1000000L; /* Get the events of the file descriptors with * activity */ again: n_events = kevent (fdp->kqueue, fdp->changelist, fdp->nchanges, fdp->changelist, FDPOLL(fdp)->nfiles, &timeout); fdp->nchanges = 0; if (unlikely (n_events < 0)) { if (errno == EINTR) goto again; LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_FDPOLL_KQUEUE); return 0; } else if (n_events > 0) { memset (fdp->fdevents, 0, FDPOLL(fdp)->system_nfiles * sizeof(int)); for (i = 0; i < n_events; ++i) { /* Filter */ if (fdp->changelist[i].filter == EVFILT_READ) { fdp->fdevents[fdp->changelist[i].ident] = KQUEUE_READ_EVENT; } else if (fdp->changelist[i].filter == EVFILT_WRITE) { fdp->fdevents[fdp->changelist[i].ident] = KQUEUE_WRITE_EVENT; } else { SHOULDNT_HAPPEN; } /* Flags */ if (fdp->changelist[i].flags & (EV_EOF | EV_ERROR)) { fdp->fdevents[fdp->changelist[i].ident] = KQUEUE_CLOSE; } } } return n_events; }
static ret_t _del (cherokee_fdpoll_select_t *fdp, int fd) { cherokee_fdpoll_t *nfd = FDPOLL(fdp); int i; for (i=0; i < nfd->npollfds; i++) { if (fdp->select_fds[i] != fd) continue; nfd->npollfds--; fdp->select_fds[i] = fdp->select_fds[nfd->npollfds]; fdp->select_fds[nfd->npollfds] = -1; FD_CLR (fd, &fdp->master_rfdset); FD_CLR (fd, &fdp->master_wfdset); if (fd >= fdp->maxfd) { fdp->maxfd_recompute = 1; } return ret_ok; } PRINT_ERROR ("Couldn't remove fd %d\n", fd); return ret_error; }
static int _watch (cherokee_fdpoll_select_t *fdp, int timeout_msecs) { int mfd; int r, idx, ridx; fdp->working_rfdset = fdp->master_rfdset; fdp->working_wfdset = fdp->master_wfdset; mfd = select_get_maxfd(fdp); if (timeout_msecs == INFTIM) { r = select (mfd + 1, &fdp->working_rfdset, &fdp->working_wfdset, NULL, NULL); } else { struct timeval timeout; timeout.tv_sec = timeout_msecs / 1000L; timeout.tv_usec = ( timeout_msecs % 1000L ) * 1000L; r = select (mfd + 1, &fdp->working_rfdset, &fdp->working_wfdset, NULL, &timeout); } if (r <= 0) { return r; } ridx = 0; for (idx = 0; idx < FDPOLL(fdp)->npollfds; ++idx) { if (_check (fdp, fdp->select_fds[idx], 0)) { fdp->select_rfdidx[ridx++] = fdp->select_fds[idx]; if (ridx == r) break; } } return ridx; /* should be equal to r */ }
static ret_t _add_change(cherokee_fdpoll_kqueue_t *fdp, int fd, int rw, int change ) { int index; struct kevent *event; index = fdp->nchanges; if (unlikely (index >= FDPOLL(fdp)->nfiles)) { PRINT_ERROR_S("kqueue_add: fdpoll is full !\n"); return ret_error; } event = &fdp->changelist[index]; event->ident = fd; switch (rw) { case FDPOLL_MODE_READ: event->filter = EVFILT_READ; break; case FDPOLL_MODE_WRITE: event->filter = EVFILT_WRITE; break; default: SHOULDNT_HAPPEN; } event->flags = change; event->fflags = 0; fdp->fdinterest[fd] = rw; fdp->nchanges++; return ret_ok; }
ret_t fdpoll_kqueue_new (cherokee_fdpoll_t **fdp, int sys_fd_limit, int fd_limit) { int re; cherokee_fdpoll_t *nfd; CHEROKEE_CNEW_STRUCT (1, n, fdpoll_kqueue); nfd = FDPOLL(n); /* Init base class properties */ nfd->type = cherokee_poll_kqueue; nfd->nfiles = fd_limit; nfd->system_nfiles = sys_fd_limit; nfd->npollfds = 0; /* Init base class virtual methods */ nfd->free = (fdpoll_func_free_t) _free; nfd->add = (fdpoll_func_add_t) _add; nfd->del = (fdpoll_func_del_t) _del; nfd->reset = (fdpoll_func_reset_t) _reset; nfd->set_mode = (fdpoll_func_set_mode_t) _set_mode; nfd->check = (fdpoll_func_check_t) _check; nfd->watch = (fdpoll_func_watch_t) _watch; /* Init kqueue specific variables */ n->kqueue = -1; n->nchanges = 0; n->changelist = (struct kevent *) calloc (nfd->nfiles * 2, sizeof(struct kevent)); n->fdevents = (int *) calloc (nfd->system_nfiles, sizeof(int)); n->fdinterest = (int *) calloc (nfd->system_nfiles, sizeof(int)); if (n->fdevents == NULL || n->changelist == NULL || n->fdinterest == NULL) { _free (n); return ret_nomem; } n->kqueue = kqueue(); if (n->kqueue == -1) { _free (n); return ret_error; } re = fcntl (n->kqueue, F_SETFD, FD_CLOEXEC); if (re < 0) { LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_FDPOLL_EPOLL_CLOEXEC); _free (n); return ret_error; } /* Return the object */ *fdp = nfd; return ret_ok; }
static int _check (cherokee_fdpoll_epoll_t *fdp, int fd, int rw) { int fdidx; uint32_t events; /* Sanity check: is it a wrong fd? */ if (fd < 0 || fd >= FDPOLL(fdp)->system_nfiles) return -1; /* If fdidx is -1, it is not valid, ignore it. */ fdidx = fdp->epoll_fd2idx[fd]; if (fdidx < 0 || fdidx >= fdp->ep_nrevents) return 0; /* Sanity check */ if (fdidx >= FDPOLL(fdp)->nfiles) { PRINT_ERROR ("ERROR: fdpoll: out of range, %d of %d, fd=%d\n", fdidx, FDPOLL(fdp)->nfiles, fd); return -1; } /* Sanity check */ if (fdp->ep_events[fdidx].data.fd != fd) return 0; /* return -1; */ /* Check for errors */ events = fdp->ep_events[fdidx].events; switch (rw) { case FDPOLL_MODE_READ: return events & (EPOLLIN | EPOLLERR | EPOLLHUP); case FDPOLL_MODE_WRITE: return events & (EPOLLOUT | EPOLLERR | EPOLLHUP); default: return -1; } }
ret_t fdpoll_win32_new (cherokee_fdpoll_t **fdp, int system_fd_limit, int fd_limit) { int i; cherokee_fdpoll_t *nfd; CHEROKEE_CNEW_STRUCT (1, n, fdpoll_select); /* Verify that the max. number of selectable fds * is below the max. acceptable limit per select set. */ if (fd_limit > FD_SETSIZE) { _free(n); return ret_error; } nfd = FDPOLL(n); /* Init base class properties */ nfd->type = cherokee_poll_win32; nfd->nfiles = fd_limit; nfd->system_nfiles = system_fd_limit; nfd->npollfds = 0; /* Init base class virtual methods */ nfd->free = (fdpoll_func_free_t) _free; nfd->add = (fdpoll_func_add_t) _add; nfd->del = (fdpoll_func_del_t) _del; nfd->reset = (fdpoll_func_reset_t) _reset; nfd->set_mode = (fdpoll_func_set_mode_t) _set_mode; nfd->check = (fdpoll_func_check_t) _check; nfd->watch = (fdpoll_func_watch_t) _watch; /* Init properties */ FD_ZERO (&n->master_rfdset); FD_ZERO (&n->master_wfdset); n->select_fds = (int*) calloc(nfd->nfiles, sizeof(int)); n->maxfd = -1; n->maxfd_recompute = 0; if (n->select_fds == NULL) { _free (n); return ret_nomem; } for (i = 0; i < nfd->nfiles; ++i) { n->select_fds[i] = -1; } *fdp = nfd; return ret_ok; }
static ret_t _reset (cherokee_fdpoll_epoll_t *fdp, int fd) { /* Sanity check: is it a wrong fd? */ if (fd < 0 || fd >= FDPOLL(fdp)->system_nfiles) return ret_error; fdp->epoll_fd2idx[fd] = -1; return ret_ok; }
static ret_t _add (cherokee_fdpoll_kqueue_t *fdp, int fd, int rw) { int re; re = _add_change (fdp, fd, rw, EV_ADD); if (re == ret_ok) { FDPOLL(fdp)->npollfds++; } return re; }
static ret_t _del (cherokee_fdpoll_kqueue_t *fdp, int fd) { int re; re = _add_change (fdp, fd, fdp->fdinterest[fd], EV_DELETE); if (re == ret_ok) { FDPOLL(fdp)->npollfds--; } return re; }
ret_t fdpoll_port_new (cherokee_fdpoll_t **fdp, int sys_limit, int limit) { cuint_t i; cherokee_fdpoll_t *nfd; CHEROKEE_CNEW_STRUCT (1, n, fdpoll_port); nfd = FDPOLL(n); /* Init base class properties */ nfd->type = cherokee_poll_port; nfd->nfiles = limit; nfd->system_nfiles = sys_limit; nfd->npollfds = 0; /* Init base class virtual methods */ nfd->free = (fdpoll_func_free_t) _free; nfd->add = (fdpoll_func_add_t) _add; nfd->del = (fdpoll_func_del_t) _del; nfd->reset = (fdpoll_func_reset_t) _reset; nfd->set_mode = (fdpoll_func_set_mode_t) _set_mode; nfd->check = (fdpoll_func_check_t) _check; nfd->watch = (fdpoll_func_watch_t) _watch; /* Allocate data */ n->port = -1; n->port_readyfds = 0; n->port_events = (port_event_t *) calloc(nfd->nfiles, sizeof(port_event_t)); n->port_activefd = (int *) calloc(nfd->system_nfiles, sizeof(int)); if ( n->port_events == NULL || n->port_activefd == NULL ) { _free( n ); return ret_nomem; } for (i=0; i < nfd->system_nfiles; i++) { n->port_activefd[i] = -1; } if ( (n->port = port_create()) == -1 ) { _free( n ); return ret_error; } /* Return the object */ *fdp = nfd; return ret_ok; }
static ret_t _add (cherokee_fdpoll_epoll_t *fdp, int fd, int rw) { struct epoll_event ev; /* Check the fd limit */ if (unlikely (cherokee_fdpoll_is_full (FDPOLL(fdp)))) { PRINT_ERROR_S("epoll_add: fdpoll is full !\n"); return ret_error; } /* Add the new descriptor */ ev.data.u64 = 0; ev.data.fd = fd; switch (rw) { case FDPOLL_MODE_READ: ev.events = EPOLLIN | EPOLLERR | EPOLLHUP; break; case FDPOLL_MODE_WRITE: ev.events = EPOLLOUT | EPOLLERR | EPOLLHUP; break; default: ev.events = 0; SHOULDNT_HAPPEN; return ret_error; } if (epoll_ctl (fdp->ep_fd, EPOLL_CTL_ADD, fd, &ev) < 0) { LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_FDPOLL_EPOLL_CTL_ADD, fdp->ep_fd, fd); return ret_error; } FDPOLL(fdp)->npollfds++; return ret_ok; }
static ret_t _add (cherokee_fdpoll_port_t *fdp, int fd, int rw) { int rc; rc = fd_associate(fdp, fd, (rw == FDPOLL_MODE_WRITE ? WRITE : READ)); if ( rc == -1 ) { LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_FDPOLL_PORTS_FD_ASSOCIATE, fd); return ret_error; } FDPOLL(fdp)->npollfds++; return ret_ok; }
static int _watch (cherokee_fdpoll_epoll_t *fdp, int timeout_msecs) { int i; fdp->ep_nrevents = epoll_wait (fdp->ep_fd, fdp->ep_events, FDPOLL(fdp)->nfiles, timeout_msecs); if (fdp->ep_nrevents < 1) return fdp->ep_nrevents; for (i = 0; i < fdp->ep_nrevents; ++i) { fdp->epoll_fd2idx[fdp->ep_events[i].data.fd] = i; } return fdp->ep_nrevents; }
static int select_get_maxfd (cherokee_fdpoll_select_t *fdp) { if (fdp->maxfd_recompute) { int i; fdp->maxfd = -1; for (i = 0; i < FDPOLL(fdp)->npollfds; ++i) { if (fdp->select_fds[i] > fdp->maxfd ) { fdp->maxfd = fdp->select_fds[i]; } } fdp->maxfd_recompute = 0; } return fdp->maxfd; }
static ret_t _del (cherokee_fdpoll_port_t *fdp, int fd) { int rc; rc = port_dissociate( fdp->port, /* port */ PORT_SOURCE_FD, /* source */ fd); /* object */ if ( rc == -1 ) { LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_FDPOLL_PORTS_ASSOCIATE, fd); return ret_error; } FDPOLL(fdp)->npollfds--; /* remote fd from the active fd list */ fdp->port_activefd[fd] = -1; return ret_ok; }
ret_t fdpoll_epoll_new (cherokee_fdpoll_t **fdp, int sys_fd_limit, int fd_limit) { int re; cherokee_fdpoll_t *nfd; CHEROKEE_CNEW_STRUCT (1, n, fdpoll_epoll); nfd = FDPOLL(n); /* Init base class properties */ nfd->type = cherokee_poll_epoll; nfd->nfiles = fd_limit; nfd->system_nfiles = sys_fd_limit; nfd->npollfds = 0; /* Init base class virtual methods */ nfd->free = (fdpoll_func_free_t) _free; nfd->add = (fdpoll_func_add_t) _add; nfd->del = (fdpoll_func_del_t) _del; nfd->reset = (fdpoll_func_reset_t) _reset; nfd->set_mode = (fdpoll_func_set_mode_t) _set_mode; nfd->check = (fdpoll_func_check_t) _check; nfd->watch = (fdpoll_func_watch_t) _watch; /* Look for max fd limit */ n->ep_fd = -1; n->ep_nrevents = 0; n->ep_events = (struct epoll_event *) calloc (nfd->nfiles, sizeof(struct epoll_event)); n->epoll_fd2idx = (int *) calloc (nfd->system_nfiles, sizeof(int)); /* If anyone fails free all and return ret_nomem */ if (n->ep_events == NULL || n->epoll_fd2idx == NULL) { _free(n); return ret_nomem; } for (re = 0; re < nfd->system_nfiles; re++) { n->epoll_fd2idx[re] = -1; } n->ep_fd = epoll_create (nfd->nfiles); if (n->ep_fd < 0) { /* It may fail here if the glibc library supports epoll, * but the kernel doesn't. */ #if 0 LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_FDPOLL_EPOLL_CREATE, nfd->nfiles+1); #endif _free (n); return ret_error; } re = fcntl (n->ep_fd, F_SETFD, FD_CLOEXEC); if (re < 0) { LOG_ERRNO (errno, cherokee_err_error, CHEROKEE_ERROR_FDPOLL_EPOLL_CLOEXEC); _free (n); return ret_error; } /* Return the object */ *fdp = nfd; return ret_ok; }