#include <errno.h>
static size_t num_fds = 0, max_fds = 0, num_closing = 0, num_waiting = 0;
+static bool some_always = false;
static struct pollfd *pollfds = NULL;
static struct fd **fds = NULL;
static struct timers timeouts;
fds[n] = fds[num_fds-1];
assert(fds[n]->backend_info == num_fds-1);
fds[n]->backend_info = n;
+ /* If that happens to be a duplex, move that too. */
+ if (!fds[n]->listener) {
+ struct io_conn *c = (void *)fds[n];
+ if (c->duplex) {
+ assert(c->duplex->fd.backend_info == num_fds-1);
+ c->duplex->fd.backend_info = n;
+ }
+ }
} else if (num_fds == 1) {
/* Free everything when no more fds. */
io_alloc.free(pollfds);
if (pfd->events)
num_waiting--;
- pfd->events = conn->plan.pollflag;
+ pfd->events = conn->plan.pollflag & (POLLIN|POLLOUT);
if (conn->duplex) {
- int mask = conn->duplex->plan.pollflag;
+ int mask = conn->duplex->plan.pollflag & (POLLIN|POLLOUT);
/* You can't *both* read/write. */
assert(!mask || pfd->events != mask);
pfd->events |= mask;
if (!conn->plan.next)
num_closing++;
+
+ if (conn->plan.pollflag == POLLALWAYS)
+ some_always = true;
}
bool add_conn(struct io_conn *c)
{
- if (!add_fd(&c->fd, c->plan.pollflag))
+ if (!add_fd(&c->fd, c->plan.pollflag & (POLLIN|POLLOUT)))
return false;
/* Immediate close is allowed. */
if (!c->plan.next)
num_closing++;
+ if (c->plan.pollflag == POLLALWAYS)
+ some_always = true;
return true;
}
void backend_del_conn(struct io_conn *conn)
{
- if (conn->finish) {
- /* Saved by io_close */
- errno = conn->plan.u1.s;
- conn->finish(conn, conn->finish_arg);
- }
if (timeout_active(conn))
backend_del_timeout(conn);
io_alloc.free(conn->timeout);
if (conn->duplex) {
/* In case fds[] pointed to the other one. */
+ assert(conn->duplex->fd.backend_info == conn->fd.backend_info);
fds[conn->fd.backend_info] = &conn->duplex->fd;
conn->duplex->duplex = NULL;
conn->fd.backend_info = -1;
} else
del_fd(&conn->fd);
num_closing--;
+ if (conn->finish) {
+ /* Saved by io_close */
+ errno = conn->plan.u1.s;
+ conn->finish(conn, conn->finish_arg);
+ }
free_conn(conn);
}
conn->timeout->conn = NULL;
}
+static void handle_always(void)
+{
+ int i;
+
+ some_always = false;
+
+ for (i = 0; i < num_fds && !io_loop_return; i++) {
+ struct io_conn *c = (void *)fds[i];
+
+ if (fds[i]->listener)
+ continue;
+
+ if (c->plan.pollflag == POLLALWAYS)
+ io_ready(c);
+
+ if (c->duplex && c->duplex->plan.pollflag == POLLALWAYS)
+ io_ready(c->duplex);
+ }
+}
+
/* This is the main loop. */
void *do_io_loop(struct io_conn **ready)
{
if (doing_debug() && some_timeouts)
continue;
+ if (some_always) {
+ handle_always();
+ continue;
+ }
+
if (num_fds == 0)
break;