Line data Source code
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 : #ifdef HAVE_PTHREAD
63 : #include "system/threads.h"
64 : #endif
65 : #define TEVENT_DEPRECATED 1
66 : #include "tevent.h"
67 : #include "tevent_internal.h"
68 : #include "tevent_util.h"
69 : #ifdef HAVE_EVENTFD
70 : #include <sys/eventfd.h>
71 : #endif
72 :
73 : struct tevent_ops_list {
74 : struct tevent_ops_list *next, *prev;
75 : const char *name;
76 : const struct tevent_ops *ops;
77 : };
78 :
79 : /* list of registered event backends */
80 : static struct tevent_ops_list *tevent_backends = NULL;
81 : static char *tevent_default_backend = NULL;
82 :
83 : /*
84 : register an events backend
85 : */
86 112784 : bool tevent_register_backend(const char *name, const struct tevent_ops *ops)
87 : {
88 : struct tevent_ops_list *e;
89 :
90 281960 : for (e = tevent_backends; e != NULL; e = e->next) {
91 169176 : if (0 == strcmp(e->name, name)) {
92 : /* already registered, skip it */
93 0 : return true;
94 : }
95 : }
96 :
97 112784 : e = talloc(NULL, struct tevent_ops_list);
98 112784 : if (e == NULL) return false;
99 :
100 112784 : e->name = name;
101 112784 : e->ops = ops;
102 112784 : DLIST_ADD(tevent_backends, e);
103 :
104 112784 : return true;
105 : }
106 :
107 : /*
108 : set the default event backend
109 : */
110 0 : void tevent_set_default_backend(const char *backend)
111 : {
112 0 : talloc_free(tevent_default_backend);
113 0 : tevent_default_backend = talloc_strdup(NULL, backend);
114 0 : }
115 :
116 : /*
117 : initialise backends if not already done
118 : */
119 163644882 : static void tevent_backend_init(void)
120 : {
121 : static bool done;
122 :
123 163644882 : if (done) {
124 163616686 : return;
125 : }
126 :
127 28196 : done = true;
128 :
129 28196 : tevent_poll_init();
130 28196 : tevent_poll_mt_init();
131 : #if defined(HAVE_EPOLL)
132 28196 : tevent_epoll_init();
133 : #elif defined(HAVE_SOLARIS_PORTS)
134 : tevent_port_init();
135 : #endif
136 :
137 28196 : tevent_standard_init();
138 : }
139 :
140 163643916 : _PRIVATE_ const struct tevent_ops *tevent_find_ops_byname(const char *name)
141 : {
142 : struct tevent_ops_list *e;
143 :
144 163643916 : tevent_backend_init();
145 :
146 163643916 : if (name == NULL) {
147 54547971 : name = tevent_default_backend;
148 : }
149 163643916 : if (name == NULL) {
150 54547971 : name = "standard";
151 : }
152 :
153 381835804 : for (e = tevent_backends; e != NULL; e = e->next) {
154 381835804 : if (0 == strcmp(e->name, name)) {
155 163643916 : return e->ops;
156 : }
157 : }
158 :
159 0 : return NULL;
160 : }
161 :
162 : /*
163 : list available backends
164 : */
165 966 : const char **tevent_backend_list(TALLOC_CTX *mem_ctx)
166 : {
167 966 : const char **list = NULL;
168 : struct tevent_ops_list *e;
169 966 : size_t idx = 0;
170 :
171 966 : tevent_backend_init();
172 :
173 4830 : for (e=tevent_backends;e;e=e->next) {
174 3864 : idx += 1;
175 : }
176 :
177 966 : list = talloc_zero_array(mem_ctx, const char *, idx+1);
178 966 : if (list == NULL) {
179 0 : return NULL;
180 : }
181 :
182 966 : idx = 0;
183 4830 : for (e=tevent_backends;e;e=e->next) {
184 3864 : list[idx] = talloc_strdup(list, e->name);
185 3864 : if (list[idx] == NULL) {
186 0 : TALLOC_FREE(list);
187 0 : return NULL;
188 : }
189 3864 : idx += 1;
190 : }
191 :
192 966 : return list;
193 : }
194 :
195 : static void tevent_common_wakeup_fini(struct tevent_context *ev);
196 :
197 : #ifdef HAVE_PTHREAD
198 :
199 : static pthread_mutex_t tevent_contexts_mutex = PTHREAD_MUTEX_INITIALIZER;
200 : static struct tevent_context *tevent_contexts = NULL;
201 : static pthread_once_t tevent_atfork_initialized = PTHREAD_ONCE_INIT;
202 : static pid_t tevent_cached_global_pid = 0;
203 :
204 7900940 : static void tevent_atfork_prepare(void)
205 : {
206 : struct tevent_context *ev;
207 : int ret;
208 :
209 7900940 : ret = pthread_mutex_lock(&tevent_contexts_mutex);
210 7900940 : if (ret != 0) {
211 0 : abort();
212 : }
213 :
214 23822747 : for (ev = tevent_contexts; ev != NULL; ev = ev->next) {
215 : struct tevent_threaded_context *tctx;
216 :
217 26366150 : for (tctx = ev->threaded_contexts; tctx != NULL;
218 1325 : tctx = tctx->next) {
219 1325 : ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
220 1325 : if (ret != 0) {
221 0 : tevent_abort(ev, "pthread_mutex_lock failed");
222 : }
223 : }
224 :
225 15921807 : ret = pthread_mutex_lock(&ev->scheduled_mutex);
226 15921807 : if (ret != 0) {
227 0 : tevent_abort(ev, "pthread_mutex_lock failed");
228 : }
229 : }
230 7900940 : }
231 :
232 7867746 : static void tevent_atfork_parent(void)
233 : {
234 : struct tevent_context *ev;
235 : int ret;
236 :
237 28791510 : for (ev = DLIST_TAIL(tevent_contexts); ev != NULL;
238 15855839 : ev = DLIST_PREV(ev)) {
239 : struct tevent_threaded_context *tctx;
240 :
241 15855839 : ret = pthread_mutex_unlock(&ev->scheduled_mutex);
242 15855839 : if (ret != 0) {
243 0 : tevent_abort(ev, "pthread_mutex_unlock failed");
244 : }
245 :
246 26256235 : for (tctx = DLIST_TAIL(ev->threaded_contexts); tctx != NULL;
247 1275 : tctx = DLIST_PREV(tctx)) {
248 1275 : ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
249 1275 : if (ret != 0) {
250 0 : tevent_abort(
251 : ev, "pthread_mutex_unlock failed");
252 : }
253 : }
254 : }
255 :
256 7867746 : ret = pthread_mutex_unlock(&tevent_contexts_mutex);
257 7867746 : if (ret != 0) {
258 0 : abort();
259 : }
260 7867746 : }
261 :
262 33194 : static void tevent_atfork_child(void)
263 : {
264 : struct tevent_context *ev;
265 : int ret;
266 :
267 33194 : tevent_cached_global_pid = getpid();
268 :
269 121032 : for (ev = DLIST_TAIL(tevent_contexts); ev != NULL;
270 65968 : ev = DLIST_PREV(ev)) {
271 : struct tevent_threaded_context *tctx;
272 :
273 109915 : for (tctx = DLIST_TAIL(ev->threaded_contexts); tctx != NULL;
274 50 : tctx = DLIST_PREV(tctx)) {
275 50 : tctx->event_ctx = NULL;
276 :
277 50 : ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
278 50 : if (ret != 0) {
279 0 : tevent_abort(
280 : ev, "pthread_mutex_unlock failed");
281 : }
282 : }
283 :
284 65968 : ev->threaded_contexts = NULL;
285 :
286 65968 : ret = pthread_mutex_unlock(&ev->scheduled_mutex);
287 65968 : if (ret != 0) {
288 0 : tevent_abort(ev, "pthread_mutex_unlock failed");
289 : }
290 : }
291 :
292 33194 : ret = pthread_mutex_unlock(&tevent_contexts_mutex);
293 33194 : if (ret != 0) {
294 0 : abort();
295 : }
296 33194 : }
297 :
298 28140 : static void tevent_prep_atfork(void)
299 : {
300 : int ret;
301 :
302 28140 : ret = pthread_atfork(tevent_atfork_prepare,
303 : tevent_atfork_parent,
304 : tevent_atfork_child);
305 28140 : if (ret != 0) {
306 0 : abort();
307 : }
308 :
309 28140 : tevent_cached_global_pid = getpid();
310 28140 : }
311 :
312 : #endif
313 :
314 182977323 : static int tevent_init_globals(void)
315 : {
316 : #ifdef HAVE_PTHREAD
317 : int ret;
318 :
319 182977323 : ret = pthread_once(&tevent_atfork_initialized, tevent_prep_atfork);
320 182977323 : if (ret != 0) {
321 0 : return ret;
322 : }
323 : #endif
324 :
325 182977323 : return 0;
326 : }
327 :
328 128392020 : _PUBLIC_ pid_t tevent_cached_getpid(void)
329 : {
330 : #ifdef HAVE_PTHREAD
331 128392020 : tevent_init_globals();
332 : #ifdef TEVENT_VERIFY_CACHED_GETPID
333 : if (tevent_cached_global_pid != getpid()) {
334 : tevent_abort(NULL, "tevent_cached_global_pid invalid");
335 : }
336 : #endif
337 128392020 : if (tevent_cached_global_pid != 0) {
338 128392020 : return tevent_cached_global_pid;
339 : }
340 : #endif
341 0 : return getpid();
342 : }
343 :
344 54575710 : int tevent_common_context_destructor(struct tevent_context *ev)
345 : {
346 : struct tevent_fd *fd, *fn;
347 : struct tevent_timer *te, *tn;
348 : struct tevent_immediate *ie, *in;
349 : struct tevent_signal *se, *sn;
350 : struct tevent_wrapper_glue *gl, *gn;
351 : #ifdef HAVE_PTHREAD
352 : int ret;
353 : #endif
354 :
355 54575710 : if (ev->wrapper.glue != NULL) {
356 0 : tevent_abort(ev,
357 : "tevent_common_context_destructor() active on wrapper");
358 : }
359 :
360 : #ifdef HAVE_PTHREAD
361 54575710 : ret = pthread_mutex_lock(&tevent_contexts_mutex);
362 54575710 : if (ret != 0) {
363 0 : abort();
364 : }
365 :
366 54575710 : DLIST_REMOVE(tevent_contexts, ev);
367 :
368 54575710 : ret = pthread_mutex_unlock(&tevent_contexts_mutex);
369 54575710 : if (ret != 0) {
370 0 : abort();
371 : }
372 :
373 109151422 : while (ev->threaded_contexts != NULL) {
374 2 : struct tevent_threaded_context *tctx = ev->threaded_contexts;
375 :
376 2 : ret = pthread_mutex_lock(&tctx->event_ctx_mutex);
377 2 : if (ret != 0) {
378 0 : abort();
379 : }
380 :
381 : /*
382 : * Indicate to the thread that the tevent_context is
383 : * gone. The counterpart of this is in
384 : * _tevent_threaded_schedule_immediate, there we read
385 : * this under the threaded_context's mutex.
386 : */
387 :
388 2 : tctx->event_ctx = NULL;
389 :
390 2 : ret = pthread_mutex_unlock(&tctx->event_ctx_mutex);
391 2 : if (ret != 0) {
392 0 : abort();
393 : }
394 :
395 2 : DLIST_REMOVE(ev->threaded_contexts, tctx);
396 : }
397 :
398 54575710 : ret = pthread_mutex_destroy(&ev->scheduled_mutex);
399 54575710 : if (ret != 0) {
400 0 : abort();
401 : }
402 : #endif
403 :
404 54575710 : for (gl = ev->wrapper.list; gl; gl = gn) {
405 0 : gn = gl->next;
406 :
407 0 : gl->main_ev = NULL;
408 0 : DLIST_REMOVE(ev->wrapper.list, gl);
409 : }
410 :
411 54575710 : tevent_common_wakeup_fini(ev);
412 :
413 54918199 : for (fd = ev->fd_events; fd; fd = fn) {
414 342489 : fn = fd->next;
415 342489 : tevent_trace_fd_callback(fd->event_ctx, fd, TEVENT_EVENT_TRACE_DETACH);
416 342489 : fd->wrapper = NULL;
417 342489 : fd->event_ctx = NULL;
418 342489 : DLIST_REMOVE(ev->fd_events, fd);
419 : }
420 :
421 54575710 : ev->last_zero_timer = NULL;
422 54626636 : for (te = ev->timer_events; te; te = tn) {
423 50926 : tn = te->next;
424 50926 : tevent_trace_timer_callback(te->event_ctx, te, TEVENT_EVENT_TRACE_DETACH);
425 50926 : te->wrapper = NULL;
426 50926 : te->event_ctx = NULL;
427 50926 : DLIST_REMOVE(ev->timer_events, te);
428 : }
429 :
430 54575799 : for (ie = ev->immediate_events; ie; ie = in) {
431 89 : in = ie->next;
432 89 : tevent_trace_immediate_callback(ie->event_ctx, ie, TEVENT_EVENT_TRACE_DETACH);
433 89 : ie->wrapper = NULL;
434 89 : ie->event_ctx = NULL;
435 89 : ie->cancel_fn = NULL;
436 89 : DLIST_REMOVE(ev->immediate_events, ie);
437 : }
438 :
439 54657309 : for (se = ev->signal_events; se; se = sn) {
440 81599 : sn = se->next;
441 81599 : tevent_trace_signal_callback(se->event_ctx, se, TEVENT_EVENT_TRACE_DETACH);
442 81599 : se->wrapper = NULL;
443 81599 : se->event_ctx = NULL;
444 81599 : DLIST_REMOVE(ev->signal_events, se);
445 : /*
446 : * This is important, Otherwise signals
447 : * are handled twice in child. eg, SIGHUP.
448 : * one added in parent, and another one in
449 : * the child. -- BoYang
450 : */
451 81599 : tevent_cleanup_pending_signal_handlers(se);
452 : }
453 :
454 : /* removing nesting hook or we get an abort when nesting is
455 : * not allowed. -- SSS
456 : * Note that we need to leave the allowed flag at its current
457 : * value, otherwise the use in tevent_re_initialise() will
458 : * leave the event context with allowed forced to false, which
459 : * will break users that expect nesting to be allowed
460 : */
461 54575710 : ev->nesting.level = 0;
462 54575710 : ev->nesting.hook_fn = NULL;
463 54575710 : ev->nesting.hook_private = NULL;
464 :
465 54575710 : return 0;
466 : }
467 :
468 54585303 : static int tevent_common_context_constructor(struct tevent_context *ev)
469 : {
470 : int ret;
471 :
472 54585303 : ret = tevent_init_globals();
473 54585303 : if (ret != 0) {
474 0 : return ret;
475 : }
476 :
477 : #ifdef HAVE_PTHREAD
478 :
479 54585303 : ret = pthread_mutex_init(&ev->scheduled_mutex, NULL);
480 54585303 : if (ret != 0) {
481 0 : return ret;
482 : }
483 :
484 54585303 : ret = pthread_mutex_lock(&tevent_contexts_mutex);
485 54585303 : if (ret != 0) {
486 0 : pthread_mutex_destroy(&ev->scheduled_mutex);
487 0 : return ret;
488 : }
489 :
490 54585303 : DLIST_ADD(tevent_contexts, ev);
491 :
492 54585303 : ret = pthread_mutex_unlock(&tevent_contexts_mutex);
493 54585303 : if (ret != 0) {
494 0 : abort();
495 : }
496 : #endif
497 :
498 54585303 : talloc_set_destructor(ev, tevent_common_context_destructor);
499 :
500 54585303 : return 0;
501 : }
502 :
503 77759157 : void tevent_common_check_double_free(TALLOC_CTX *ptr, const char *reason)
504 : {
505 77759157 : void *parent_ptr = talloc_parent(ptr);
506 77759157 : size_t parent_blocks = talloc_total_blocks(parent_ptr);
507 :
508 77759157 : if (parent_ptr != NULL && parent_blocks == 0) {
509 : /*
510 : * This is an implicit talloc free, as we still have a parent
511 : * but it's already being destroyed. Note that
512 : * talloc_total_blocks(ptr) also just returns 0 if a
513 : * talloc_free(ptr) is still in progress of freeing all
514 : * children.
515 : */
516 77759157 : return;
517 : }
518 :
519 0 : tevent_abort(NULL, reason);
520 : }
521 :
522 : /*
523 : create a event_context structure for a specific implemementation.
524 : This must be the first events call, and all subsequent calls pass
525 : this event_context as the first element. Event handlers also
526 : receive this as their first argument.
527 :
528 : This function is for allowing third-party-applications to hook in gluecode
529 : to their own event loop code, so that they can make async usage of our client libs
530 :
531 : NOTE: use tevent_context_init() inside of samba!
532 : */
533 54547972 : struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
534 : const struct tevent_ops *ops,
535 : void *additional_data)
536 : {
537 : struct tevent_context *ev;
538 : int ret;
539 :
540 54547972 : ev = talloc_zero(mem_ctx, struct tevent_context);
541 54547972 : if (!ev) return NULL;
542 :
543 54547972 : ret = tevent_common_context_constructor(ev);
544 54547972 : if (ret != 0) {
545 0 : talloc_free(ev);
546 0 : return NULL;
547 : }
548 :
549 54547972 : ev->ops = ops;
550 54547972 : ev->additional_data = additional_data;
551 :
552 54547972 : ret = ev->ops->context_init(ev);
553 54547972 : if (ret != 0) {
554 0 : talloc_free(ev);
555 0 : return NULL;
556 : }
557 :
558 54547972 : return ev;
559 : }
560 :
561 : /*
562 : create a event_context structure. This must be the first events
563 : call, and all subsequent calls pass this event_context as the first
564 : element. Event handlers also receive this as their first argument.
565 : */
566 54547972 : struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
567 : const char *name)
568 : {
569 : const struct tevent_ops *ops;
570 :
571 54547972 : ops = tevent_find_ops_byname(name);
572 54547972 : if (ops == NULL) {
573 0 : return NULL;
574 : }
575 :
576 54547972 : return tevent_context_init_ops(mem_ctx, ops, NULL);
577 : }
578 :
579 :
580 : /*
581 : create a event_context structure. This must be the first events
582 : call, and all subsequent calls pass this event_context as the first
583 : element. Event handlers also receive this as their first argument.
584 : */
585 54097049 : struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
586 : {
587 54097049 : return tevent_context_init_byname(mem_ctx, NULL);
588 : }
589 :
590 : /*
591 : add a fd based event
592 : return NULL on failure (memory allocation error)
593 : */
594 8875895 : struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
595 : TALLOC_CTX *mem_ctx,
596 : int fd,
597 : uint16_t flags,
598 : tevent_fd_handler_t handler,
599 : void *private_data,
600 : const char *handler_name,
601 : const char *location)
602 : {
603 8875895 : return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
604 : handler_name, location);
605 : }
606 :
607 : /*
608 : set a close function on the fd event
609 : */
610 6881190 : void tevent_fd_set_close_fn(struct tevent_fd *fde,
611 : tevent_fd_close_fn_t close_fn)
612 : {
613 6881190 : if (!fde) return;
614 6881190 : if (!fde->event_ctx) return;
615 6881190 : fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
616 : }
617 :
618 6680479 : static void tevent_fd_auto_close_fn(struct tevent_context *ev,
619 : struct tevent_fd *fde,
620 : int fd,
621 : void *private_data)
622 : {
623 6680479 : close(fd);
624 6680479 : }
625 :
626 6685899 : void tevent_fd_set_auto_close(struct tevent_fd *fde)
627 : {
628 6685899 : tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
629 6685899 : }
630 :
631 : /*
632 : return the fd event flags
633 : */
634 28067434 : uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
635 : {
636 28067434 : if (!fde) return 0;
637 27806968 : if (!fde->event_ctx) return 0;
638 27740862 : return fde->event_ctx->ops->get_fd_flags(fde);
639 : }
640 :
641 : /*
642 : set the fd event flags
643 : */
644 18693872 : void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
645 : {
646 18693872 : if (!fde) return;
647 18689157 : if (!fde->event_ctx) return;
648 18670433 : fde->event_ctx->ops->set_fd_flags(fde, flags);
649 : }
650 :
651 1 : bool tevent_signal_support(struct tevent_context *ev)
652 : {
653 1 : if (ev->ops->add_signal) {
654 1 : return true;
655 : }
656 0 : return false;
657 : }
658 :
659 : static void (*tevent_abort_fn)(const char *reason);
660 :
661 0 : void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
662 : {
663 0 : tevent_abort_fn = abort_fn;
664 0 : }
665 :
666 0 : void tevent_abort(struct tevent_context *ev, const char *reason)
667 : {
668 0 : if (ev != NULL) {
669 0 : tevent_debug(ev, TEVENT_DEBUG_FATAL,
670 : "abort: %s\n", reason);
671 : }
672 :
673 0 : if (!tevent_abort_fn) {
674 0 : abort();
675 : }
676 :
677 0 : tevent_abort_fn(reason);
678 0 : }
679 :
680 : /*
681 : add a timer event
682 : return NULL on failure
683 : */
684 276365892 : struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
685 : TALLOC_CTX *mem_ctx,
686 : struct timeval next_event,
687 : tevent_timer_handler_t handler,
688 : void *private_data,
689 : const char *handler_name,
690 : const char *location)
691 : {
692 276365892 : return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
693 : handler_name, location);
694 : }
695 :
696 : /*
697 : allocate an immediate event
698 : return NULL on failure (memory allocation error)
699 : */
700 75919152 : struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
701 : const char *location)
702 : {
703 : struct tevent_immediate *im;
704 :
705 75919152 : im = talloc(mem_ctx, struct tevent_immediate);
706 75919152 : if (im == NULL) return NULL;
707 :
708 75919152 : *im = (struct tevent_immediate) { .create_location = location };
709 :
710 75919152 : return im;
711 : }
712 :
713 : /*
714 : schedule an immediate event
715 : */
716 17329540 : void _tevent_schedule_immediate(struct tevent_immediate *im,
717 : struct tevent_context *ev,
718 : tevent_immediate_handler_t handler,
719 : void *private_data,
720 : const char *handler_name,
721 : const char *location)
722 : {
723 17329540 : ev->ops->schedule_immediate(im, ev, handler, private_data,
724 : handler_name, location);
725 17329540 : }
726 :
727 : /*
728 : add a signal event
729 :
730 : sa_flags are flags to sigaction(2)
731 :
732 : return NULL on failure
733 : */
734 108669 : struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
735 : TALLOC_CTX *mem_ctx,
736 : int signum,
737 : int sa_flags,
738 : tevent_signal_handler_t handler,
739 : void *private_data,
740 : const char *handler_name,
741 : const char *location)
742 : {
743 108669 : return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
744 : handler_name, location);
745 : }
746 :
747 54424572 : void tevent_loop_allow_nesting(struct tevent_context *ev)
748 : {
749 54424572 : if (ev->wrapper.glue != NULL) {
750 0 : tevent_abort(ev, "tevent_loop_allow_nesting() on wrapper");
751 0 : return;
752 : }
753 :
754 54424572 : if (ev->wrapper.list != NULL) {
755 0 : tevent_abort(ev, "tevent_loop_allow_nesting() with wrapper");
756 0 : return;
757 : }
758 :
759 54424572 : ev->nesting.allowed = true;
760 : }
761 :
762 1321 : void tevent_loop_set_nesting_hook(struct tevent_context *ev,
763 : tevent_nesting_hook hook,
764 : void *private_data)
765 : {
766 2594 : if (ev->nesting.hook_fn &&
767 2590 : (ev->nesting.hook_fn != hook ||
768 1317 : ev->nesting.hook_private != private_data)) {
769 : /* the way the nesting hook code is currently written
770 : we cannot support two different nesting hooks at the
771 : same time. */
772 0 : tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
773 : }
774 1321 : ev->nesting.hook_fn = hook;
775 1321 : ev->nesting.hook_private = private_data;
776 1321 : }
777 :
778 0 : static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
779 : {
780 : const char *reason;
781 :
782 0 : reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
783 : location);
784 0 : if (!reason) {
785 0 : reason = "tevent_loop_once() nesting";
786 : }
787 :
788 0 : tevent_abort(ev, reason);
789 0 : }
790 :
791 : /*
792 : do a single event loop using the events defined in ev
793 : */
794 200473794 : int _tevent_loop_once(struct tevent_context *ev, const char *location)
795 : {
796 : int ret;
797 200473794 : void *nesting_stack_ptr = NULL;
798 :
799 200473794 : ev->nesting.level++;
800 :
801 200473794 : if (ev->nesting.level > 1) {
802 54526426 : if (!ev->nesting.allowed) {
803 0 : tevent_abort_nesting(ev, location);
804 0 : errno = ELOOP;
805 0 : return -1;
806 : }
807 : }
808 200473794 : if (ev->nesting.level > 0) {
809 200473794 : if (ev->nesting.hook_fn) {
810 : int ret2;
811 2940265 : ret2 = ev->nesting.hook_fn(ev,
812 : ev->nesting.hook_private,
813 : ev->nesting.level,
814 : true,
815 : (void *)&nesting_stack_ptr,
816 : location);
817 2940265 : if (ret2 != 0) {
818 0 : ret = ret2;
819 0 : goto done;
820 : }
821 : }
822 : }
823 :
824 200473794 : tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
825 200473794 : ret = ev->ops->loop_once(ev, location);
826 200436412 : tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
827 :
828 200436412 : if (ev->nesting.level > 0) {
829 200436412 : if (ev->nesting.hook_fn) {
830 : int ret2;
831 2940266 : ret2 = ev->nesting.hook_fn(ev,
832 : ev->nesting.hook_private,
833 : ev->nesting.level,
834 : false,
835 : (void *)&nesting_stack_ptr,
836 : location);
837 2940266 : if (ret2 != 0) {
838 0 : ret = ret2;
839 0 : goto done;
840 : }
841 : }
842 : }
843 :
844 374853772 : done:
845 200436412 : ev->nesting.level--;
846 200436412 : return ret;
847 : }
848 :
849 : /*
850 : this is a performance optimization for the samba4 nested event loop problems
851 : */
852 0 : int _tevent_loop_until(struct tevent_context *ev,
853 : bool (*finished)(void *private_data),
854 : void *private_data,
855 : const char *location)
856 : {
857 0 : int ret = 0;
858 0 : void *nesting_stack_ptr = NULL;
859 :
860 0 : ev->nesting.level++;
861 :
862 0 : if (ev->nesting.level > 1) {
863 0 : if (!ev->nesting.allowed) {
864 0 : tevent_abort_nesting(ev, location);
865 0 : errno = ELOOP;
866 0 : return -1;
867 : }
868 : }
869 0 : if (ev->nesting.level > 0) {
870 0 : if (ev->nesting.hook_fn) {
871 : int ret2;
872 0 : ret2 = ev->nesting.hook_fn(ev,
873 : ev->nesting.hook_private,
874 : ev->nesting.level,
875 : true,
876 : (void *)&nesting_stack_ptr,
877 : location);
878 0 : if (ret2 != 0) {
879 0 : ret = ret2;
880 0 : goto done;
881 : }
882 : }
883 : }
884 :
885 0 : while (!finished(private_data)) {
886 0 : tevent_trace_point_callback(ev, TEVENT_TRACE_BEFORE_LOOP_ONCE);
887 0 : ret = ev->ops->loop_once(ev, location);
888 0 : tevent_trace_point_callback(ev, TEVENT_TRACE_AFTER_LOOP_ONCE);
889 0 : if (ret != 0) {
890 0 : break;
891 : }
892 : }
893 :
894 0 : if (ev->nesting.level > 0) {
895 0 : if (ev->nesting.hook_fn) {
896 : int ret2;
897 0 : ret2 = ev->nesting.hook_fn(ev,
898 : ev->nesting.hook_private,
899 : ev->nesting.level,
900 : false,
901 : (void *)&nesting_stack_ptr,
902 : location);
903 0 : if (ret2 != 0) {
904 0 : ret = ret2;
905 0 : goto done;
906 : }
907 : }
908 : }
909 :
910 0 : done:
911 0 : ev->nesting.level--;
912 0 : return ret;
913 : }
914 :
915 42713269 : bool tevent_common_have_events(struct tevent_context *ev)
916 : {
917 42713269 : if (ev->fd_events != NULL) {
918 42713268 : if (ev->fd_events != ev->wakeup_fde) {
919 42677731 : return true;
920 : }
921 35537 : if (ev->fd_events->next != NULL) {
922 35537 : return true;
923 : }
924 :
925 : /*
926 : * At this point we just have the wakeup pipe event as
927 : * the only fd_event. That one does not count as a
928 : * regular event, so look at the other event types.
929 : */
930 : }
931 :
932 2 : return ((ev->timer_events != NULL) ||
933 2 : (ev->immediate_events != NULL) ||
934 1 : (ev->signal_events != NULL));
935 : }
936 :
937 : /*
938 : return on failure or (with 0) if all fd events are removed
939 : */
940 37293 : int tevent_common_loop_wait(struct tevent_context *ev,
941 : const char *location)
942 : {
943 : /*
944 : * loop as long as we have events pending
945 : */
946 42737816 : while (tevent_common_have_events(ev)) {
947 : int ret;
948 42713268 : ret = _tevent_loop_once(ev, location);
949 42675976 : if (ret != 0) {
950 0 : tevent_debug(ev, TEVENT_DEBUG_FATAL,
951 : "_tevent_loop_once() failed: %d - %s\n",
952 0 : ret, strerror(errno));
953 0 : return ret;
954 : }
955 : }
956 :
957 1 : tevent_debug(ev, TEVENT_DEBUG_WARNING,
958 : "tevent_common_loop_wait() out of events\n");
959 1 : return 0;
960 : }
961 :
962 : /*
963 : return on failure or (with 0) if all fd events are removed
964 : */
965 37293 : int _tevent_loop_wait(struct tevent_context *ev, const char *location)
966 : {
967 37293 : return ev->ops->loop_wait(ev, location);
968 : }
969 :
970 :
971 : /*
972 : re-initialise a tevent context. This leaves you with the same
973 : event context, but all events are wiped and the structure is
974 : re-initialised. This is most useful after a fork()
975 :
976 : zero is returned on success, non-zero on failure
977 : */
978 37331 : int tevent_re_initialise(struct tevent_context *ev)
979 : {
980 37331 : tevent_common_context_destructor(ev);
981 :
982 37331 : tevent_common_context_constructor(ev);
983 :
984 37331 : return ev->ops->context_init(ev);
985 : }
986 :
987 1172866 : static void wakeup_pipe_handler(struct tevent_context *ev,
988 : struct tevent_fd *fde,
989 : uint16_t flags, void *_private)
990 : {
991 : ssize_t ret;
992 :
993 : do {
994 : /*
995 : * This is the boilerplate for eventfd, but it works
996 : * for pipes too. And as we don't care about the data
997 : * we read, we're fine.
998 : */
999 : uint64_t val;
1000 1172866 : ret = read(fde->fd, &val, sizeof(val));
1001 1172866 : } while (ret == -1 && errno == EINTR);
1002 1172866 : }
1003 :
1004 : /*
1005 : * Initialize the wakeup pipe and pipe fde
1006 : */
1007 :
1008 109069 : int tevent_common_wakeup_init(struct tevent_context *ev)
1009 : {
1010 : int ret, read_fd;
1011 :
1012 109069 : if (ev->wakeup_fde != NULL) {
1013 57440 : return 0;
1014 : }
1015 :
1016 : #ifdef HAVE_EVENTFD
1017 51629 : ret = eventfd(0, EFD_NONBLOCK);
1018 51629 : if (ret == -1) {
1019 0 : return errno;
1020 : }
1021 51629 : read_fd = ev->wakeup_fd = ret;
1022 : #else
1023 : {
1024 : int pipe_fds[2];
1025 : ret = pipe(pipe_fds);
1026 : if (ret == -1) {
1027 : return errno;
1028 : }
1029 : ev->wakeup_fd = pipe_fds[1];
1030 : ev->wakeup_read_fd = pipe_fds[0];
1031 :
1032 : ev_set_blocking(ev->wakeup_fd, false);
1033 : ev_set_blocking(ev->wakeup_read_fd, false);
1034 :
1035 : read_fd = ev->wakeup_read_fd;
1036 : }
1037 : #endif
1038 :
1039 51629 : ev->wakeup_fde = tevent_add_fd(ev, ev, read_fd, TEVENT_FD_READ,
1040 : wakeup_pipe_handler, NULL);
1041 51629 : if (ev->wakeup_fde == NULL) {
1042 0 : close(ev->wakeup_fd);
1043 : #ifndef HAVE_EVENTFD
1044 : close(ev->wakeup_read_fd);
1045 : #endif
1046 0 : return ENOMEM;
1047 : }
1048 :
1049 51629 : return 0;
1050 : }
1051 :
1052 1175982 : int tevent_common_wakeup_fd(int fd)
1053 : {
1054 : ssize_t ret;
1055 :
1056 : do {
1057 : #ifdef HAVE_EVENTFD
1058 1175982 : uint64_t val = 1;
1059 1175982 : ret = write(fd, &val, sizeof(val));
1060 : #else
1061 : char c = '\0';
1062 : ret = write(fd, &c, 1);
1063 : #endif
1064 1175982 : } while ((ret == -1) && (errno == EINTR));
1065 :
1066 1175982 : return 0;
1067 : }
1068 :
1069 1174290 : int tevent_common_wakeup(struct tevent_context *ev)
1070 : {
1071 1174290 : if (ev->wakeup_fde == NULL) {
1072 0 : return ENOTCONN;
1073 : }
1074 :
1075 1174290 : return tevent_common_wakeup_fd(ev->wakeup_fd);
1076 : }
1077 :
1078 54575710 : static void tevent_common_wakeup_fini(struct tevent_context *ev)
1079 : {
1080 54575710 : if (ev->wakeup_fde == NULL) {
1081 54524373 : return;
1082 : }
1083 :
1084 51337 : TALLOC_FREE(ev->wakeup_fde);
1085 :
1086 51337 : close(ev->wakeup_fd);
1087 : #ifndef HAVE_EVENTFD
1088 : close(ev->wakeup_read_fd);
1089 : #endif
1090 : }
|