1 /* Licensed under LGPLv2.1+ - see LICENSE file for details */
8 #include <sys/socket.h>
11 #include <ccan/time/time.h>
12 #include <ccan/timer/timer.h>
14 static size_t num_fds = 0, max_fds = 0, num_waiting = 0;
15 static struct pollfd *pollfds = NULL;
16 static struct fd **fds = NULL;
17 static LIST_HEAD(closing);
18 static LIST_HEAD(always);
19 static struct timeabs (*nowfn)(void) = time_now;
21 struct timeabs (*io_time_override(struct timeabs (*now)(void)))(void)
23 struct timeabs (*old)(void) = nowfn;
28 static bool add_fd(struct fd *fd, short events)
32 pollfds = tal_arr(NULL, struct pollfd, 8);
35 fds = tal_arr(pollfds, struct fd *, 8);
41 if (num_fds + 1 > max_fds) {
42 size_t num = max_fds * 2;
44 if (!tal_resize(&pollfds, num))
46 if (!tal_resize(&fds, num))
51 pollfds[num_fds].events = events;
52 /* In case it's idle. */
54 pollfds[num_fds].fd = -fd->fd;
56 pollfds[num_fds].fd = fd->fd;
57 pollfds[num_fds].revents = 0; /* In case we're iterating now */
59 fd->backend_info = num_fds;
67 static void del_fd(struct fd *fd)
69 size_t n = fd->backend_info;
73 if (pollfds[n].events)
75 if (n != num_fds - 1) {
76 /* Move last one over us. */
77 pollfds[n] = pollfds[num_fds-1];
78 fds[n] = fds[num_fds-1];
79 assert(fds[n]->backend_info == num_fds-1);
80 fds[n]->backend_info = n;
81 } else if (num_fds == 1) {
82 /* Free everything when no more fds. */
83 pollfds = tal_free(pollfds);
88 fd->backend_info = -1;
90 /* Closing a local socket doesn't wake poll() because other end
91 * has them open. See 2.6. When should I use shutdown()?
92 * in http://www.faqs.org/faqs/unix-faq/socket/ */
93 shutdown(fd->fd, SHUT_RDWR);
98 bool add_listener(struct io_listener *l)
100 if (!add_fd(&l->fd, POLLIN))
105 void remove_from_always(struct io_conn *conn)
107 list_del_init(&conn->always);
110 void backend_new_closing(struct io_conn *conn)
112 /* In case it's on always list, remove it. */
113 list_del_init(&conn->always);
114 list_add_tail(&closing, &conn->closing);
117 void backend_new_always(struct io_conn *conn)
119 /* In case it's already in always list. */
120 list_del(&conn->always);
121 list_add_tail(&always, &conn->always);
124 void backend_new_plan(struct io_conn *conn)
126 struct pollfd *pfd = &pollfds[conn->fd.backend_info];
132 if (conn->plan[IO_IN].status == IO_POLLING)
133 pfd->events |= POLLIN;
134 if (conn->plan[IO_OUT].status == IO_POLLING)
135 pfd->events |= POLLOUT;
139 pfd->fd = conn->fd.fd;
141 pfd->fd = -conn->fd.fd;
145 void backend_wake(const void *wait)
149 for (i = 0; i < num_fds; i++) {
152 /* Ignore listeners */
153 if (fds[i]->listener)
157 if (c->plan[IO_IN].status == IO_WAITING
158 && c->plan[IO_IN].arg.u1.const_vp == wait)
159 io_do_wakeup(c, IO_IN);
161 if (c->plan[IO_OUT].status == IO_WAITING
162 && c->plan[IO_OUT].arg.u1.const_vp == wait)
163 io_do_wakeup(c, IO_OUT);
167 bool add_conn(struct io_conn *c)
169 return add_fd(&c->fd, 0);
172 static void del_conn(struct io_conn *conn)
176 /* Saved by io_close */
177 errno = conn->plan[IO_IN].arg.u1.s;
178 conn->finish(conn, conn->finish_arg);
183 void del_listener(struct io_listener *l)
188 static void accept_conn(struct io_listener *l)
190 int fd = accept(l->fd.fd, NULL, NULL);
192 /* FIXME: What to do here? */
196 io_new_conn(l->ctx, fd, l->init, l->arg);
199 /* It's OK to miss some, as long as we make progress. */
200 static bool close_conns(void)
203 struct io_conn *conn;
205 while ((conn = list_pop(&closing, struct io_conn, closing)) != NULL) {
206 assert(conn->plan[IO_IN].status == IO_CLOSING);
207 assert(conn->plan[IO_OUT].status == IO_CLOSING);
215 static bool handle_always(void)
218 struct io_conn *conn;
220 while ((conn = list_pop(&always, struct io_conn, always)) != NULL) {
221 assert(conn->plan[IO_IN].status == IO_ALWAYS
222 || conn->plan[IO_OUT].status == IO_ALWAYS);
224 /* Re-initialize, for next time. */
225 list_node_init(&conn->always);
232 /* This is the main loop. */
233 void *io_loop(struct timers *timers, struct timer **expired)
237 /* if timers is NULL, expired must be. If not, not. */
238 assert(!timers == !expired);
240 /* Make sure this is NULL if we exit for some other reason. */
244 while (!io_loop_return) {
245 int i, r, ms_timeout = -1;
248 /* Could have started/finished more. */
252 if (handle_always()) {
253 /* Could have started/finished more. */
257 /* Everything closed? */
261 /* You can't tell them all to go to sleep! */
265 struct timeabs now, first;
269 /* Call functions for expired timers. */
270 *expired = timers_expire(timers, now);
274 /* Now figure out how long to wait for the next one. */
275 if (timer_earliest(timers, &first)) {
277 next = time_to_msec(time_between(first, now));
281 ms_timeout = INT_MAX;
285 r = poll(pollfds, num_fds, ms_timeout);
289 for (i = 0; i < num_fds && !io_loop_return; i++) {
290 struct io_conn *c = (void *)fds[i];
291 int events = pollfds[i].revents;
296 if (fds[i]->listener) {
297 if (events & POLLIN) {
298 accept_conn((void *)c);
301 } else if (events & (POLLIN|POLLOUT)) {
304 } else if (events & (POLLHUP|POLLNVAL|POLLERR)) {
314 ret = io_loop_return;
315 io_loop_return = NULL;