lib/tevent: Add a thread-safe tevent backend
[obnox/samba/samba-obnox.git] / lib / tevent / tevent_poll.c
1 /*
2    Unix SMB/CIFS implementation.
3    main select loop and event handling
4    Copyright (C) Andrew Tridgell        2003-2005
5    Copyright (C) Stefan Metzmacher      2005-2009
6
7      ** NOTE! The following LGPL license applies to the tevent
8      ** library. This does NOT imply that all of Samba is released
9      ** under the LGPL
10
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU Lesser General Public
13    License as published by the Free Software Foundation; either
14    version 3 of the License, or (at your option) any later version.
15
16    This library is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    Lesser General Public License for more details.
20
21    You should have received a copy of the GNU Lesser General Public
22    License along with this library; if not, see <http://www.gnu.org/licenses/>.
23 */
24
25 #include "replace.h"
26 #include "system/filesys.h"
27 #include "system/select.h"
28 #include "tevent.h"
29 #include "tevent_util.h"
30 #include "tevent_internal.h"
31
32 struct poll_event_context {
33         /* a pointer back to the generic event_context */
34         struct tevent_context *ev;
35
36         /*
37          * A DLIST for fresh fde's added by poll_event_add_fd but not
38          * picked up yet by poll_event_loop_once
39          */
40         struct tevent_fd *fresh;
41
42         /*
43          * These two arrays are maintained together.
44          */
45         struct pollfd *fds;
46         struct tevent_fd **fdes;
47         unsigned num_fds;
48
49         /*
50          * Signal fd to wake the poll() thread
51          */
52         int signal_fd;
53
54         /* information for exiting from the event loop */
55         int exit_code;
56 };
57
58 /*
59   create a select_event_context structure.
60 */
61 static int poll_event_context_init(struct tevent_context *ev)
62 {
63         struct poll_event_context *poll_ev;
64
65         poll_ev = talloc_zero(ev, struct poll_event_context);
66         if (poll_ev == NULL) {
67                 return -1;
68         }
69         poll_ev->ev = ev;
70         poll_ev->signal_fd = -1;
71         ev->additional_data = poll_ev;
72         return 0;
73 }
74
75 static int poll_event_mt_destructor(struct poll_event_context *poll_ev)
76 {
77         if (poll_ev->signal_fd != -1) {
78                 close(poll_ev->signal_fd);
79                 poll_ev->signal_fd = -1;
80         }
81         if (poll_ev->num_fds == 0) {
82                 return 0;
83         }
84         if (poll_ev->fds[0].fd != -1) {
85                 close(poll_ev->fds[0].fd);
86                 poll_ev->fds[0].fd = -1;
87         }
88         return 0;
89 }
90
91 static bool set_nonblock(int fd)
92 {
93         int val;
94
95         val = fcntl(fd, F_GETFL, 0);
96         if (val == -1) {
97                 return false;
98         }
99         val |= O_NONBLOCK;
100
101         return (fcntl(fd, F_SETFL, val) != -1);
102 }
103
104 static int poll_event_context_init_mt(struct tevent_context *ev)
105 {
106         struct poll_event_context *poll_ev;
107         struct pollfd *pfd;
108         int fds[2];
109         int ret;
110
111         ret = poll_event_context_init(ev);
112         if (ret == -1) {
113                 return ret;
114         }
115
116         poll_ev = talloc_get_type_abort(
117                 ev->additional_data, struct poll_event_context);
118
119         poll_ev->fds = talloc_zero(poll_ev, struct pollfd);
120         if (poll_ev->fds == NULL) {
121                 return -1;
122         }
123
124         ret = pipe(fds);
125         if (ret == -1) {
126                 return -1;
127         }
128
129         if (!set_nonblock(fds[0]) || !set_nonblock(fds[1])) {
130                 close(fds[0]);
131                 close(fds[1]);
132                 return -1;
133         }
134
135         poll_ev->signal_fd = fds[1];
136
137         pfd = &poll_ev->fds[0];
138         pfd->fd = fds[0];
139         pfd->events = (POLLIN|POLLHUP);
140
141         poll_ev->num_fds = 1;
142
143         talloc_set_destructor(poll_ev, poll_event_mt_destructor);
144
145         return 0;
146 }
147
148 static void poll_event_wake_pollthread(struct poll_event_context *poll_ev)
149 {
150         char c;
151         ssize_t ret;
152
153         if (poll_ev->signal_fd == -1) {
154                 return;
155         }
156         c = 0;
157         do {
158                 ret = write(poll_ev->signal_fd, &c, sizeof(c));
159         } while ((ret == -1) && (errno == EINTR));
160 }
161
162 static void poll_event_drain_signal_fd(struct poll_event_context *poll_ev)
163 {
164         char buf[16];
165         ssize_t ret;
166         int fd;
167
168         if (poll_ev->signal_fd == -1) {
169                 return;
170         }
171
172         if (poll_ev->num_fds < 1) {
173                 return;
174         }
175         fd = poll_ev->fds[0].fd;
176
177         do {
178                 ret = read(fd, buf, sizeof(buf));
179         } while (ret == sizeof(buf));
180 }
181
182 /*
183   destroy an fd_event
184 */
185 static int poll_event_fd_destructor(struct tevent_fd *fde)
186 {
187         struct tevent_context *ev = fde->event_ctx;
188         struct poll_event_context *poll_ev;
189         uint64_t del_idx = fde->additional_flags;
190
191         if (ev == NULL) {
192                 goto done;
193         }
194
195         poll_ev = talloc_get_type_abort(
196                 ev->additional_data, struct poll_event_context);
197
198         poll_ev->fdes[del_idx] = NULL;
199         poll_event_wake_pollthread(poll_ev);
200 done:
201         return tevent_common_fd_destructor(fde);
202 }
203
204 static int poll_fresh_fde_destructor(struct tevent_fd *fde)
205 {
206         struct poll_event_context *poll_ev = talloc_get_type_abort(
207                 fde->event_ctx->additional_data, struct poll_event_context);
208         DLIST_REMOVE(poll_ev->fresh, fde);
209         return 0;
210 }
211
212 static void poll_event_schedule_immediate(struct tevent_immediate *im,
213                                           struct tevent_context *ev,
214                                           tevent_immediate_handler_t handler,
215                                           void *private_data,
216                                           const char *handler_name,
217                                           const char *location)
218 {
219         struct poll_event_context *poll_ev = talloc_get_type_abort(
220                 ev->additional_data, struct poll_event_context);
221
222         tevent_common_schedule_immediate(im, ev, handler, private_data,
223                                          handler_name, location);
224         poll_event_wake_pollthread(poll_ev);
225 }
226
227 /*
228   add a fd based event
229   return NULL on failure (memory allocation error)
230 */
231 static struct tevent_fd *poll_event_add_fd(struct tevent_context *ev,
232                                            TALLOC_CTX *mem_ctx,
233                                            int fd, uint16_t flags,
234                                            tevent_fd_handler_t handler,
235                                            void *private_data,
236                                            const char *handler_name,
237                                            const char *location)
238 {
239         struct poll_event_context *poll_ev = talloc_get_type_abort(
240                 ev->additional_data, struct poll_event_context);
241         struct tevent_fd *fde;
242
243         if (fd < 0) {
244                 return NULL;
245         }
246
247         fde = talloc(mem_ctx ? mem_ctx : ev, struct tevent_fd);
248         if (fde == NULL) {
249                 return NULL;
250         }
251         fde->event_ctx          = ev;
252         fde->fd                 = fd;
253         fde->flags              = flags;
254         fde->handler            = handler;
255         fde->close_fn           = NULL;
256         fde->private_data       = private_data;
257         fde->handler_name       = handler_name;
258         fde->location           = location;
259         fde->additional_flags   = 0;
260         fde->additional_data    = NULL;
261
262         DLIST_ADD(poll_ev->fresh, fde);
263         talloc_set_destructor(fde, poll_fresh_fde_destructor);
264         poll_event_wake_pollthread(poll_ev);
265
266         /*
267          * poll_event_loop_poll will take care of the rest in
268          * poll_event_setup_fresh
269          */
270         return fde;
271 }
272
273 /*
274   set the fd event flags
275 */
276 static void poll_event_set_fd_flags(struct tevent_fd *fde, uint16_t flags)
277 {
278         struct poll_event_context *poll_ev = talloc_get_type_abort(
279                 fde->event_ctx->additional_data, struct poll_event_context);
280         uint64_t idx = fde->additional_flags;
281         uint16_t pollflags = 0;
282
283         if (flags & TEVENT_FD_READ) {
284                 pollflags |= (POLLIN|POLLHUP);
285         }
286         if (flags & TEVENT_FD_WRITE) {
287                 pollflags |= (POLLOUT);
288         }
289
290         poll_ev->fds[idx].events = pollflags;
291
292         fde->flags = flags;
293         poll_event_wake_pollthread(poll_ev);
294 }
295
296 static bool poll_event_setup_fresh(struct tevent_context *ev,
297                                    struct poll_event_context *poll_ev)
298 {
299         struct tevent_fd *fde, *next;
300         unsigned num_fresh, num_fds;
301
302         if (poll_ev->fresh == NULL) {
303                 return true;
304         }
305
306         num_fresh = 0;
307         for (fde = poll_ev->fresh; fde; fde = fde->next) {
308                 num_fresh += 1;
309         }
310         num_fds = poll_ev->num_fds + num_fresh;
311
312         /*
313          * We check the length of fdes here. It is the last one
314          * enlarged, so if the realloc for poll_fd->fdes fails,
315          * poll_fd->fds will have at least the size of poll_fd->fdes
316          */
317
318         if (num_fds >= talloc_array_length(poll_ev->fdes)) {
319                 struct pollfd *tmp_fds;
320                 struct tevent_fd **tmp_fdes;
321                 unsigned array_length;
322
323                 array_length = (num_fds + 15) & ~15; /* round up to 16 */
324
325                 tmp_fds = talloc_realloc(
326                         poll_ev, poll_ev->fds, struct pollfd, array_length);
327                 if (tmp_fds == NULL) {
328                         return false;
329                 }
330                 poll_ev->fds = tmp_fds;
331
332                 tmp_fdes = talloc_realloc(
333                         poll_ev, poll_ev->fdes, struct tevent_fd *,
334                         array_length);
335                 if (tmp_fdes == NULL) {
336                         return false;
337                 }
338                 poll_ev->fdes = tmp_fdes;
339         }
340
341         for (fde = poll_ev->fresh; fde; fde = next) {
342                 struct pollfd *pfd;
343
344                 pfd = &poll_ev->fds[poll_ev->num_fds];
345
346                 pfd->fd = fde->fd;
347                 pfd->events = 0;
348                 pfd->revents = 0;
349
350                 if (fde->flags & TEVENT_FD_READ) {
351                         pfd->events |= (POLLIN|POLLHUP);
352                 }
353                 if (fde->flags & TEVENT_FD_WRITE) {
354                         pfd->events |= (POLLOUT);
355                 }
356
357                 fde->additional_flags = poll_ev->num_fds;
358                 poll_ev->fdes[poll_ev->num_fds] = fde;
359
360                 next = fde->next;
361                 DLIST_REMOVE(poll_ev->fresh, fde);
362                 DLIST_ADD(ev->fd_events, fde);
363
364                 talloc_set_destructor(fde, poll_event_fd_destructor);
365
366                 poll_ev->num_fds += 1;
367         }
368         return true;
369 }
370
371 /*
372   event loop handling using poll()
373 */
374 static int poll_event_loop_poll(struct tevent_context *ev,
375                                 struct timeval *tvalp)
376 {
377         struct poll_event_context *poll_ev = talloc_get_type_abort(
378                 ev->additional_data, struct poll_event_context);
379         int pollrtn;
380         int timeout = -1;
381         unsigned first_fd;
382         unsigned i;
383
384         if (ev->signal_events && tevent_common_check_signal(ev)) {
385                 return 0;
386         }
387
388         if (tvalp != NULL) {
389                 timeout = tvalp->tv_sec * 1000;
390                 timeout += (tvalp->tv_usec + 999) / 1000;
391         }
392
393         poll_event_drain_signal_fd(poll_ev);
394
395         if (!poll_event_setup_fresh(ev, poll_ev)) {
396                 return -1;
397         }
398
399         tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
400         pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
401         tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_AFTER_WAIT);
402
403         if (pollrtn == -1 && errno == EINTR && ev->signal_events) {
404                 tevent_common_check_signal(ev);
405                 return 0;
406         }
407
408         if (pollrtn == 0 && tvalp) {
409                 /* we don't care about a possible delay here */
410                 tevent_common_loop_timer_delay(ev);
411                 return 0;
412         }
413
414         if (pollrtn <= 0) {
415                 /*
416                  * No fd's ready
417                  */
418                 return 0;
419         }
420
421         first_fd = (poll_ev->signal_fd != -1) ? 1 : 0;
422
423         /* at least one file descriptor is ready - check
424            which ones and call the handler, being careful to allow
425            the handler to remove itself when called */
426
427         for (i=first_fd; i<poll_ev->num_fds; i++) {
428                 struct pollfd *pfd;
429                 struct tevent_fd *fde;
430                 uint16_t flags = 0;
431
432                 fde = poll_ev->fdes[i];
433                 if (fde == NULL) {
434                         /*
435                          * This fde was talloc_free()'ed. Delete it
436                          * from the arrays
437                          */
438                         poll_ev->num_fds -= 1;
439                         poll_ev->fds[i] = poll_ev->fds[poll_ev->num_fds];
440                         poll_ev->fdes[i] = poll_ev->fdes[poll_ev->num_fds];
441                         if (poll_ev->fdes[i] != NULL) {
442                                 poll_ev->fdes[i]->additional_flags = i;
443                         }
444                         continue;
445                 }
446
447                 pfd = &poll_ev->fds[i];
448
449                 if (pfd->revents & (POLLHUP|POLLERR)) {
450                         /* If we only wait for TEVENT_FD_WRITE, we
451                            should not tell the event handler about it,
452                            and remove the writable flag, as we only
453                            report errors when waiting for read events
454                            to match the select behavior. */
455                         if (!(fde->flags & TEVENT_FD_READ)) {
456                                 TEVENT_FD_NOT_WRITEABLE(fde);
457                                 continue;
458                         }
459                         flags |= TEVENT_FD_READ;
460                 }
461                 if (pfd->revents & POLLIN) {
462                         flags |= TEVENT_FD_READ;
463                 }
464                 if (pfd->revents & POLLOUT) {
465                         flags |= TEVENT_FD_WRITE;
466                 }
467                 if (flags != 0) {
468                         fde->handler(ev, fde, flags, fde->private_data);
469                         break;
470                 }
471         }
472
473         return 0;
474 }
475
476 /*
477   do a single event loop using the events defined in ev
478 */
479 static int poll_event_loop_once(struct tevent_context *ev,
480                                 const char *location)
481 {
482         struct timeval tval;
483
484         if (ev->signal_events &&
485             tevent_common_check_signal(ev)) {
486                 return 0;
487         }
488
489         if (ev->immediate_events &&
490             tevent_common_loop_immediate(ev)) {
491                 return 0;
492         }
493
494         tval = tevent_common_loop_timer_delay(ev);
495         if (tevent_timeval_is_zero(&tval)) {
496                 return 0;
497         }
498
499         return poll_event_loop_poll(ev, &tval);
500 }
501
502 static const struct tevent_ops poll_event_ops = {
503         .context_init           = poll_event_context_init,
504         .add_fd                 = poll_event_add_fd,
505         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
506         .get_fd_flags           = tevent_common_fd_get_flags,
507         .set_fd_flags           = poll_event_set_fd_flags,
508         .add_timer              = tevent_common_add_timer,
509         .schedule_immediate     = tevent_common_schedule_immediate,
510         .add_signal             = tevent_common_add_signal,
511         .loop_once              = poll_event_loop_once,
512         .loop_wait              = tevent_common_loop_wait,
513 };
514
515 _PRIVATE_ bool tevent_poll_init(void)
516 {
517         return tevent_register_backend("poll", &poll_event_ops);
518 }
519
520 static const struct tevent_ops poll_event_mt_ops = {
521         .context_init           = poll_event_context_init_mt,
522         .add_fd                 = poll_event_add_fd,
523         .set_fd_close_fn        = tevent_common_fd_set_close_fn,
524         .get_fd_flags           = tevent_common_fd_get_flags,
525         .set_fd_flags           = poll_event_set_fd_flags,
526         .add_timer              = tevent_common_add_timer,
527         .schedule_immediate     = poll_event_schedule_immediate,
528         .add_signal             = tevent_common_add_signal,
529         .loop_once              = poll_event_loop_once,
530         .loop_wait              = tevent_common_loop_wait,
531 };
532
533 _PRIVATE_ bool tevent_poll_mt_init(void)
534 {
535         return tevent_register_backend("poll_mt", &poll_event_mt_ops);
536 }