0c02e46f3ca16e6478fe820ae459d5272e4dfcbc
[ira/wip.git] / lib / tevent / tevent.c
1 /* 
2    Unix SMB/CIFS implementation.
3    main select loop and event handling
4    Copyright (C) Andrew Tridgell 2003
5    Copyright (C) Stefan Metzmacher 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 /*
26   PLEASE READ THIS BEFORE MODIFYING!
27
28   This module is a general abstraction for the main select loop and
29   event handling. Do not ever put any localised hacks in here, instead
30   register one of the possible event types and implement that event
31   somewhere else.
32
33   There are 2 types of event handling that are handled in this module:
34
35   1) a file descriptor becoming readable or writeable. This is mostly
36      used for network sockets, but can be used for any type of file
37      descriptor. You may only register one handler for each file
38      descriptor/io combination or you will get unpredictable results
39      (this means that you can have a handler for read events, and a
40      separate handler for write events, but not two handlers that are
41      both handling read events)
42
43   2) a timed event. You can register an event that happens at a
44      specific time.  You can register as many of these as you
45      like. They are single shot - add a new timed event in the event
46      handler to get another event.
47
48   To setup a set of events you first need to create a event_context
49   structure using the function tevent_context_init(); This returns a
50   'struct tevent_context' that you use in all subsequent calls.
51
52   After that you can add/remove events that you are interested in
53   using tevent_add_*() and talloc_free()
54
55   Finally, you call tevent_loop_wait_once() to block waiting for one of the
56   events to occor or tevent_loop_wait() which will loop
57   forever.
58
59 */
60 #include "replace.h"
61 #include "system/filesys.h"
62 #define TEVENT_DEPRECATED 1
63 #include "tevent.h"
64 #include "tevent_internal.h"
65 #include "tevent_util.h"
66
67 struct tevent_ops_list {
68         struct tevent_ops_list *next, *prev;
69         const char *name;
70         const struct tevent_ops *ops;
71 };
72
73 /* list of registered event backends */
74 static struct tevent_ops_list *tevent_backends = NULL;
75 static char *tevent_default_backend = NULL;
76
77 /*
78   register an events backend
79 */
80 bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
81 {
82         struct tevent_ops_list *e;
83
84         for (e = tevent_backends; e != NULL; e = e->next) {
85                 if (0 == strcmp(e->name, name)) {
86                         /* already registered, skip it */
87                         return true;
88                 }
89         }
90
91         e = talloc(talloc_autofree_context(), struct tevent_ops_list);
92         if (e == NULL) return false;
93
94         e->name = name;
95         e->ops = ops;
96         DLIST_ADD(tevent_backends, e);
97
98         return true;
99 }
100
101 /*
102   set the default event backend
103  */
104 void tevent_set_default_backend(const char *backend)
105 {
106         talloc_free(tevent_default_backend);
107         tevent_default_backend = talloc_strdup(talloc_autofree_context(),
108                                                backend);
109 }
110
111 /*
112   initialise backends if not already done
113 */
114 static void tevent_backend_init(void)
115 {
116         tevent_select_init();
117         tevent_standard_init();
118 #ifdef HAVE_EPOLL
119         tevent_epoll_init();
120 #endif
121 }
122
123 /*
124   list available backends
125 */
126 const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
127 {
128         const char **list = NULL;
129         struct tevent_ops_list *e;
130
131         tevent_backend_init();
132
133         for (e=tevent_backends;e;e=e->next) {
134                 list = ev_str_list_add(list, e->name);
135         }
136
137         talloc_steal(mem_ctx, list);
138
139         return list;
140 }
141
142 int tevent_common_context_destructor(struct tevent_context *ev)
143 {
144         struct tevent_fd *fd, *fn;
145         struct tevent_timer *te, *tn;
146         struct tevent_immediate *ie, *in;
147         struct tevent_signal *se, *sn;
148
149         if (ev->pipe_fde) {
150                 talloc_free(ev->pipe_fde);
151                 ev->pipe_fde = NULL;
152         }
153
154         for (fd = ev->fd_events; fd; fd = fn) {
155                 fn = fd->next;
156                 fd->event_ctx = NULL;
157                 DLIST_REMOVE(ev->fd_events, fd);
158         }
159
160         for (te = ev->timer_events; te; te = tn) {
161                 tn = te->next;
162                 te->event_ctx = NULL;
163                 DLIST_REMOVE(ev->timer_events, te);
164         }
165
166         for (ie = ev->immediate_events; ie; ie = in) {
167                 in = ie->next;
168                 ie->event_ctx = NULL;
169                 ie->cancel_fn = NULL;
170                 DLIST_REMOVE(ev->immediate_events, ie);
171         }
172
173         for (se = ev->signal_events; se; se = sn) {
174                 sn = se->next;
175                 se->event_ctx = NULL;
176                 DLIST_REMOVE(ev->signal_events, se);
177         }
178
179         return 0;
180 }
181
182 /*
183   create a event_context structure for a specific implemementation.
184   This must be the first events call, and all subsequent calls pass
185   this event_context as the first element. Event handlers also
186   receive this as their first argument.
187
188   This function is for allowing third-party-applications to hook in gluecode
189   to their own event loop code, so that they can make async usage of our client libs
190
191   NOTE: use tevent_context_init() inside of samba!
192 */
193 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
194                                                       const struct tevent_ops *ops)
195 {
196         struct tevent_context *ev;
197         int ret;
198
199         ev = talloc_zero(mem_ctx, struct tevent_context);
200         if (!ev) return NULL;
201
202         talloc_set_destructor(ev, tevent_common_context_destructor);
203
204         ev->ops = ops;
205
206         ret = ev->ops->context_init(ev);
207         if (ret != 0) {
208                 talloc_free(ev);
209                 return NULL;
210         }
211
212         return ev;
213 }
214
215 /*
216   create a event_context structure. This must be the first events
217   call, and all subsequent calls pass this event_context as the first
218   element. Event handlers also receive this as their first argument.
219 */
220 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
221                                                   const char *name)
222 {
223         struct tevent_ops_list *e;
224
225         tevent_backend_init();
226
227         if (name == NULL) {
228                 name = tevent_default_backend;
229         }
230         if (name == NULL) {
231                 name = "standard";
232         }
233
234         for (e=tevent_backends;e;e=e->next) {
235                 if (strcmp(name, e->name) == 0) {
236                         return tevent_context_init_ops(mem_ctx, e->ops);
237                 }
238         }
239         return NULL;
240 }
241
242
243 /*
244   create a event_context structure. This must be the first events
245   call, and all subsequent calls pass this event_context as the first
246   element. Event handlers also receive this as their first argument.
247 */
248 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
249 {
250         return tevent_context_init_byname(mem_ctx, NULL);
251 }
252
253 /*
254   add a fd based event
255   return NULL on failure (memory allocation error)
256
257   if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
258   the returned fd_event context is freed
259 */
260 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
261                                  TALLOC_CTX *mem_ctx,
262                                  int fd,
263                                  uint16_t flags,
264                                  tevent_fd_handler_t handler,
265                                  void *private_data,
266                                  const char *handler_name,
267                                  const char *location)
268 {
269         return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
270                                handler_name, location);
271 }
272
273 /*
274   set a close function on the fd event
275 */
276 void tevent_fd_set_close_fn(struct tevent_fd *fde,
277                             tevent_fd_close_fn_t close_fn)
278 {
279         if (!fde) return;
280         if (!fde->event_ctx) return;
281         fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
282 }
283
284 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
285                                     struct tevent_fd *fde,
286                                     int fd,
287                                     void *private_data)
288 {
289         close(fd);
290 }
291
292 void tevent_fd_set_auto_close(struct tevent_fd *fde)
293 {
294         tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
295 }
296
297 /*
298   return the fd event flags
299 */
300 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
301 {
302         if (!fde) return 0;
303         if (!fde->event_ctx) return 0;
304         return fde->event_ctx->ops->get_fd_flags(fde);
305 }
306
307 /*
308   set the fd event flags
309 */
310 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
311 {
312         if (!fde) return;
313         if (!fde->event_ctx) return;
314         fde->event_ctx->ops->set_fd_flags(fde, flags);
315 }
316
317 bool tevent_signal_support(struct tevent_context *ev)
318 {
319         if (ev->ops->add_signal) {
320                 return true;
321         }
322         return false;
323 }
324
325 static void (*tevent_abort_fn)(const char *reason);
326
327 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
328 {
329         tevent_abort_fn = abort_fn;
330 }
331
332 static void tevent_abort(struct tevent_context *ev, const char *reason)
333 {
334         tevent_debug(ev, TEVENT_DEBUG_FATAL,
335                      "abort: %s\n", reason);
336
337         if (!tevent_abort_fn) {
338                 abort();
339         }
340
341         tevent_abort_fn(reason);
342 }
343
344 /*
345   add a timer event
346   return NULL on failure
347 */
348 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
349                                        TALLOC_CTX *mem_ctx,
350                                        struct timeval next_event,
351                                        tevent_timer_handler_t handler,
352                                        void *private_data,
353                                        const char *handler_name,
354                                        const char *location)
355 {
356         return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
357                                   handler_name, location);
358 }
359
360 /*
361   allocate an immediate event
362   return NULL on failure (memory allocation error)
363 */
364 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
365                                                   const char *location)
366 {
367         struct tevent_immediate *im;
368
369         im = talloc(mem_ctx, struct tevent_immediate);
370         if (im == NULL) return NULL;
371
372         im->prev                = NULL;
373         im->next                = NULL;
374         im->event_ctx           = NULL;
375         im->create_location     = location;
376         im->handler             = NULL;
377         im->private_data        = NULL;
378         im->handler_name        = NULL;
379         im->schedule_location   = NULL;
380         im->cancel_fn           = NULL;
381         im->additional_data     = NULL;
382
383         return im;
384 }
385
386 /*
387   schedule an immediate event
388   return NULL on failure
389 */
390 void _tevent_schedule_immediate(struct tevent_immediate *im,
391                                 struct tevent_context *ev,
392                                 tevent_immediate_handler_t handler,
393                                 void *private_data,
394                                 const char *handler_name,
395                                 const char *location)
396 {
397         ev->ops->schedule_immediate(im, ev, handler, private_data,
398                                     handler_name, location);
399 }
400
401 /*
402   add a signal event
403
404   sa_flags are flags to sigaction(2)
405
406   return NULL on failure
407 */
408 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
409                                          TALLOC_CTX *mem_ctx,
410                                          int signum,
411                                          int sa_flags,
412                                          tevent_signal_handler_t handler,
413                                          void *private_data,
414                                          const char *handler_name,
415                                          const char *location)
416 {
417         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
418                                    handler_name, location);
419 }
420
421 void tevent_loop_allow_nesting(struct tevent_context *ev)
422 {
423         ev->nesting.allowed = true;
424 }
425
426 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
427                                   tevent_nesting_hook hook,
428                                   void *private_data)
429 {
430         if (ev->nesting.hook_fn && 
431             (ev->nesting.hook_fn != hook ||
432              ev->nesting.hook_private != private_data)) {
433                 /* the way the nesting hook code is currently written
434                    we cannot support two different nesting hooks at the
435                    same time. */
436                 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
437         }
438         ev->nesting.hook_fn = hook;
439         ev->nesting.hook_private = private_data;
440 }
441
442 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
443 {
444         const char *reason;
445
446         reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
447                                  location);
448         if (!reason) {
449                 reason = "tevent_loop_once() nesting";
450         }
451
452         tevent_abort(ev, reason);
453 }
454
455 /*
456   do a single event loop using the events defined in ev 
457 */
458 int _tevent_loop_once(struct tevent_context *ev, const char *location)
459 {
460         int ret;
461         void *nesting_stack_ptr = NULL;
462
463         ev->nesting.level++;
464
465         if (ev->nesting.level > 1) {
466                 if (!ev->nesting.allowed) {
467                         tevent_abort_nesting(ev, location);
468                         errno = ELOOP;
469                         return -1;
470                 }
471         }
472         if (ev->nesting.level > 0) {
473                 if (ev->nesting.hook_fn) {
474                         int ret2;
475                         ret2 = ev->nesting.hook_fn(ev,
476                                                    ev->nesting.hook_private,
477                                                    ev->nesting.level,
478                                                    true,
479                                                    (void *)&nesting_stack_ptr,
480                                                    location);
481                         if (ret2 != 0) {
482                                 ret = ret2;
483                                 goto done;
484                         }
485                 }
486         }
487
488         ret = ev->ops->loop_once(ev, location);
489
490         if (ev->nesting.level > 0) {
491                 if (ev->nesting.hook_fn) {
492                         int ret2;
493                         ret2 = ev->nesting.hook_fn(ev,
494                                                    ev->nesting.hook_private,
495                                                    ev->nesting.level,
496                                                    false,
497                                                    (void *)&nesting_stack_ptr,
498                                                    location);
499                         if (ret2 != 0) {
500                                 ret = ret2;
501                                 goto done;
502                         }
503                 }
504         }
505
506 done:
507         ev->nesting.level--;
508         return ret;
509 }
510
511 /*
512   this is a performance optimization for the samba4 nested event loop problems
513 */
514 int _tevent_loop_until(struct tevent_context *ev,
515                        bool (*finished)(void *private_data),
516                        void *private_data,
517                        const char *location)
518 {
519         int ret = 0;
520         void *nesting_stack_ptr = NULL;
521
522         ev->nesting.level++;
523
524         if (ev->nesting.level > 1) {
525                 if (!ev->nesting.allowed) {
526                         tevent_abort_nesting(ev, location);
527                         errno = ELOOP;
528                         return -1;
529                 }
530         }
531         if (ev->nesting.level > 0) {
532                 if (ev->nesting.hook_fn) {
533                         int ret2;
534                         ret2 = ev->nesting.hook_fn(ev,
535                                                    ev->nesting.hook_private,
536                                                    ev->nesting.level,
537                                                    true,
538                                                    (void *)&nesting_stack_ptr,
539                                                    location);
540                         if (ret2 != 0) {
541                                 ret = ret2;
542                                 goto done;
543                         }
544                 }
545         }
546
547         while (!finished(private_data)) {
548                 ret = ev->ops->loop_once(ev, location);
549                 if (ret != 0) {
550                         break;
551                 }
552         }
553
554         if (ev->nesting.level > 0) {
555                 if (ev->nesting.hook_fn) {
556                         int ret2;
557                         ret2 = ev->nesting.hook_fn(ev,
558                                                    ev->nesting.hook_private,
559                                                    ev->nesting.level,
560                                                    false,
561                                                    (void *)&nesting_stack_ptr,
562                                                    location);
563                         if (ret2 != 0) {
564                                 ret = ret2;
565                                 goto done;
566                         }
567                 }
568         }
569
570 done:
571         ev->nesting.level--;
572         return ret;
573 }
574
575 /*
576   return on failure or (with 0) if all fd events are removed
577 */
578 int tevent_common_loop_wait(struct tevent_context *ev,
579                             const char *location)
580 {
581         /*
582          * loop as long as we have events pending
583          */
584         while (ev->fd_events ||
585                ev->timer_events ||
586                ev->immediate_events ||
587                ev->signal_events) {
588                 int ret;
589                 ret = _tevent_loop_once(ev, location);
590                 if (ret != 0) {
591                         tevent_debug(ev, TEVENT_DEBUG_FATAL,
592                                      "_tevent_loop_once() failed: %d - %s\n",
593                                      ret, strerror(errno));
594                         return ret;
595                 }
596         }
597
598         tevent_debug(ev, TEVENT_DEBUG_WARNING,
599                      "tevent_common_loop_wait() out of events\n");
600         return 0;
601 }
602
603 /*
604   return on failure or (with 0) if all fd events are removed
605 */
606 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
607 {
608         return ev->ops->loop_wait(ev, location);
609 }