1 /* Licensed under LGPLv2.1+ - see LICENSE file for details */
8 #include <sys/socket.h>
12 static size_t num_fds = 0, max_fds = 0, num_waiting = 0;
13 static struct pollfd *pollfds = NULL;
14 static struct fd **fds = NULL;
15 static struct io_conn *closing = NULL, *always = NULL;
17 static bool add_fd(struct fd *fd, short events)
21 pollfds = tal_arr(NULL, struct pollfd, 8);
24 fds = tal_arr(pollfds, struct fd *, 8);
30 if (num_fds + 1 > max_fds) {
31 size_t num = max_fds * 2;
33 if (!tal_resize(&pollfds, num))
35 if (!tal_resize(&fds, num))
40 pollfds[num_fds].events = events;
41 /* In case it's idle. */
43 pollfds[num_fds].fd = -fd->fd;
45 pollfds[num_fds].fd = fd->fd;
46 pollfds[num_fds].revents = 0; /* In case we're iterating now */
48 fd->backend_info = num_fds;
56 static void del_fd(struct fd *fd)
58 size_t n = fd->backend_info;
62 if (pollfds[n].events)
64 if (n != num_fds - 1) {
65 /* Move last one over us. */
66 pollfds[n] = pollfds[num_fds-1];
67 fds[n] = fds[num_fds-1];
68 assert(fds[n]->backend_info == num_fds-1);
69 fds[n]->backend_info = n;
70 } else if (num_fds == 1) {
71 /* Free everything when no more fds. */
72 pollfds = tal_free(pollfds);
77 fd->backend_info = -1;
81 bool add_listener(struct io_listener *l)
83 if (!add_fd(&l->fd, POLLIN))
88 void backend_new_closing(struct io_conn *conn)
90 /* Already on always list? Remove it. */
92 struct io_conn **p = &always;
100 conn->list = closing;
104 void backend_new_always(struct io_conn *conn)
106 /* May already be in always list (other plan), or closing. */
113 void backend_new_plan(struct io_conn *conn)
115 struct pollfd *pfd = &pollfds[conn->fd.backend_info];
121 if (conn->plan[IO_IN].status == IO_POLLING)
122 pfd->events |= POLLIN;
123 if (conn->plan[IO_OUT].status == IO_POLLING)
124 pfd->events |= POLLOUT;
128 pfd->fd = conn->fd.fd;
130 pfd->fd = -conn->fd.fd;
134 void backend_wake(const void *wait)
138 for (i = 0; i < num_fds; i++) {
141 /* Ignore listeners */
142 if (fds[i]->listener)
146 if (c->plan[IO_IN].status == IO_WAITING
147 && c->plan[IO_IN].u1.const_vp == wait)
148 io_do_wakeup(c, &c->plan[IO_IN]);
150 if (c->plan[IO_OUT].status == IO_WAITING
151 && c->plan[IO_OUT].u1.const_vp == wait)
152 io_do_wakeup(c, &c->plan[IO_OUT]);
156 bool add_conn(struct io_conn *c)
158 return add_fd(&c->fd, 0);
161 static void del_conn(struct io_conn *conn)
165 /* Saved by io_close */
166 errno = conn->plan[IO_IN].u1.s;
167 conn->finish(conn, conn->finish_arg);
172 void del_listener(struct io_listener *l)
177 static void accept_conn(struct io_listener *l)
179 int fd = accept(l->fd.fd, NULL, NULL);
181 /* FIXME: What to do here? */
185 io_new_conn(l->ctx, fd, l->init, l->arg);
188 /* It's OK to miss some, as long as we make progress. */
189 static bool close_conns(void)
194 struct io_conn *conn = closing;
196 assert(conn->plan[IO_IN].status == IO_CLOSING);
197 assert(conn->plan[IO_OUT].status == IO_CLOSING);
199 closing = closing->list;
206 static bool handle_always(void)
211 struct io_conn *conn = always;
213 assert(conn->plan[IO_IN].status == IO_ALWAYS
214 || conn->plan[IO_OUT].status == IO_ALWAYS);
216 /* Remove from list, and mark it so it knows that. */
217 always = always->list;
225 /* This is the main loop. */
230 while (!io_loop_return) {
234 /* Could have started/finished more. */
238 if (handle_always()) {
239 /* Could have started/finished more. */
243 /* Everything closed? */
247 /* You can't tell them all to go to sleep! */
250 r = poll(pollfds, num_fds, -1);
254 for (i = 0; i < num_fds && !io_loop_return; i++) {
255 struct io_conn *c = (void *)fds[i];
256 int events = pollfds[i].revents;
261 if (fds[i]->listener) {
262 if (events & POLLIN) {
263 accept_conn((void *)c);
266 } else if (events & (POLLIN|POLLOUT)) {
269 } else if (events & (POLLHUP|POLLNVAL|POLLERR)) {
279 ret = io_loop_return;
280 io_loop_return = NULL;