]> git.ozlabs.org Git - ccan/blob - ccan/io/poll.c
list_del_init/list_node_init: for multiple list_del() calls.
[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/list/list.h>
12 #include <ccan/time/time.h>
13 #include <ccan/timer/timer.h>
14
15 static size_t num_fds = 0, max_fds = 0, num_waiting = 0;
16 static struct pollfd *pollfds = NULL;
17 static struct fd **fds = NULL;
18 static struct io_conn *closing = NULL, *always = NULL;
19
20 static bool add_fd(struct fd *fd, short events)
21 {
22         if (!max_fds) {
23                 assert(num_fds == 0);
24                 pollfds = tal_arr(NULL, struct pollfd, 8);
25                 if (!pollfds)
26                         return false;
27                 fds = tal_arr(pollfds, struct fd *, 8);
28                 if (!fds)
29                         return false;
30                 max_fds = 8;
31         }
32
33         if (num_fds + 1 > max_fds) {
34                 size_t num = max_fds * 2;
35
36                 if (!tal_resize(&pollfds, num))
37                         return false;
38                 if (!tal_resize(&fds, num))
39                         return false;
40                 max_fds = num;
41         }
42
43         pollfds[num_fds].events = events;
44         /* In case it's idle. */
45         if (!events)
46                 pollfds[num_fds].fd = -fd->fd;
47         else
48                 pollfds[num_fds].fd = fd->fd;
49         pollfds[num_fds].revents = 0; /* In case we're iterating now */
50         fds[num_fds] = fd;
51         fd->backend_info = num_fds;
52         num_fds++;
53         if (events)
54                 num_waiting++;
55
56         return true;
57 }
58
59 static void del_fd(struct fd *fd)
60 {
61         size_t n = fd->backend_info;
62
63         assert(n != -1);
64         assert(n < num_fds);
65         if (pollfds[n].events)
66                 num_waiting--;
67         if (n != num_fds - 1) {
68                 /* Move last one over us. */
69                 pollfds[n] = pollfds[num_fds-1];
70                 fds[n] = fds[num_fds-1];
71                 assert(fds[n]->backend_info == num_fds-1);
72                 fds[n]->backend_info = n;
73         } else if (num_fds == 1) {
74                 /* Free everything when no more fds. */
75                 pollfds = tal_free(pollfds);
76                 fds = NULL;
77                 max_fds = 0;
78         }
79         num_fds--;
80         fd->backend_info = -1;
81
82         /* Closing a local socket doesn't wake poll() because other end
83          * has them open.  See 2.6.  When should I use shutdown()?
84          * in http://www.faqs.org/faqs/unix-faq/socket/ */
85         shutdown(fd->fd, SHUT_RDWR);
86
87         close(fd->fd);
88 }
89
90 bool add_listener(struct io_listener *l)
91 {
92         if (!add_fd(&l->fd, POLLIN))
93                 return false;
94         return true;
95 }
96
97 void remove_from_always(struct io_conn *conn)
98 {
99         struct io_conn **p = &always;
100
101         while (*p != conn)
102                 p = &(*p)->list;
103
104         *p = conn->list;
105 }
106
107 void backend_new_closing(struct io_conn *conn)
108 {
109         /* Already on always list?  Remove it. */
110         if (conn->list)
111                 remove_from_always(conn);
112
113         conn->list = closing;
114         closing = conn;
115 }
116
117 void backend_new_always(struct io_conn *conn)
118 {
119         /* May already be in always list (other plan), or closing. */
120         if (!conn->list) {
121                 conn->list = always;
122                 always = conn;
123         }
124 }
125
126 void backend_new_plan(struct io_conn *conn)
127 {
128         struct pollfd *pfd = &pollfds[conn->fd.backend_info];
129
130         if (pfd->events)
131                 num_waiting--;
132
133         pfd->events = 0;
134         if (conn->plan[IO_IN].status == IO_POLLING)
135                 pfd->events |= POLLIN;
136         if (conn->plan[IO_OUT].status == IO_POLLING)
137                 pfd->events |= POLLOUT;
138
139         if (pfd->events) {
140                 num_waiting++;
141                 pfd->fd = conn->fd.fd;
142         } else {
143                 pfd->fd = -conn->fd.fd;
144         }
145 }
146
147 void backend_wake(const void *wait)
148 {
149         unsigned int i;
150
151         for (i = 0; i < num_fds; i++) {
152                 struct io_conn *c;
153
154                 /* Ignore listeners */
155                 if (fds[i]->listener)
156                         continue;
157
158                 c = (void *)fds[i];
159                 if (c->plan[IO_IN].status == IO_WAITING
160                     && c->plan[IO_IN].arg.u1.const_vp == wait)
161                         io_do_wakeup(c, IO_IN);
162
163                 if (c->plan[IO_OUT].status == IO_WAITING
164                     && c->plan[IO_OUT].arg.u1.const_vp == wait)
165                         io_do_wakeup(c, IO_OUT);
166         }
167 }
168
169 bool add_conn(struct io_conn *c)
170 {
171         return add_fd(&c->fd, 0);
172 }
173
174 static void del_conn(struct io_conn *conn)
175 {
176         del_fd(&conn->fd);
177         if (conn->finish) {
178                 /* Saved by io_close */
179                 errno = conn->plan[IO_IN].arg.u1.s;
180                 conn->finish(conn, conn->finish_arg);
181         }
182         tal_free(conn);
183 }
184
185 void del_listener(struct io_listener *l)
186 {
187         del_fd(&l->fd);
188 }
189
190 static void accept_conn(struct io_listener *l)
191 {
192         int fd = accept(l->fd.fd, NULL, NULL);
193
194         /* FIXME: What to do here? */
195         if (fd < 0)
196                 return;
197
198         io_new_conn(l->ctx, fd, l->init, l->arg);
199 }
200
201 /* It's OK to miss some, as long as we make progress. */
202 static bool close_conns(void)
203 {
204         bool ret = false;
205
206         while (closing) {
207                 struct io_conn *conn = closing;
208
209                 assert(conn->plan[IO_IN].status == IO_CLOSING);
210                 assert(conn->plan[IO_OUT].status == IO_CLOSING);
211
212                 closing = closing->list;
213                 del_conn(conn);
214                 ret = true;
215         }
216         return ret;
217 }
218
219 static bool handle_always(void)
220 {
221         bool ret = false;
222
223         while (always) {
224                 struct io_conn *conn = always;
225
226                 assert(conn->plan[IO_IN].status == IO_ALWAYS
227                        || conn->plan[IO_OUT].status == IO_ALWAYS);
228
229                 /* Remove from list, and mark it so it knows that. */
230                 always = always->list;
231                 conn->list = NULL;
232                 io_do_always(conn);
233                 ret = true;
234         }
235         return ret;
236 }
237
238 /* This is the main loop. */
239 void *io_loop(struct timers *timers, struct list_head *expired)
240 {
241         void *ret;
242
243         /* if timers is NULL, expired must be.  If not, not. */
244         assert(!timers == !expired);
245
246         /* Make sure this is empty if we exit for some other reason. */
247         if (expired)
248                 list_head_init(expired);
249
250         while (!io_loop_return) {
251                 int i, r, ms_timeout = -1;
252
253                 if (close_conns()) {
254                         /* Could have started/finished more. */
255                         continue;
256                 }
257
258                 if (handle_always()) {
259                         /* Could have started/finished more. */
260                         continue;
261                 }
262
263                 /* Everything closed? */
264                 if (num_fds == 0)
265                         break;
266
267                 /* You can't tell them all to go to sleep! */
268                 assert(num_waiting);
269
270                 if (timers) {
271                         struct timeabs now, first;
272
273                         now = time_now();
274
275                         /* Call functions for expired timers. */
276                         timers_expire(timers, now, expired);
277                         if (!list_empty(expired))
278                                 break;
279
280                         /* Now figure out how long to wait for the next one. */
281                         if (timer_earliest(timers, &first)) {
282                                 uint64_t next;
283                                 next = time_to_msec(time_between(first, now));
284                                 if (next < INT_MAX)
285                                         ms_timeout = next;
286                                 else
287                                         ms_timeout = INT_MAX;
288                         }
289                 }
290
291                 r = poll(pollfds, num_fds, ms_timeout);
292                 if (r < 0)
293                         break;
294
295                 for (i = 0; i < num_fds && !io_loop_return; i++) {
296                         struct io_conn *c = (void *)fds[i];
297                         int events = pollfds[i].revents;
298
299                         if (r == 0)
300                                 break;
301
302                         if (fds[i]->listener) {
303                                 if (events & POLLIN) {
304                                         accept_conn((void *)c);
305                                         r--;
306                                 }
307                         } else if (events & (POLLIN|POLLOUT)) {
308                                 r--;
309                                 io_ready(c, events);
310                         } else if (events & (POLLHUP|POLLNVAL|POLLERR)) {
311                                 r--;
312                                 errno = EBADF;
313                                 io_close(c);
314                         }
315                 }
316         }
317
318         close_conns();
319
320         ret = io_loop_return;
321         io_loop_return = NULL;
322
323         return ret;
324 }