1 /* Licensed under BSD-MIT - see LICENSE file for details */
8 #include <sys/socket.h>
10 static size_t num_fds = 0, max_fds = 0, num_next = 0, num_finished = 0, num_waiting = 0;
11 static struct pollfd *pollfds = NULL;
12 static struct fd **fds = NULL;
14 static bool add_fd(struct fd *fd, short events)
16 if (num_fds + 1 > max_fds) {
17 struct pollfd *newpollfds;
19 size_t num = max_fds ? max_fds * 2 : 8;
21 newpollfds = realloc(pollfds, sizeof(*newpollfds) * num);
25 newfds = realloc(fds, sizeof(*newfds) * num);
32 pollfds[num_fds].fd = fd->fd;
33 pollfds[num_fds].events = events;
34 pollfds[num_fds].revents = 0; /* In case we're iterating now */
36 fd->backend_info = num_fds;
41 static void del_fd(struct fd *fd)
43 size_t n = fd->backend_info;
47 if (n != num_fds - 1) {
48 /* Move last one over us. */
49 pollfds[n] = pollfds[num_fds-1];
50 fds[n] = fds[num_fds-1];
51 assert(fds[n]->backend_info == num_fds-1);
52 fds[n]->backend_info = n;
53 } else if (num_fds == 1) {
54 /* Free everything when no more fds. */
62 fd->backend_info = -1;
66 bool add_listener(struct io_listener *l)
68 if (!add_fd(&l->fd, POLLIN))
74 bool add_conn(struct io_conn *c)
76 if (!add_fd(&c->fd, 0))
82 bool add_duplex(struct io_conn *c)
84 c->fd.backend_info = c->duplex->fd.backend_info;
89 static void del_conn(struct io_conn *conn)
92 conn->fd.finish(conn, conn->fd.finish_arg);
94 /* In case fds[] pointed to the other one. */
95 fds[conn->fd.backend_info] = &conn->duplex->fd;
96 conn->duplex->duplex = NULL;
99 if (conn->state == FINISHED)
101 else if (conn->state == NEXT)
105 void del_listener(struct io_listener *l)
110 static int pollmask(enum io_state state)
124 void backend_set_state(struct io_conn *conn, struct io_op *op)
126 enum io_state state = from_ioop(op);
127 struct pollfd *pfd = &pollfds[conn->fd.backend_info];
132 pfd->events = pollmask(state);
134 int mask = pollmask(conn->duplex->state);
135 /* You can't *both* read/write. */
136 assert(!mask || pfd->events != mask);
144 else if (state == FINISHED)
150 static void accept_conn(struct io_listener *l)
153 int fd = accept(l->fd.fd, NULL, NULL);
155 /* FIXME: What to do here? */
158 c = io_new_conn(fd, l->fd.next, l->fd.finish, l->fd.next_arg);
165 /* It's OK to miss some, as long as we make progress. */
166 static void finish_and_next(bool finished_only)
170 for (i = 0; !io_loop_return && i < num_fds; i++) {
171 struct io_conn *c, *duplex;
174 if (finished_only || num_next == 0)
177 if (fds[i]->listener)
180 for (duplex = c->duplex; c; c = duplex, duplex = NULL) {
181 if (c->state == FINISHED) {
185 } else if (!finished_only && c->state == NEXT) {
195 static void ready(struct io_conn *c)
197 backend_set_state(c, do_ready(c));
200 /* This is the main loop. */
205 while (!io_loop_return) {
208 if (num_finished || num_next) {
209 finish_and_next(false);
210 /* Could have started/finished more. */
217 /* You can't tell them all to go to sleep! */
220 r = poll(pollfds, num_fds, -1);
224 for (i = 0; i < num_fds && !io_loop_return; i++) {
225 struct io_conn *c = (void *)fds[i];
226 int events = pollfds[i].revents;
228 if (fds[i]->listener) {
230 accept_conn((void *)c);
231 } else if (events & (POLLIN|POLLOUT)) {
233 int mask = pollmask(c->duplex->state);
237 if (!(events&(POLLIN|POLLOUT)))
242 } else if (events & POLLHUP) {
243 backend_set_state(c, io_close(c, NULL));
245 backend_set_state(c->duplex,
254 finish_and_next(true);
256 ret = io_loop_return;
257 io_loop_return = NULL;