]> git.ozlabs.org Git - ccan/blob - ccan/io/poll.c
timer: change to use time_mono (api break!)
[ccan] / ccan / io / poll.c
1 /* Licensed under LGPLv2.1+ - see LICENSE file for details */
2 #include "io.h"
3 #include "backend.h"
4 #include <assert.h>
5 #include <poll.h>
6 #include <stdlib.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <limits.h>
10 #include <errno.h>
11 #include <ccan/time/time.h>
12 #include <ccan/timer/timer.h>
13
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;
20
21 struct timeabs (*io_time_override(struct timeabs (*now)(void)))(void)
22 {
23         struct timeabs (*old)(void) = nowfn;
24         nowfn = now;
25         return old;
26 }
27
28 static bool add_fd(struct fd *fd, short events)
29 {
30         if (!max_fds) {
31                 assert(num_fds == 0);
32                 pollfds = tal_arr(NULL, struct pollfd, 8);
33                 if (!pollfds)
34                         return false;
35                 fds = tal_arr(pollfds, struct fd *, 8);
36                 if (!fds)
37                         return false;
38                 max_fds = 8;
39         }
40
41         if (num_fds + 1 > max_fds) {
42                 size_t num = max_fds * 2;
43
44                 if (!tal_resize(&pollfds, num))
45                         return false;
46                 if (!tal_resize(&fds, num))
47                         return false;
48                 max_fds = num;
49         }
50
51         pollfds[num_fds].events = events;
52         /* In case it's idle. */
53         if (!events)
54                 pollfds[num_fds].fd = -fd->fd;
55         else
56                 pollfds[num_fds].fd = fd->fd;
57         pollfds[num_fds].revents = 0; /* In case we're iterating now */
58         fds[num_fds] = fd;
59         fd->backend_info = num_fds;
60         num_fds++;
61         if (events)
62                 num_waiting++;
63
64         return true;
65 }
66
67 static void del_fd(struct fd *fd)
68 {
69         size_t n = fd->backend_info;
70
71         assert(n != -1);
72         assert(n < num_fds);
73         if (pollfds[n].events)
74                 num_waiting--;
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);
84                 fds = NULL;
85                 max_fds = 0;
86         }
87         num_fds--;
88         fd->backend_info = -1;
89
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);
94
95         close(fd->fd);
96 }
97
98 bool add_listener(struct io_listener *l)
99 {
100         if (!add_fd(&l->fd, POLLIN))
101                 return false;
102         return true;
103 }
104
105 void remove_from_always(struct io_conn *conn)
106 {
107         list_del_init(&conn->always);
108 }
109
110 void backend_new_closing(struct io_conn *conn)
111 {
112         /* In case it's on always list, remove it. */
113         list_del_init(&conn->always);
114         list_add_tail(&closing, &conn->closing);
115 }
116
117 void backend_new_always(struct io_conn *conn)
118 {
119         /* In case it's already in always list. */
120         list_del(&conn->always);
121         list_add_tail(&always, &conn->always);
122 }
123
124 void backend_new_plan(struct io_conn *conn)
125 {
126         struct pollfd *pfd = &pollfds[conn->fd.backend_info];
127
128         if (pfd->events)
129                 num_waiting--;
130
131         pfd->events = 0;
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;
136
137         if (pfd->events) {
138                 num_waiting++;
139                 pfd->fd = conn->fd.fd;
140         } else {
141                 pfd->fd = -conn->fd.fd;
142         }
143 }
144
145 void backend_wake(const void *wait)
146 {
147         unsigned int i;
148
149         for (i = 0; i < num_fds; i++) {
150                 struct io_conn *c;
151
152                 /* Ignore listeners */
153                 if (fds[i]->listener)
154                         continue;
155
156                 c = (void *)fds[i];
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);
160
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);
164         }
165 }
166
167 bool add_conn(struct io_conn *c)
168 {
169         return add_fd(&c->fd, 0);
170 }
171
172 static void del_conn(struct io_conn *conn)
173 {
174         del_fd(&conn->fd);
175         if (conn->finish) {
176                 /* Saved by io_close */
177                 errno = conn->plan[IO_IN].arg.u1.s;
178                 conn->finish(conn, conn->finish_arg);
179         }
180         tal_free(conn);
181 }
182
183 void del_listener(struct io_listener *l)
184 {
185         del_fd(&l->fd);
186 }
187
188 static void accept_conn(struct io_listener *l)
189 {
190         int fd = accept(l->fd.fd, NULL, NULL);
191
192         /* FIXME: What to do here? */
193         if (fd < 0)
194                 return;
195
196         io_new_conn(l->ctx, fd, l->init, l->arg);
197 }
198
199 /* It's OK to miss some, as long as we make progress. */
200 static bool close_conns(void)
201 {
202         bool ret = false;
203         struct io_conn *conn;
204
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);
208
209                 del_conn(conn);
210                 ret = true;
211         }
212         return ret;
213 }
214
215 static bool handle_always(void)
216 {
217         bool ret = false;
218         struct io_conn *conn;
219
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);
223
224                 /* Re-initialize, for next time. */
225                 list_node_init(&conn->always);
226                 io_do_always(conn);
227                 ret = true;
228         }
229         return ret;
230 }
231
232 /* This is the main loop. */
233 void *io_loop(struct timers *timers, struct timer **expired)
234 {
235         void *ret;
236
237         /* if timers is NULL, expired must be.  If not, not. */
238         assert(!timers == !expired);
239
240         /* Make sure this is NULL if we exit for some other reason. */
241         if (expired)
242                 *expired = NULL;
243
244         while (!io_loop_return) {
245                 int i, r, ms_timeout = -1;
246
247                 if (close_conns()) {
248                         /* Could have started/finished more. */
249                         continue;
250                 }
251
252                 if (handle_always()) {
253                         /* Could have started/finished more. */
254                         continue;
255                 }
256
257                 /* Everything closed? */
258                 if (num_fds == 0)
259                         break;
260
261                 /* You can't tell them all to go to sleep! */
262                 assert(num_waiting);
263
264                 if (timers) {
265                         struct timeabs now, first;
266
267                         now = nowfn();
268
269                         /* Call functions for expired timers. */
270                         *expired = timers_expire(timers, now);
271                         if (*expired)
272                                 break;
273
274                         /* Now figure out how long to wait for the next one. */
275                         if (timer_earliest(timers, &first)) {
276                                 uint64_t next;
277                                 next = time_to_msec(time_between(first, now));
278                                 if (next < INT_MAX)
279                                         ms_timeout = next;
280                                 else
281                                         ms_timeout = INT_MAX;
282                         }
283                 }
284
285                 r = poll(pollfds, num_fds, ms_timeout);
286                 if (r < 0)
287                         break;
288
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;
292
293                         if (r == 0)
294                                 break;
295
296                         if (fds[i]->listener) {
297                                 if (events & POLLIN) {
298                                         accept_conn((void *)c);
299                                         r--;
300                                 }
301                         } else if (events & (POLLIN|POLLOUT)) {
302                                 r--;
303                                 io_ready(c, events);
304                         } else if (events & (POLLHUP|POLLNVAL|POLLERR)) {
305                                 r--;
306                                 errno = EBADF;
307                                 io_close(c);
308                         }
309                 }
310         }
311
312         close_conns();
313
314         ret = io_loop_return;
315         io_loop_return = NULL;
316
317         return ret;
318 }