| 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 |  | 
|---|
| 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 | */ | 
|---|
| 104 | void 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 | */ | 
|---|
| 113 | static 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 | */ | 
|---|
| 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 | } | 
|---|
| 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 | } | 
|---|