Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

324 lines (257 sloc) 7.263 kB
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/* Cherokee
*
* Authors:
* Alvaro Lopez Ortega <alvaro@alobbs.com>
*
* Copyright (C) 2001-2011 Alvaro Lopez Ortega
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#include "common-internal.h"
#include "fdpoll-protected.h"
#include <errno.h>
#ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
#endif
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#ifndef INFTIM
# define INFTIM -1
#endif
/***********************************************************************/
/* select() */
/* */
/* #include <sys/select.h> */
/* int select(int n, fd_set *readfds, fd_set *writefds, */
/* fd_set *exceptfds, struct timeval *timeout); */
/* */
/***********************************************************************/
typedef struct {
struct cherokee_fdpoll poll;
int *fd_rw;
fd_set master_rfdset;
fd_set master_wfdset;
fd_set working_rfdset;
fd_set working_wfdset;
int *select_fds;
int *select_fdidx;
int *select_rfdidx;
int maxfd;
int maxfd_recompute;
} cherokee_fdpoll_select_t;
static ret_t
_free (cherokee_fdpoll_select_t *fdp)
{
if (fdp == NULL)
return ret_ok;
/* ANSI C required, so that free() can handle NULL pointers
*/
free (fdp->select_fds);
free (fdp->select_fdidx);
free (fdp->select_rfdidx);
free (fdp->fd_rw);
/* Caller has to set this pointer to NULL.
*/
free (fdp);
return ret_ok;
}
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("select_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;
}
fdp->select_fdidx[fd] = nfd->npollfds;
fdp->fd_rw[fd] = rw;
nfd->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 ret_t
_set_mode (cherokee_fdpoll_select_t *fdp, int fd, int rw)
{
ret_t ret;
ret = _del (fdp, fd);
if (unlikely(ret < ret_ok))
return ret;
return _add (fdp, fd, rw);
}
static int
_check (cherokee_fdpoll_select_t *fdp, int fd, int rw)
{
UNUSED(rw);
switch (fdp->fd_rw[fd]) {
case FDPOLL_MODE_READ:
return FD_ISSET (fd, &fdp->working_rfdset);
case FDPOLL_MODE_WRITE:
return FD_ISSET (fd, &fdp->working_wfdset);
}
return 0;
}
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 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
_reset (cherokee_fdpoll_select_t *fdp, int fd)
{
UNUSED(fdp);
UNUSED(fd);
return ret_ok;
}
ret_t
fdpoll_select_get_fdlimits (cuint_t *system_fd_limit, cuint_t *fd_limit)
{
*system_fd_limit = FD_SETSIZE;
*fd_limit = 0;
return ret_ok;
}
ret_t
fdpoll_select_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 system fds
* is below the max. acceptable limit.
*/
if (system_fd_limit > FD_SETSIZE) {
_free(n);
return ret_error;
}
nfd = FDPOLL(n);
/* Init base class properties
*/
nfd->type = cherokee_poll_select;
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->select_rfdidx = (int*) calloc(nfd->nfiles, sizeof(int));
n->select_fdidx = (int*) calloc(nfd->system_nfiles, sizeof(int));
n->fd_rw = (int*) calloc(nfd->system_nfiles, sizeof(int));
n->maxfd = -1;
n->maxfd_recompute = 0;
if (n->select_fds == NULL ||
n->select_rfdidx == NULL ||
n->select_fdidx == NULL ||
n->fd_rw == NULL) {
_free (n);
return ret_nomem;
}
for (i = 0; i < nfd->nfiles; ++i) {
n->select_fds[i] = -1;
}
for (i = 0; i < nfd->system_nfiles; ++i) {
n->select_fdidx[i] = -1;
n->fd_rw[i] = -1;
}
*fdp = nfd;
return ret_ok;
}
Jump to Line
Something went wrong with that request. Please try again.