[429] | 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 |
|
---|
[745] | 91 | e = talloc(NULL, struct tevent_ops_list);
|
---|
[429] | 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);
|
---|
[745] | 107 | tevent_default_backend = talloc_strdup(NULL, backend);
|
---|
[429] | 108 | }
|
---|
| 109 |
|
---|
| 110 | /*
|
---|
| 111 | initialise backends if not already done
|
---|
| 112 | */
|
---|
| 113 | static void tevent_backend_init(void)
|
---|
| 114 | {
|
---|
| 115 | tevent_select_init();
|
---|
[745] | 116 | tevent_poll_init();
|
---|
[429] | 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 | struct 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 | */
|
---|
| 282 | void 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 |
|
---|
| 290 | static 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 |
|
---|
| 298 | void 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 | */
|
---|
| 306 | uint16_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 | */
|
---|
| 316 | void 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 |
|
---|
| 323 | bool tevent_signal_support(struct tevent_context *ev)
|
---|
| 324 | {
|
---|
| 325 | if (ev->ops->add_signal) {
|
---|
| 326 | return true;
|
---|
| 327 | }
|
---|
| 328 | return false;
|
---|
| 329 | }
|
---|
| 330 |
|
---|
| 331 | static void (*tevent_abort_fn)(const char *reason);
|
---|
| 332 |
|
---|
| 333 | void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
|
---|
| 334 | {
|
---|
| 335 | tevent_abort_fn = abort_fn;
|
---|
| 336 | }
|
---|
| 337 |
|
---|
| 338 | static 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 | */
|
---|
| 354 | struct 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 | */
|
---|
| 370 | struct 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 | */
|
---|
| 396 | void _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 | */
|
---|
| 414 | struct 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 |
|
---|
| 427 | void tevent_loop_allow_nesting(struct tevent_context *ev)
|
---|
| 428 | {
|
---|
| 429 | ev->nesting.allowed = true;
|
---|
| 430 | }
|
---|
| 431 |
|
---|
| 432 | void 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 |
|
---|
| 448 | static 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 | */
|
---|
| 464 | int _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 |
|
---|
| 512 | done:
|
---|
| 513 | ev->nesting.level--;
|
---|
| 514 | return ret;
|
---|
| 515 | }
|
---|
| 516 |
|
---|
| 517 | /*
|
---|
| 518 | this is a performance optimization for the samba4 nested event loop problems
|
---|
| 519 | */
|
---|
| 520 | int _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 |
|
---|
| 576 | done:
|
---|
| 577 | ev->nesting.level--;
|
---|
| 578 | return ret;
|
---|
| 579 | }
|
---|
| 580 |
|
---|
| 581 | /*
|
---|
| 582 | return on failure or (with 0) if all fd events are removed
|
---|
| 583 | */
|
---|
| 584 | int 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 | */
|
---|
| 612 | int _tevent_loop_wait(struct tevent_context *ev, const char *location)
|
---|
| 613 | {
|
---|
| 614 | return ev->ops->loop_wait(ev, location);
|
---|
| 615 | }
|
---|
[745] | 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 | */
|
---|
| 625 | int tevent_re_initialise(struct tevent_context *ev)
|
---|
| 626 | {
|
---|
| 627 | tevent_common_context_destructor(ev);
|
---|
| 628 |
|
---|
| 629 | return ev->ops->context_init(ev);
|
---|
| 630 | }
|
---|