source: vendor/current/lib/tevent/tevent.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 15.7 KB
Line 
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
67struct 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 */
74static struct tevent_ops_list *tevent_backends = NULL;
75static char *tevent_default_backend = NULL;
76
77/*
78 register an events backend
79*/
80bool 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(NULL, 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 */
104void tevent_set_default_backend(const char *backend)
105{
106 talloc_free(tevent_default_backend);
107 tevent_default_backend = talloc_strdup(NULL, backend);
108}
109
110/*
111 initialise backends if not already done
112*/
113static void tevent_backend_init(void)
114{
115 static bool done;
116
117 if (done) {
118 return;
119 }
120
121 done = true;
122
123 tevent_select_init();
124 tevent_poll_init();
125 tevent_poll_mt_init();
126#if defined(HAVE_EPOLL)
127 tevent_epoll_init();
128#elif defined(HAVE_SOLARIS_PORTS)
129 tevent_port_init();
130#endif
131
132 tevent_standard_init();
133}
134
135_PRIVATE_ const struct tevent_ops *tevent_find_ops_byname(const char *name)
136{
137 struct tevent_ops_list *e;
138
139 tevent_backend_init();
140
141 if (name == NULL) {
142 name = tevent_default_backend;
143 }
144 if (name == NULL) {
145 name = "standard";
146 }
147
148 for (e = tevent_backends; e != NULL; e = e->next) {
149 if (0 == strcmp(e->name, name)) {
150 return e->ops;
151 }
152 }
153
154 return NULL;
155}
156
157/*
158 list available backends
159*/
160const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
161{
162 const char **list = NULL;
163 struct tevent_ops_list *e;
164
165 tevent_backend_init();
166
167 for (e=tevent_backends;e;e=e->next) {
168 list = ev_str_list_add(list, e->name);
169 }
170
171 talloc_steal(mem_ctx, list);
172
173 return list;
174}
175
176int tevent_common_context_destructor(struct tevent_context *ev)
177{
178 struct tevent_fd *fd, *fn;
179 struct tevent_timer *te, *tn;
180 struct tevent_immediate *ie, *in;
181 struct tevent_signal *se, *sn;
182
183 if (ev->pipe_fde) {
184 talloc_free(ev->pipe_fde);
185 close(ev->pipe_fds[0]);
186 close(ev->pipe_fds[1]);
187 ev->pipe_fde = NULL;
188 }
189
190 for (fd = ev->fd_events; fd; fd = fn) {
191 fn = fd->next;
192 fd->event_ctx = NULL;
193 DLIST_REMOVE(ev->fd_events, fd);
194 }
195
196 ev->last_zero_timer = NULL;
197 for (te = ev->timer_events; te; te = tn) {
198 tn = te->next;
199 te->event_ctx = NULL;
200 DLIST_REMOVE(ev->timer_events, te);
201 }
202
203 for (ie = ev->immediate_events; ie; ie = in) {
204 in = ie->next;
205 ie->event_ctx = NULL;
206 ie->cancel_fn = NULL;
207 DLIST_REMOVE(ev->immediate_events, ie);
208 }
209
210 for (se = ev->signal_events; se; se = sn) {
211 sn = se->next;
212 se->event_ctx = NULL;
213 DLIST_REMOVE(ev->signal_events, se);
214 /*
215 * This is important, Otherwise signals
216 * are handled twice in child. eg, SIGHUP.
217 * one added in parent, and another one in
218 * the child. -- BoYang
219 */
220 tevent_cleanup_pending_signal_handlers(se);
221 }
222
223 /* removing nesting hook or we get an abort when nesting is
224 * not allowed. -- SSS
225 * Note that we need to leave the allowed flag at its current
226 * value, otherwise the use in tevent_re_initialise() will
227 * leave the event context with allowed forced to false, which
228 * will break users that expect nesting to be allowed
229 */
230 ev->nesting.level = 0;
231 ev->nesting.hook_fn = NULL;
232 ev->nesting.hook_private = NULL;
233
234 return 0;
235}
236
237/*
238 create a event_context structure for a specific implemementation.
239 This must be the first events call, and all subsequent calls pass
240 this event_context as the first element. Event handlers also
241 receive this as their first argument.
242
243 This function is for allowing third-party-applications to hook in gluecode
244 to their own event loop code, so that they can make async usage of our client libs
245
246 NOTE: use tevent_context_init() inside of samba!
247*/
248struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
249 const struct tevent_ops *ops,
250 void *additional_data)
251{
252 struct tevent_context *ev;
253 int ret;
254
255 ev = talloc_zero(mem_ctx, struct tevent_context);
256 if (!ev) return NULL;
257
258 talloc_set_destructor(ev, tevent_common_context_destructor);
259
260 ev->ops = ops;
261 ev->additional_data = additional_data;
262
263 ret = ev->ops->context_init(ev);
264 if (ret != 0) {
265 talloc_free(ev);
266 return NULL;
267 }
268
269 return ev;
270}
271
272/*
273 create a event_context structure. This must be the first events
274 call, and all subsequent calls pass this event_context as the first
275 element. Event handlers also receive this as their first argument.
276*/
277struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
278 const char *name)
279{
280 const struct tevent_ops *ops;
281
282 ops = tevent_find_ops_byname(name);
283 if (ops == NULL) {
284 return NULL;
285 }
286
287 return tevent_context_init_ops(mem_ctx, ops, NULL);
288}
289
290
291/*
292 create a event_context structure. This must be the first events
293 call, and all subsequent calls pass this event_context as the first
294 element. Event handlers also receive this as their first argument.
295*/
296struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
297{
298 return tevent_context_init_byname(mem_ctx, NULL);
299}
300
301/*
302 add a fd based event
303 return NULL on failure (memory allocation error)
304*/
305struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
306 TALLOC_CTX *mem_ctx,
307 int fd,
308 uint16_t flags,
309 tevent_fd_handler_t handler,
310 void *private_data,
311 const char *handler_name,
312 const char *location)
313{
314 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
315 handler_name, location);
316}
317
318/*
319 set a close function on the fd event
320*/
321void tevent_fd_set_close_fn(struct tevent_fd *fde,
322 tevent_fd_close_fn_t close_fn)
323{
324 if (!fde) return;
325 if (!fde->event_ctx) return;
326 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
327}
328
329static void tevent_fd_auto_close_fn(struct tevent_context *ev,
330 struct tevent_fd *fde,
331 int fd,
332 void *private_data)
333{
334 close(fd);
335}
336
337void tevent_fd_set_auto_close(struct tevent_fd *fde)
338{
339 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
340}
341
342/*
343 return the fd event flags
344*/
345uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
346{
347 if (!fde) return 0;
348 if (!fde->event_ctx) return 0;
349 return fde->event_ctx->ops->get_fd_flags(fde);
350}
351
352/*
353 set the fd event flags
354*/
355void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
356{
357 if (!fde) return;
358 if (!fde->event_ctx) return;
359 fde->event_ctx->ops->set_fd_flags(fde, flags);
360}
361
362bool tevent_signal_support(struct tevent_context *ev)
363{
364 if (ev->ops->add_signal) {
365 return true;
366 }
367 return false;
368}
369
370static void (*tevent_abort_fn)(const char *reason);
371
372void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
373{
374 tevent_abort_fn = abort_fn;
375}
376
377static void tevent_abort(struct tevent_context *ev, const char *reason)
378{
379 tevent_debug(ev, TEVENT_DEBUG_FATAL,
380 "abort: %s\n", reason);
381
382 if (!tevent_abort_fn) {
383 abort();
384 }
385
386 tevent_abort_fn(reason);
387}
388
389/*
390 add a timer event
391 return NULL on failure
392*/
393struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
394 TALLOC_CTX *mem_ctx,
395 struct timeval next_event,
396 tevent_timer_handler_t handler,
397 void *private_data,
398 const char *handler_name,
399 const char *location)
400{
401 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
402 handler_name, location);
403}
404
405/*
406 allocate an immediate event
407 return NULL on failure (memory allocation error)
408*/
409struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
410 const char *location)
411{
412 struct tevent_immediate *im;
413
414 im = talloc(mem_ctx, struct tevent_immediate);
415 if (im == NULL) return NULL;
416
417 im->prev = NULL;
418 im->next = NULL;
419 im->event_ctx = NULL;
420 im->create_location = location;
421 im->handler = NULL;
422 im->private_data = NULL;
423 im->handler_name = NULL;
424 im->schedule_location = NULL;
425 im->cancel_fn = NULL;
426 im->additional_data = NULL;
427
428 return im;
429}
430
431/*
432 schedule an immediate event
433*/
434void _tevent_schedule_immediate(struct tevent_immediate *im,
435 struct tevent_context *ev,
436 tevent_immediate_handler_t handler,
437 void *private_data,
438 const char *handler_name,
439 const char *location)
440{
441 ev->ops->schedule_immediate(im, ev, handler, private_data,
442 handler_name, location);
443}
444
445/*
446 add a signal event
447
448 sa_flags are flags to sigaction(2)
449
450 return NULL on failure
451*/
452struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
453 TALLOC_CTX *mem_ctx,
454 int signum,
455 int sa_flags,
456 tevent_signal_handler_t handler,
457 void *private_data,
458 const char *handler_name,
459 const char *location)
460{
461 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
462 handler_name, location);
463}
464
465void tevent_loop_allow_nesting(struct tevent_context *ev)
466{
467 ev->nesting.allowed = true;
468}
469
470void tevent_loop_set_nesting_hook(struct tevent_context *ev,
471 tevent_nesting_hook hook,
472 void *private_data)
473{
474 if (ev->nesting.hook_fn &&
475 (ev->nesting.hook_fn != hook ||
476 ev->nesting.hook_private != private_data)) {
477 /* the way the nesting hook code is currently written
478 we cannot support two different nesting hooks at the
479 same time. */
480 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
481 }
482 ev->nesting.hook_fn = hook;
483 ev->nesting.hook_private = private_data;
484}
485
486static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
487{
488 const char *reason;
489
490 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
491 location);
492 if (!reason) {
493 reason = "tevent_loop_once() nesting";
494 }
495
496 tevent_abort(ev, reason);
497}
498
499/*
500 do a single event loop using the events defined in ev
501*/
502int _tevent_loop_once(struct tevent_context *ev, const char *location)
503{
504 int ret;
505 void *nesting_stack_ptr = NULL;
506
507 ev->nesting.level++;
508
509 if (ev->nesting.level > 1) {
510 if (!ev->nesting.allowed) {
511 tevent_abort_nesting(ev, location);
512 errno = ELOOP;
513 return -1;
514 }
515 }
516 if (ev->nesting.level > 0) {
517 if (ev->nesting.hook_fn) {
518 int ret2;
519 ret2 = ev->nesting.hook_fn(ev,
520 ev->nesting.hook_private,
521 ev->nesting.level,
522 true,
523 (void *)&nesting_stack_ptr,
524 location);
525 if (ret2 != 0) {
526 ret = ret2;
527 goto done;
528 }
529 }
530 }
531
532 tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
533 ret = ev->ops->loop_once(ev, location);
534 tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
535
536 if (ev->nesting.level > 0) {
537 if (ev->nesting.hook_fn) {
538 int ret2;
539 ret2 = ev->nesting.hook_fn(ev,
540 ev->nesting.hook_private,
541 ev->nesting.level,
542 false,
543 (void *)&nesting_stack_ptr,
544 location);
545 if (ret2 != 0) {
546 ret = ret2;
547 goto done;
548 }
549 }
550 }
551
552done:
553 ev->nesting.level--;
554 return ret;
555}
556
557/*
558 this is a performance optimization for the samba4 nested event loop problems
559*/
560int _tevent_loop_until(struct tevent_context *ev,
561 bool (*finished)(void *private_data),
562 void *private_data,
563 const char *location)
564{
565 int ret = 0;
566 void *nesting_stack_ptr = NULL;
567
568 ev->nesting.level++;
569
570 if (ev->nesting.level > 1) {
571 if (!ev->nesting.allowed) {
572 tevent_abort_nesting(ev, location);
573 errno = ELOOP;
574 return -1;
575 }
576 }
577 if (ev->nesting.level > 0) {
578 if (ev->nesting.hook_fn) {
579 int ret2;
580 ret2 = ev->nesting.hook_fn(ev,
581 ev->nesting.hook_private,
582 ev->nesting.level,
583 true,
584 (void *)&nesting_stack_ptr,
585 location);
586 if (ret2 != 0) {
587 ret = ret2;
588 goto done;
589 }
590 }
591 }
592
593 while (!finished(private_data)) {
594 tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
595 ret = ev->ops->loop_once(ev, location);
596 tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
597 if (ret != 0) {
598 break;
599 }
600 }
601
602 if (ev->nesting.level > 0) {
603 if (ev->nesting.hook_fn) {
604 int ret2;
605 ret2 = ev->nesting.hook_fn(ev,
606 ev->nesting.hook_private,
607 ev->nesting.level,
608 false,
609 (void *)&nesting_stack_ptr,
610 location);
611 if (ret2 != 0) {
612 ret = ret2;
613 goto done;
614 }
615 }
616 }
617
618done:
619 ev->nesting.level--;
620 return ret;
621}
622
623/*
624 return on failure or (with 0) if all fd events are removed
625*/
626int tevent_common_loop_wait(struct tevent_context *ev,
627 const char *location)
628{
629 /*
630 * loop as long as we have events pending
631 */
632 while (ev->fd_events ||
633 ev->timer_events ||
634 ev->immediate_events ||
635 ev->signal_events) {
636 int ret;
637 ret = _tevent_loop_once(ev, location);
638 if (ret != 0) {
639 tevent_debug(ev, TEVENT_DEBUG_FATAL,
640 "_tevent_loop_once() failed: %d - %s\n",
641 ret, strerror(errno));
642 return ret;
643 }
644 }
645
646 tevent_debug(ev, TEVENT_DEBUG_WARNING,
647 "tevent_common_loop_wait() out of events\n");
648 return 0;
649}
650
651/*
652 return on failure or (with 0) if all fd events are removed
653*/
654int _tevent_loop_wait(struct tevent_context *ev, const char *location)
655{
656 return ev->ops->loop_wait(ev, location);
657}
658
659
660/*
661 re-initialise a tevent context. This leaves you with the same
662 event context, but all events are wiped and the structure is
663 re-initialised. This is most useful after a fork()
664
665 zero is returned on success, non-zero on failure
666*/
667int tevent_re_initialise(struct tevent_context *ev)
668{
669 tevent_common_context_destructor(ev);
670
671 return ev->ops->context_init(ev);
672}
Note: See TracBrowser for help on using the repository browser.