Change uint_t to unsigned int in lib/replace
[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                 close(ev->pipe_fds[0]);
152                 close(ev->pipe_fds[1]);
153                 ev->pipe_fde = NULL;
154         }
155
156         for (fd = ev->fd_events; fd; fd = fn) {
157                 fn = fd->next;
158                 fd->event_ctx = NULL;
159                 DLIST_REMOVE(ev->fd_events, fd);
160         }
161
162         for (te = ev->timer_events; te; te = tn) {
163                 tn = te->next;
164                 te->event_ctx = NULL;
165                 DLIST_REMOVE(ev->timer_events, te);
166         }
167
168         for (ie = ev->immediate_events; ie; ie = in) {
169                 in = ie->next;
170                 ie->event_ctx = NULL;
171                 ie->cancel_fn = NULL;
172                 DLIST_REMOVE(ev->immediate_events, ie);
173         }
174
175         for (se = ev->signal_events; se; se = sn) {
176                 sn = se->next;
177                 se->event_ctx = NULL;
178                 DLIST_REMOVE(ev->signal_events, se);
179         }
180
181         return 0;
182 }
183
184 /*
185   create a event_context structure for a specific implemementation.
186   This must be the first events call, and all subsequent calls pass
187   this event_context as the first element. Event handlers also
188   receive this as their first argument.
189
190   This function is for allowing third-party-applications to hook in gluecode
191   to their own event loop code, so that they can make async usage of our client libs
192
193   NOTE: use tevent_context_init() inside of samba!
194 */
195 static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
196                                                       const struct tevent_ops *ops)
197 {
198         struct tevent_context *ev;
199         int ret;
200
201         ev = talloc_zero(mem_ctx, struct tevent_context);
202         if (!ev) return NULL;
203
204         talloc_set_destructor(ev, tevent_common_context_destructor);
205
206         ev->ops = ops;
207
208         ret = ev->ops->context_init(ev);
209         if (ret != 0) {
210                 talloc_free(ev);
211                 return NULL;
212         }
213
214         return ev;
215 }
216
217 /*
218   create a event_context structure. This must be the first events
219   call, and all subsequent calls pass this event_context as the first
220   element. Event handlers also receive this as their first argument.
221 */
222 struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
223                                                   const char *name)
224 {
225         struct tevent_ops_list *e;
226
227         tevent_backend_init();
228
229         if (name == NULL) {
230                 name = tevent_default_backend;
231         }
232         if (name == NULL) {
233                 name = "standard";
234         }
235
236         for (e=tevent_backends;e;e=e->next) {
237                 if (strcmp(name, e->name) == 0) {
238                         return tevent_context_init_ops(mem_ctx, e->ops);
239                 }
240         }
241         return NULL;
242 }
243
244
245 /*
246   create a event_context structure. This must be the first events
247   call, and all subsequent calls pass this event_context as the first
248   element. Event handlers also receive this as their first argument.
249 */
250 struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
251 {
252         return tevent_context_init_byname(mem_ctx, NULL);
253 }
254
255 /*
256   add a fd based event
257   return NULL on failure (memory allocation error)
258
259   if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
260   the returned fd_event context is freed
261 */
262 struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
263                                  TALLOC_CTX *mem_ctx,
264                                  int fd,
265                                  uint16_t flags,
266                                  tevent_fd_handler_t handler,
267                                  void *private_data,
268                                  const char *handler_name,
269                                  const char *location)
270 {
271         return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
272                                handler_name, location);
273 }
274
275 /*
276   set a close function on the fd event
277 */
278 void tevent_fd_set_close_fn(struct tevent_fd *fde,
279                             tevent_fd_close_fn_t close_fn)
280 {
281         if (!fde) return;
282         if (!fde->event_ctx) return;
283         fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
284 }
285
286 static void tevent_fd_auto_close_fn(struct tevent_context *ev,
287                                     struct tevent_fd *fde,
288                                     int fd,
289                                     void *private_data)
290 {
291         close(fd);
292 }
293
294 void tevent_fd_set_auto_close(struct tevent_fd *fde)
295 {
296         tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
297 }
298
299 /*
300   return the fd event flags
301 */
302 uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
303 {
304         if (!fde) return 0;
305         if (!fde->event_ctx) return 0;
306         return fde->event_ctx->ops->get_fd_flags(fde);
307 }
308
309 /*
310   set the fd event flags
311 */
312 void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
313 {
314         if (!fde) return;
315         if (!fde->event_ctx) return;
316         fde->event_ctx->ops->set_fd_flags(fde, flags);
317 }
318
319 bool tevent_signal_support(struct tevent_context *ev)
320 {
321         if (ev->ops->add_signal) {
322                 return true;
323         }
324         return false;
325 }
326
327 static void (*tevent_abort_fn)(const char *reason);
328
329 void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
330 {
331         tevent_abort_fn = abort_fn;
332 }
333
334 static void tevent_abort(struct tevent_context *ev, const char *reason)
335 {
336         tevent_debug(ev, TEVENT_DEBUG_FATAL,
337                      "abort: %s\n", reason);
338
339         if (!tevent_abort_fn) {
340                 abort();
341         }
342
343         tevent_abort_fn(reason);
344 }
345
346 /*
347   add a timer event
348   return NULL on failure
349 */
350 struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
351                                        TALLOC_CTX *mem_ctx,
352                                        struct timeval next_event,
353                                        tevent_timer_handler_t handler,
354                                        void *private_data,
355                                        const char *handler_name,
356                                        const char *location)
357 {
358         return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
359                                   handler_name, location);
360 }
361
362 /*
363   allocate an immediate event
364   return NULL on failure (memory allocation error)
365 */
366 struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
367                                                   const char *location)
368 {
369         struct tevent_immediate *im;
370
371         im = talloc(mem_ctx, struct tevent_immediate);
372         if (im == NULL) return NULL;
373
374         im->prev                = NULL;
375         im->next                = NULL;
376         im->event_ctx           = NULL;
377         im->create_location     = location;
378         im->handler             = NULL;
379         im->private_data        = NULL;
380         im->handler_name        = NULL;
381         im->schedule_location   = NULL;
382         im->cancel_fn           = NULL;
383         im->additional_data     = NULL;
384
385         return im;
386 }
387
388 /*
389   schedule an immediate event
390   return NULL on failure
391 */
392 void _tevent_schedule_immediate(struct tevent_immediate *im,
393                                 struct tevent_context *ev,
394                                 tevent_immediate_handler_t handler,
395                                 void *private_data,
396                                 const char *handler_name,
397                                 const char *location)
398 {
399         ev->ops->schedule_immediate(im, ev, handler, private_data,
400                                     handler_name, location);
401 }
402
403 /*
404   add a signal event
405
406   sa_flags are flags to sigaction(2)
407
408   return NULL on failure
409 */
410 struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
411                                          TALLOC_CTX *mem_ctx,
412                                          int signum,
413                                          int sa_flags,
414                                          tevent_signal_handler_t handler,
415                                          void *private_data,
416                                          const char *handler_name,
417                                          const char *location)
418 {
419         return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
420                                    handler_name, location);
421 }
422
423 void tevent_loop_allow_nesting(struct tevent_context *ev)
424 {
425         ev->nesting.allowed = true;
426 }
427
428 void tevent_loop_set_nesting_hook(struct tevent_context *ev,
429                                   tevent_nesting_hook hook,
430                                   void *private_data)
431 {
432         if (ev->nesting.hook_fn && 
433             (ev->nesting.hook_fn != hook ||
434              ev->nesting.hook_private != private_data)) {
435                 /* the way the nesting hook code is currently written
436                    we cannot support two different nesting hooks at the
437                    same time. */
438                 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
439         }
440         ev->nesting.hook_fn = hook;
441         ev->nesting.hook_private = private_data;
442 }
443
444 static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
445 {
446         const char *reason;
447
448         reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
449                                  location);
450         if (!reason) {
451                 reason = "tevent_loop_once() nesting";
452         }
453
454         tevent_abort(ev, reason);
455 }
456
457 /*
458   do a single event loop using the events defined in ev 
459 */
460 int _tevent_loop_once(struct tevent_context *ev, const char *location)
461 {
462         int ret;
463         void *nesting_stack_ptr = NULL;
464
465         ev->nesting.level++;
466
467         if (ev->nesting.level > 1) {
468                 if (!ev->nesting.allowed) {
469                         tevent_abort_nesting(ev, location);
470                         errno = ELOOP;
471                         return -1;
472                 }
473         }
474         if (ev->nesting.level > 0) {
475                 if (ev->nesting.hook_fn) {
476                         int ret2;
477                         ret2 = ev->nesting.hook_fn(ev,
478                                                    ev->nesting.hook_private,
479                                                    ev->nesting.level,
480                                                    true,
481                                                    (void *)&nesting_stack_ptr,
482                                                    location);
483                         if (ret2 != 0) {
484                                 ret = ret2;
485                                 goto done;
486                         }
487                 }
488         }
489
490         ret = ev->ops->loop_once(ev, location);
491
492         if (ev->nesting.level > 0) {
493                 if (ev->nesting.hook_fn) {
494                         int ret2;
495                         ret2 = ev->nesting.hook_fn(ev,
496                                                    ev->nesting.hook_private,
497                                                    ev->nesting.level,
498                                                    false,
499                                                    (void *)&nesting_stack_ptr,
500                                                    location);
501                         if (ret2 != 0) {
502                                 ret = ret2;
503                                 goto done;
504                         }
505                 }
506         }
507
508 done:
509         ev->nesting.level--;
510         return ret;
511 }
512
513 /*
514   this is a performance optimization for the samba4 nested event loop problems
515 */
516 int _tevent_loop_until(struct tevent_context *ev,
517                        bool (*finished)(void *private_data),
518                        void *private_data,
519                        const char *location)
520 {
521         int ret = 0;
522         void *nesting_stack_ptr = NULL;
523
524         ev->nesting.level++;
525
526         if (ev->nesting.level > 1) {
527                 if (!ev->nesting.allowed) {
528                         tevent_abort_nesting(ev, location);
529                         errno = ELOOP;
530                         return -1;
531                 }
532         }
533         if (ev->nesting.level > 0) {
534                 if (ev->nesting.hook_fn) {
535                         int ret2;
536                         ret2 = ev->nesting.hook_fn(ev,
537                                                    ev->nesting.hook_private,
538                                                    ev->nesting.level,
539                                                    true,
540                                                    (void *)&nesting_stack_ptr,
541                                                    location);
542                         if (ret2 != 0) {
543                                 ret = ret2;
544                                 goto done;
545                         }
546                 }
547         }
548
549         while (!finished(private_data)) {
550                 ret = ev->ops->loop_once(ev, location);
551                 if (ret != 0) {
552                         break;
553                 }
554         }
555
556         if (ev->nesting.level > 0) {
557                 if (ev->nesting.hook_fn) {
558                         int ret2;
559                         ret2 = ev->nesting.hook_fn(ev,
560                                                    ev->nesting.hook_private,
561                                                    ev->nesting.level,
562                                                    false,
563                                                    (void *)&nesting_stack_ptr,
564                                                    location);
565                         if (ret2 != 0) {
566                                 ret = ret2;
567                                 goto done;
568                         }
569                 }
570         }
571
572 done:
573         ev->nesting.level--;
574         return ret;
575 }
576
577 /*
578   return on failure or (with 0) if all fd events are removed
579 */
580 int tevent_common_loop_wait(struct tevent_context *ev,
581                             const char *location)
582 {
583         /*
584          * loop as long as we have events pending
585          */
586         while (ev->fd_events ||
587                ev->timer_events ||
588                ev->immediate_events ||
589                ev->signal_events) {
590                 int ret;
591                 ret = _tevent_loop_once(ev, location);
592                 if (ret != 0) {
593                         tevent_debug(ev, TEVENT_DEBUG_FATAL,
594                                      "_tevent_loop_once() failed: %d - %s\n",
595                                      ret, strerror(errno));
596                         return ret;
597                 }
598         }
599
600         tevent_debug(ev, TEVENT_DEBUG_WARNING,
601                      "tevent_common_loop_wait() out of events\n");
602         return 0;
603 }
604
605 /*
606   return on failure or (with 0) if all fd events are removed
607 */
608 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
609 {
610         return ev->ops->loop_wait(ev, location);
611 }