Merge branch 'master' of ssh://jra@git.samba.org/data/git/samba
[sfrench/samba-autobuild/.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                 if (ev->nesting.hook_fn) {
472                         int ret2;
473                         ret2 = ev->nesting.hook_fn(ev,
474                                                    ev->nesting.hook_private,
475                                                    ev->nesting.level,
476                                                    true,
477                                                    (void *)&nesting_stack_ptr,
478                                                    location);
479                         if (ret2 != 0) {
480                                 ret = ret2;
481                                 goto done;
482                         }
483                 }
484         }
485
486         ret = ev->ops->loop_once(ev, location);
487
488         if (ev->nesting.level > 1) {
489                 if (ev->nesting.hook_fn) {
490                         int ret2;
491                         ret2 = ev->nesting.hook_fn(ev,
492                                                    ev->nesting.hook_private,
493                                                    ev->nesting.level,
494                                                    false,
495                                                    (void *)&nesting_stack_ptr,
496                                                    location);
497                         if (ret2 != 0) {
498                                 ret = ret2;
499                                 goto done;
500                         }
501                 }
502         }
503
504 done:
505         ev->nesting.level--;
506         return ret;
507 }
508
509 /*
510   this is a performance optimization for the samba4 nested event loop problems
511 */
512 int _tevent_loop_until(struct tevent_context *ev,
513                        bool (*finished)(void *private_data),
514                        void *private_data,
515                        const char *location)
516 {
517         int ret = 0;
518         void *nesting_stack_ptr = NULL;
519
520         ev->nesting.level++;
521
522         if (ev->nesting.level > 1) {
523                 if (!ev->nesting.allowed) {
524                         tevent_abort_nesting(ev, location);
525                         errno = ELOOP;
526                         return -1;
527                 }
528                 if (ev->nesting.hook_fn) {
529                         int ret2;
530                         ret2 = ev->nesting.hook_fn(ev,
531                                                    ev->nesting.hook_private,
532                                                    ev->nesting.level,
533                                                    true,
534                                                    (void *)&nesting_stack_ptr,
535                                                    location);
536                         if (ret2 != 0) {
537                                 ret = ret2;
538                                 goto done;
539                         }
540                 }
541         }
542
543         while (!finished(private_data)) {
544                 ret = ev->ops->loop_once(ev, location);
545                 if (ret != 0) {
546                         break;
547                 }
548         }
549
550         if (ev->nesting.level > 1) {
551                 if (ev->nesting.hook_fn) {
552                         int ret2;
553                         ret2 = ev->nesting.hook_fn(ev,
554                                                    ev->nesting.hook_private,
555                                                    ev->nesting.level,
556                                                    false,
557                                                    (void *)&nesting_stack_ptr,
558                                                    location);
559                         if (ret2 != 0) {
560                                 ret = ret2;
561                                 goto done;
562                         }
563                 }
564         }
565
566 done:
567         ev->nesting.level--;
568         return ret;
569 }
570
571 /*
572   return on failure or (with 0) if all fd events are removed
573 */
574 int tevent_common_loop_wait(struct tevent_context *ev,
575                             const char *location)
576 {
577         /*
578          * loop as long as we have events pending
579          */
580         while (ev->fd_events ||
581                ev->timer_events ||
582                ev->immediate_events ||
583                ev->signal_events) {
584                 int ret;
585                 ret = _tevent_loop_once(ev, location);
586                 if (ret != 0) {
587                         tevent_debug(ev, TEVENT_DEBUG_FATAL,
588                                      "_tevent_loop_once() failed: %d - %s\n",
589                                      ret, strerror(errno));
590                         return ret;
591                 }
592         }
593
594         tevent_debug(ev, TEVENT_DEBUG_WARNING,
595                      "tevent_common_loop_wait() out of events\n");
596         return 0;
597 }
598
599 /*
600   return on failure or (with 0) if all fd events are removed
601 */
602 int _tevent_loop_wait(struct tevent_context *ev, const char *location)
603 {
604         int ret;
605         ev->nesting.level++;
606         ret = ev->ops->loop_wait(ev, location);
607         ev->nesting.level--;
608         return ret;
609 }