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