source: trunk/server/lib/tevent/tevent.c@ 1075

Last change on this file since 1075 was 745, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.0

File size: 15.2 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 tevent_select_init();
116 tevent_poll_init();
117 tevent_standard_init();
118#ifdef HAVE_EPOLL
119 tevent_epoll_init();
120#endif
121}
122
123/*
124 list available backends
125*/
126const 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
142int 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*/
202static 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*/
229struct 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*/
257struct 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*/
266struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
267 TALLOC_CTX *mem_ctx,
268 int fd,
269 uint16_t flags,
270 tevent_fd_handler_t handler,
271 void *private_data,
272 const char *handler_name,
273 const char *location)
274{
275 return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
276 handler_name, location);
277}
278
279/*
280 set a close function on the fd event
281*/
282void tevent_fd_set_close_fn(struct tevent_fd *fde,
283 tevent_fd_close_fn_t close_fn)
284{
285 if (!fde) return;
286 if (!fde->event_ctx) return;
287 fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
288}
289
290static void tevent_fd_auto_close_fn(struct tevent_context *ev,
291 struct tevent_fd *fde,
292 int fd,
293 void *private_data)
294{
295 close(fd);
296}
297
298void tevent_fd_set_auto_close(struct tevent_fd *fde)
299{
300 tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
301}
302
303/*
304 return the fd event flags
305*/
306uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
307{
308 if (!fde) return 0;
309 if (!fde->event_ctx) return 0;
310 return fde->event_ctx->ops->get_fd_flags(fde);
311}
312
313/*
314 set the fd event flags
315*/
316void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
317{
318 if (!fde) return;
319 if (!fde->event_ctx) return;
320 fde->event_ctx->ops->set_fd_flags(fde, flags);
321}
322
323bool tevent_signal_support(struct tevent_context *ev)
324{
325 if (ev->ops->add_signal) {
326 return true;
327 }
328 return false;
329}
330
331static void (*tevent_abort_fn)(const char *reason);
332
333void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
334{
335 tevent_abort_fn = abort_fn;
336}
337
338static void tevent_abort(struct tevent_context *ev, const char *reason)
339{
340 tevent_debug(ev, TEVENT_DEBUG_FATAL,
341 "abort: %s\n", reason);
342
343 if (!tevent_abort_fn) {
344 abort();
345 }
346
347 tevent_abort_fn(reason);
348}
349
350/*
351 add a timer event
352 return NULL on failure
353*/
354struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
355 TALLOC_CTX *mem_ctx,
356 struct timeval next_event,
357 tevent_timer_handler_t handler,
358 void *private_data,
359 const char *handler_name,
360 const char *location)
361{
362 return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
363 handler_name, location);
364}
365
366/*
367 allocate an immediate event
368 return NULL on failure (memory allocation error)
369*/
370struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
371 const char *location)
372{
373 struct tevent_immediate *im;
374
375 im = talloc(mem_ctx, struct tevent_immediate);
376 if (im == NULL) return NULL;
377
378 im->prev = NULL;
379 im->next = NULL;
380 im->event_ctx = NULL;
381 im->create_location = location;
382 im->handler = NULL;
383 im->private_data = NULL;
384 im->handler_name = NULL;
385 im->schedule_location = NULL;
386 im->cancel_fn = NULL;
387 im->additional_data = NULL;
388
389 return im;
390}
391
392/*
393 schedule an immediate event
394 return NULL on failure
395*/
396void _tevent_schedule_immediate(struct tevent_immediate *im,
397 struct tevent_context *ev,
398 tevent_immediate_handler_t handler,
399 void *private_data,
400 const char *handler_name,
401 const char *location)
402{
403 ev->ops->schedule_immediate(im, ev, handler, private_data,
404 handler_name, location);
405}
406
407/*
408 add a signal event
409
410 sa_flags are flags to sigaction(2)
411
412 return NULL on failure
413*/
414struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
415 TALLOC_CTX *mem_ctx,
416 int signum,
417 int sa_flags,
418 tevent_signal_handler_t handler,
419 void *private_data,
420 const char *handler_name,
421 const char *location)
422{
423 return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
424 handler_name, location);
425}
426
427void tevent_loop_allow_nesting(struct tevent_context *ev)
428{
429 ev->nesting.allowed = true;
430}
431
432void tevent_loop_set_nesting_hook(struct tevent_context *ev,
433 tevent_nesting_hook hook,
434 void *private_data)
435{
436 if (ev->nesting.hook_fn &&
437 (ev->nesting.hook_fn != hook ||
438 ev->nesting.hook_private != private_data)) {
439 /* the way the nesting hook code is currently written
440 we cannot support two different nesting hooks at the
441 same time. */
442 tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
443 }
444 ev->nesting.hook_fn = hook;
445 ev->nesting.hook_private = private_data;
446}
447
448static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
449{
450 const char *reason;
451
452 reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
453 location);
454 if (!reason) {
455 reason = "tevent_loop_once() nesting";
456 }
457
458 tevent_abort(ev, reason);
459}
460
461/*
462 do a single event loop using the events defined in ev
463*/
464int _tevent_loop_once(struct tevent_context *ev, const char *location)
465{
466 int ret;
467 void *nesting_stack_ptr = NULL;
468
469 ev->nesting.level++;
470
471 if (ev->nesting.level > 1) {
472 if (!ev->nesting.allowed) {
473 tevent_abort_nesting(ev, location);
474 errno = ELOOP;
475 return -1;
476 }
477 }
478 if (ev->nesting.level > 0) {
479 if (ev->nesting.hook_fn) {
480 int ret2;
481 ret2 = ev->nesting.hook_fn(ev,
482 ev->nesting.hook_private,
483 ev->nesting.level,
484 true,
485 (void *)&nesting_stack_ptr,
486 location);
487 if (ret2 != 0) {
488 ret = ret2;
489 goto done;
490 }
491 }
492 }
493
494 ret = ev->ops->loop_once(ev, location);
495
496 if (ev->nesting.level > 0) {
497 if (ev->nesting.hook_fn) {
498 int ret2;
499 ret2 = ev->nesting.hook_fn(ev,
500 ev->nesting.hook_private,
501 ev->nesting.level,
502 false,
503 (void *)&nesting_stack_ptr,
504 location);
505 if (ret2 != 0) {
506 ret = ret2;
507 goto done;
508 }
509 }
510 }
511
512done:
513 ev->nesting.level--;
514 return ret;
515}
516
517/*
518 this is a performance optimization for the samba4 nested event loop problems
519*/
520int _tevent_loop_until(struct tevent_context *ev,
521 bool (*finished)(void *private_data),
522 void *private_data,
523 const char *location)
524{
525 int ret = 0;
526 void *nesting_stack_ptr = NULL;
527
528 ev->nesting.level++;
529
530 if (ev->nesting.level > 1) {
531 if (!ev->nesting.allowed) {
532 tevent_abort_nesting(ev, location);
533 errno = ELOOP;
534 return -1;
535 }
536 }
537 if (ev->nesting.level > 0) {
538 if (ev->nesting.hook_fn) {
539 int ret2;
540 ret2 = ev->nesting.hook_fn(ev,
541 ev->nesting.hook_private,
542 ev->nesting.level,
543 true,
544 (void *)&nesting_stack_ptr,
545 location);
546 if (ret2 != 0) {
547 ret = ret2;
548 goto done;
549 }
550 }
551 }
552
553 while (!finished(private_data)) {
554 ret = ev->ops->loop_once(ev, location);
555 if (ret != 0) {
556 break;
557 }
558 }
559
560 if (ev->nesting.level > 0) {
561 if (ev->nesting.hook_fn) {
562 int ret2;
563 ret2 = ev->nesting.hook_fn(ev,
564 ev->nesting.hook_private,
565 ev->nesting.level,
566 false,
567 (void *)&nesting_stack_ptr,
568 location);
569 if (ret2 != 0) {
570 ret = ret2;
571 goto done;
572 }
573 }
574 }
575
576done:
577 ev->nesting.level--;
578 return ret;
579}
580
581/*
582 return on failure or (with 0) if all fd events are removed
583*/
584int tevent_common_loop_wait(struct tevent_context *ev,
585 const char *location)
586{
587 /*
588 * loop as long as we have events pending
589 */
590 while (ev->fd_events ||
591 ev->timer_events ||
592 ev->immediate_events ||
593 ev->signal_events) {
594 int ret;
595 ret = _tevent_loop_once(ev, location);
596 if (ret != 0) {
597 tevent_debug(ev, TEVENT_DEBUG_FATAL,
598 "_tevent_loop_once() failed: %d - %s\n",
599 ret, strerror(errno));
600 return ret;
601 }
602 }
603
604 tevent_debug(ev, TEVENT_DEBUG_WARNING,
605 "tevent_common_loop_wait() out of events\n");
606 return 0;
607}
608
609/*
610 return on failure or (with 0) if all fd events are removed
611*/
612int _tevent_loop_wait(struct tevent_context *ev, const char *location)
613{
614 return ev->ops->loop_wait(ev, location);
615}
616
617
618/*
619 re-initialise a tevent context. This leaves you with the same
620 event context, but all events are wiped and the structure is
621 re-initialised. This is most useful after a fork()
622
623 zero is returned on success, non-zero on failure
624*/
625int tevent_re_initialise(struct tevent_context *ev)
626{
627 tevent_common_context_destructor(ev);
628
629 return ev->ops->context_init(ev);
630}
Note: See TracBrowser for help on using the repository browser.