| 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(talloc_autofree_context(), 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(talloc_autofree_context(),
|
|---|
| 108 | backend);
|
|---|
| 109 | }
|
|---|
| 110 |
|
|---|
| 111 | /*
|
|---|
| 112 | initialise backends if not already done
|
|---|
| 113 | */
|
|---|
| 114 | static void tevent_backend_init(void)
|
|---|
| 115 | {
|
|---|
| 116 | tevent_select_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 |
|
|---|
| 181 | return 0;
|
|---|
| 182 | }
|
|---|
| 183 |
|
|---|
| 184 | /*
|
|---|
| 185 | create a event_context structure for a specific implemementation.
|
|---|
| 186 | This must be the first events call, and all subsequent calls pass
|
|---|
| 187 | this event_context as the first element. Event handlers also
|
|---|
| 188 | receive this as their first argument.
|
|---|
| 189 |
|
|---|
| 190 | This function is for allowing third-party-applications to hook in gluecode
|
|---|
| 191 | to their own event loop code, so that they can make async usage of our client libs
|
|---|
| 192 |
|
|---|
| 193 | NOTE: use tevent_context_init() inside of samba!
|
|---|
| 194 | */
|
|---|
| 195 | static struct tevent_context *tevent_context_init_ops(TALLOC_CTX *mem_ctx,
|
|---|
| 196 | const struct tevent_ops *ops)
|
|---|
| 197 | {
|
|---|
| 198 | struct tevent_context *ev;
|
|---|
| 199 | int ret;
|
|---|
| 200 |
|
|---|
| 201 | ev = talloc_zero(mem_ctx, struct tevent_context);
|
|---|
| 202 | if (!ev) return NULL;
|
|---|
| 203 |
|
|---|
| 204 | talloc_set_destructor(ev, tevent_common_context_destructor);
|
|---|
| 205 |
|
|---|
| 206 | ev->ops = ops;
|
|---|
| 207 |
|
|---|
| 208 | ret = ev->ops->context_init(ev);
|
|---|
| 209 | if (ret != 0) {
|
|---|
| 210 | talloc_free(ev);
|
|---|
| 211 | return NULL;
|
|---|
| 212 | }
|
|---|
| 213 |
|
|---|
| 214 | return ev;
|
|---|
| 215 | }
|
|---|
| 216 |
|
|---|
| 217 | /*
|
|---|
| 218 | create a event_context structure. This must be the first events
|
|---|
| 219 | call, and all subsequent calls pass this event_context as the first
|
|---|
| 220 | element. Event handlers also receive this as their first argument.
|
|---|
| 221 | */
|
|---|
| 222 | struct tevent_context *tevent_context_init_byname(TALLOC_CTX *mem_ctx,
|
|---|
| 223 | const char *name)
|
|---|
| 224 | {
|
|---|
| 225 | struct tevent_ops_list *e;
|
|---|
| 226 |
|
|---|
| 227 | tevent_backend_init();
|
|---|
| 228 |
|
|---|
| 229 | if (name == NULL) {
|
|---|
| 230 | name = tevent_default_backend;
|
|---|
| 231 | }
|
|---|
| 232 | if (name == NULL) {
|
|---|
| 233 | name = "standard";
|
|---|
| 234 | }
|
|---|
| 235 |
|
|---|
| 236 | for (e=tevent_backends;e;e=e->next) {
|
|---|
| 237 | if (strcmp(name, e->name) == 0) {
|
|---|
| 238 | return tevent_context_init_ops(mem_ctx, e->ops);
|
|---|
| 239 | }
|
|---|
| 240 | }
|
|---|
| 241 | return NULL;
|
|---|
| 242 | }
|
|---|
| 243 |
|
|---|
| 244 |
|
|---|
| 245 | /*
|
|---|
| 246 | create a event_context structure. This must be the first events
|
|---|
| 247 | call, and all subsequent calls pass this event_context as the first
|
|---|
| 248 | element. Event handlers also receive this as their first argument.
|
|---|
| 249 | */
|
|---|
| 250 | struct tevent_context *tevent_context_init(TALLOC_CTX *mem_ctx)
|
|---|
| 251 | {
|
|---|
| 252 | return tevent_context_init_byname(mem_ctx, NULL);
|
|---|
| 253 | }
|
|---|
| 254 |
|
|---|
| 255 | /*
|
|---|
| 256 | add a fd based event
|
|---|
| 257 | return NULL on failure (memory allocation error)
|
|---|
| 258 |
|
|---|
| 259 | if flags contains TEVENT_FD_AUTOCLOSE then the fd will be closed when
|
|---|
| 260 | the returned fd_event context is freed
|
|---|
| 261 | */
|
|---|
| 262 | struct tevent_fd *_tevent_add_fd(struct tevent_context *ev,
|
|---|
| 263 | TALLOC_CTX *mem_ctx,
|
|---|
| 264 | int fd,
|
|---|
| 265 | uint16_t flags,
|
|---|
| 266 | tevent_fd_handler_t handler,
|
|---|
| 267 | void *private_data,
|
|---|
| 268 | const char *handler_name,
|
|---|
| 269 | const char *location)
|
|---|
| 270 | {
|
|---|
| 271 | return ev->ops->add_fd(ev, mem_ctx, fd, flags, handler, private_data,
|
|---|
| 272 | handler_name, location);
|
|---|
| 273 | }
|
|---|
| 274 |
|
|---|
| 275 | /*
|
|---|
| 276 | set a close function on the fd event
|
|---|
| 277 | */
|
|---|
| 278 | void tevent_fd_set_close_fn(struct tevent_fd *fde,
|
|---|
| 279 | tevent_fd_close_fn_t close_fn)
|
|---|
| 280 | {
|
|---|
| 281 | if (!fde) return;
|
|---|
| 282 | if (!fde->event_ctx) return;
|
|---|
| 283 | fde->event_ctx->ops->set_fd_close_fn(fde, close_fn);
|
|---|
| 284 | }
|
|---|
| 285 |
|
|---|
| 286 | static void tevent_fd_auto_close_fn(struct tevent_context *ev,
|
|---|
| 287 | struct tevent_fd *fde,
|
|---|
| 288 | int fd,
|
|---|
| 289 | void *private_data)
|
|---|
| 290 | {
|
|---|
| 291 | close(fd);
|
|---|
| 292 | }
|
|---|
| 293 |
|
|---|
| 294 | void tevent_fd_set_auto_close(struct tevent_fd *fde)
|
|---|
| 295 | {
|
|---|
| 296 | tevent_fd_set_close_fn(fde, tevent_fd_auto_close_fn);
|
|---|
| 297 | }
|
|---|
| 298 |
|
|---|
| 299 | /*
|
|---|
| 300 | return the fd event flags
|
|---|
| 301 | */
|
|---|
| 302 | uint16_t tevent_fd_get_flags(struct tevent_fd *fde)
|
|---|
| 303 | {
|
|---|
| 304 | if (!fde) return 0;
|
|---|
| 305 | if (!fde->event_ctx) return 0;
|
|---|
| 306 | return fde->event_ctx->ops->get_fd_flags(fde);
|
|---|
| 307 | }
|
|---|
| 308 |
|
|---|
| 309 | /*
|
|---|
| 310 | set the fd event flags
|
|---|
| 311 | */
|
|---|
| 312 | void tevent_fd_set_flags(struct tevent_fd *fde, uint16_t flags)
|
|---|
| 313 | {
|
|---|
| 314 | if (!fde) return;
|
|---|
| 315 | if (!fde->event_ctx) return;
|
|---|
| 316 | fde->event_ctx->ops->set_fd_flags(fde, flags);
|
|---|
| 317 | }
|
|---|
| 318 |
|
|---|
| 319 | bool tevent_signal_support(struct tevent_context *ev)
|
|---|
| 320 | {
|
|---|
| 321 | if (ev->ops->add_signal) {
|
|---|
| 322 | return true;
|
|---|
| 323 | }
|
|---|
| 324 | return false;
|
|---|
| 325 | }
|
|---|
| 326 |
|
|---|
| 327 | static void (*tevent_abort_fn)(const char *reason);
|
|---|
| 328 |
|
|---|
| 329 | void tevent_set_abort_fn(void (*abort_fn)(const char *reason))
|
|---|
| 330 | {
|
|---|
| 331 | tevent_abort_fn = abort_fn;
|
|---|
| 332 | }
|
|---|
| 333 |
|
|---|
| 334 | static void tevent_abort(struct tevent_context *ev, const char *reason)
|
|---|
| 335 | {
|
|---|
| 336 | tevent_debug(ev, TEVENT_DEBUG_FATAL,
|
|---|
| 337 | "abort: %s\n", reason);
|
|---|
| 338 |
|
|---|
| 339 | if (!tevent_abort_fn) {
|
|---|
| 340 | abort();
|
|---|
| 341 | }
|
|---|
| 342 |
|
|---|
| 343 | tevent_abort_fn(reason);
|
|---|
| 344 | }
|
|---|
| 345 |
|
|---|
| 346 | /*
|
|---|
| 347 | add a timer event
|
|---|
| 348 | return NULL on failure
|
|---|
| 349 | */
|
|---|
| 350 | struct tevent_timer *_tevent_add_timer(struct tevent_context *ev,
|
|---|
| 351 | TALLOC_CTX *mem_ctx,
|
|---|
| 352 | struct timeval next_event,
|
|---|
| 353 | tevent_timer_handler_t handler,
|
|---|
| 354 | void *private_data,
|
|---|
| 355 | const char *handler_name,
|
|---|
| 356 | const char *location)
|
|---|
| 357 | {
|
|---|
| 358 | return ev->ops->add_timer(ev, mem_ctx, next_event, handler, private_data,
|
|---|
| 359 | handler_name, location);
|
|---|
| 360 | }
|
|---|
| 361 |
|
|---|
| 362 | /*
|
|---|
| 363 | allocate an immediate event
|
|---|
| 364 | return NULL on failure (memory allocation error)
|
|---|
| 365 | */
|
|---|
| 366 | struct tevent_immediate *_tevent_create_immediate(TALLOC_CTX *mem_ctx,
|
|---|
| 367 | const char *location)
|
|---|
| 368 | {
|
|---|
| 369 | struct tevent_immediate *im;
|
|---|
| 370 |
|
|---|
| 371 | im = talloc(mem_ctx, struct tevent_immediate);
|
|---|
| 372 | if (im == NULL) return NULL;
|
|---|
| 373 |
|
|---|
| 374 | im->prev = NULL;
|
|---|
| 375 | im->next = NULL;
|
|---|
| 376 | im->event_ctx = NULL;
|
|---|
| 377 | im->create_location = location;
|
|---|
| 378 | im->handler = NULL;
|
|---|
| 379 | im->private_data = NULL;
|
|---|
| 380 | im->handler_name = NULL;
|
|---|
| 381 | im->schedule_location = NULL;
|
|---|
| 382 | im->cancel_fn = NULL;
|
|---|
| 383 | im->additional_data = NULL;
|
|---|
| 384 |
|
|---|
| 385 | return im;
|
|---|
| 386 | }
|
|---|
| 387 |
|
|---|
| 388 | /*
|
|---|
| 389 | schedule an immediate event
|
|---|
| 390 | return NULL on failure
|
|---|
| 391 | */
|
|---|
| 392 | void _tevent_schedule_immediate(struct tevent_immediate *im,
|
|---|
| 393 | struct tevent_context *ev,
|
|---|
| 394 | tevent_immediate_handler_t handler,
|
|---|
| 395 | void *private_data,
|
|---|
| 396 | const char *handler_name,
|
|---|
| 397 | const char *location)
|
|---|
| 398 | {
|
|---|
| 399 | ev->ops->schedule_immediate(im, ev, handler, private_data,
|
|---|
| 400 | handler_name, location);
|
|---|
| 401 | }
|
|---|
| 402 |
|
|---|
| 403 | /*
|
|---|
| 404 | add a signal event
|
|---|
| 405 |
|
|---|
| 406 | sa_flags are flags to sigaction(2)
|
|---|
| 407 |
|
|---|
| 408 | return NULL on failure
|
|---|
| 409 | */
|
|---|
| 410 | struct tevent_signal *_tevent_add_signal(struct tevent_context *ev,
|
|---|
| 411 | TALLOC_CTX *mem_ctx,
|
|---|
| 412 | int signum,
|
|---|
| 413 | int sa_flags,
|
|---|
| 414 | tevent_signal_handler_t handler,
|
|---|
| 415 | void *private_data,
|
|---|
| 416 | const char *handler_name,
|
|---|
| 417 | const char *location)
|
|---|
| 418 | {
|
|---|
| 419 | return ev->ops->add_signal(ev, mem_ctx, signum, sa_flags, handler, private_data,
|
|---|
| 420 | handler_name, location);
|
|---|
| 421 | }
|
|---|
| 422 |
|
|---|
| 423 | void tevent_loop_allow_nesting(struct tevent_context *ev)
|
|---|
| 424 | {
|
|---|
| 425 | ev->nesting.allowed = true;
|
|---|
| 426 | }
|
|---|
| 427 |
|
|---|
| 428 | void tevent_loop_set_nesting_hook(struct tevent_context *ev,
|
|---|
| 429 | tevent_nesting_hook hook,
|
|---|
| 430 | void *private_data)
|
|---|
| 431 | {
|
|---|
| 432 | if (ev->nesting.hook_fn &&
|
|---|
| 433 | (ev->nesting.hook_fn != hook ||
|
|---|
| 434 | ev->nesting.hook_private != private_data)) {
|
|---|
| 435 | /* the way the nesting hook code is currently written
|
|---|
| 436 | we cannot support two different nesting hooks at the
|
|---|
| 437 | same time. */
|
|---|
| 438 | tevent_abort(ev, "tevent: Violation of nesting hook rules\n");
|
|---|
| 439 | }
|
|---|
| 440 | ev->nesting.hook_fn = hook;
|
|---|
| 441 | ev->nesting.hook_private = private_data;
|
|---|
| 442 | }
|
|---|
| 443 |
|
|---|
| 444 | static void tevent_abort_nesting(struct tevent_context *ev, const char *location)
|
|---|
| 445 | {
|
|---|
| 446 | const char *reason;
|
|---|
| 447 |
|
|---|
| 448 | reason = talloc_asprintf(NULL, "tevent_loop_once() nesting at %s",
|
|---|
| 449 | location);
|
|---|
| 450 | if (!reason) {
|
|---|
| 451 | reason = "tevent_loop_once() nesting";
|
|---|
| 452 | }
|
|---|
| 453 |
|
|---|
| 454 | tevent_abort(ev, reason);
|
|---|
| 455 | }
|
|---|
| 456 |
|
|---|
| 457 | /*
|
|---|
| 458 | do a single event loop using the events defined in ev
|
|---|
| 459 | */
|
|---|
| 460 | int _tevent_loop_once(struct tevent_context *ev, const char *location)
|
|---|
| 461 | {
|
|---|
| 462 | int ret;
|
|---|
| 463 | void *nesting_stack_ptr = NULL;
|
|---|
| 464 |
|
|---|
| 465 | ev->nesting.level++;
|
|---|
| 466 |
|
|---|
| 467 | if (ev->nesting.level > 1) {
|
|---|
| 468 | if (!ev->nesting.allowed) {
|
|---|
| 469 | tevent_abort_nesting(ev, location);
|
|---|
| 470 | errno = ELOOP;
|
|---|
| 471 | return -1;
|
|---|
| 472 | }
|
|---|
| 473 | }
|
|---|
| 474 | if (ev->nesting.level > 0) {
|
|---|
| 475 | if (ev->nesting.hook_fn) {
|
|---|
| 476 | int ret2;
|
|---|
| 477 | ret2 = ev->nesting.hook_fn(ev,
|
|---|
| 478 | ev->nesting.hook_private,
|
|---|
| 479 | ev->nesting.level,
|
|---|
| 480 | true,
|
|---|
| 481 | (void *)&nesting_stack_ptr,
|
|---|
| 482 | location);
|
|---|
| 483 | if (ret2 != 0) {
|
|---|
| 484 | ret = ret2;
|
|---|
| 485 | goto done;
|
|---|
| 486 | }
|
|---|
| 487 | }
|
|---|
| 488 | }
|
|---|
| 489 |
|
|---|
| 490 | ret = ev->ops->loop_once(ev, location);
|
|---|
| 491 |
|
|---|
| 492 | if (ev->nesting.level > 0) {
|
|---|
| 493 | if (ev->nesting.hook_fn) {
|
|---|
| 494 | int ret2;
|
|---|
| 495 | ret2 = ev->nesting.hook_fn(ev,
|
|---|
| 496 | ev->nesting.hook_private,
|
|---|
| 497 | ev->nesting.level,
|
|---|
| 498 | false,
|
|---|
| 499 | (void *)&nesting_stack_ptr,
|
|---|
| 500 | location);
|
|---|
| 501 | if (ret2 != 0) {
|
|---|
| 502 | ret = ret2;
|
|---|
| 503 | goto done;
|
|---|
| 504 | }
|
|---|
| 505 | }
|
|---|
| 506 | }
|
|---|
| 507 |
|
|---|
| 508 | done:
|
|---|
| 509 | ev->nesting.level--;
|
|---|
| 510 | return ret;
|
|---|
| 511 | }
|
|---|
| 512 |
|
|---|
| 513 | /*
|
|---|
| 514 | this is a performance optimization for the samba4 nested event loop problems
|
|---|
| 515 | */
|
|---|
| 516 | int _tevent_loop_until(struct tevent_context *ev,
|
|---|
| 517 | bool (*finished)(void *private_data),
|
|---|
| 518 | void *private_data,
|
|---|
| 519 | const char *location)
|
|---|
| 520 | {
|
|---|
| 521 | int ret = 0;
|
|---|
| 522 | void *nesting_stack_ptr = NULL;
|
|---|
| 523 |
|
|---|
| 524 | ev->nesting.level++;
|
|---|
| 525 |
|
|---|
| 526 | if (ev->nesting.level > 1) {
|
|---|
| 527 | if (!ev->nesting.allowed) {
|
|---|
| 528 | tevent_abort_nesting(ev, location);
|
|---|
| 529 | errno = ELOOP;
|
|---|
| 530 | return -1;
|
|---|
| 531 | }
|
|---|
| 532 | }
|
|---|
| 533 | if (ev->nesting.level > 0) {
|
|---|
| 534 | if (ev->nesting.hook_fn) {
|
|---|
| 535 | int ret2;
|
|---|
| 536 | ret2 = ev->nesting.hook_fn(ev,
|
|---|
| 537 | ev->nesting.hook_private,
|
|---|
| 538 | ev->nesting.level,
|
|---|
| 539 | true,
|
|---|
| 540 | (void *)&nesting_stack_ptr,
|
|---|
| 541 | location);
|
|---|
| 542 | if (ret2 != 0) {
|
|---|
| 543 | ret = ret2;
|
|---|
| 544 | goto done;
|
|---|
| 545 | }
|
|---|
| 546 | }
|
|---|
| 547 | }
|
|---|
| 548 |
|
|---|
| 549 | while (!finished(private_data)) {
|
|---|
| 550 | ret = ev->ops->loop_once(ev, location);
|
|---|
| 551 | if (ret != 0) {
|
|---|
| 552 | break;
|
|---|
| 553 | }
|
|---|
| 554 | }
|
|---|
| 555 |
|
|---|
| 556 | if (ev->nesting.level > 0) {
|
|---|
| 557 | if (ev->nesting.hook_fn) {
|
|---|
| 558 | int ret2;
|
|---|
| 559 | ret2 = ev->nesting.hook_fn(ev,
|
|---|
| 560 | ev->nesting.hook_private,
|
|---|
| 561 | ev->nesting.level,
|
|---|
| 562 | false,
|
|---|
| 563 | (void *)&nesting_stack_ptr,
|
|---|
| 564 | location);
|
|---|
| 565 | if (ret2 != 0) {
|
|---|
| 566 | ret = ret2;
|
|---|
| 567 | goto done;
|
|---|
| 568 | }
|
|---|
| 569 | }
|
|---|
| 570 | }
|
|---|
| 571 |
|
|---|
| 572 | done:
|
|---|
| 573 | ev->nesting.level--;
|
|---|
| 574 | return ret;
|
|---|
| 575 | }
|
|---|
| 576 |
|
|---|
| 577 | /*
|
|---|
| 578 | return on failure or (with 0) if all fd events are removed
|
|---|
| 579 | */
|
|---|
| 580 | int tevent_common_loop_wait(struct tevent_context *ev,
|
|---|
| 581 | const char *location)
|
|---|
| 582 | {
|
|---|
| 583 | /*
|
|---|
| 584 | * loop as long as we have events pending
|
|---|
| 585 | */
|
|---|
| 586 | while (ev->fd_events ||
|
|---|
| 587 | ev->timer_events ||
|
|---|
| 588 | ev->immediate_events ||
|
|---|
| 589 | ev->signal_events) {
|
|---|
| 590 | int ret;
|
|---|
| 591 | ret = _tevent_loop_once(ev, location);
|
|---|
| 592 | if (ret != 0) {
|
|---|
| 593 | tevent_debug(ev, TEVENT_DEBUG_FATAL,
|
|---|
| 594 | "_tevent_loop_once() failed: %d - %s\n",
|
|---|
| 595 | ret, strerror(errno));
|
|---|
| 596 | return ret;
|
|---|
| 597 | }
|
|---|
| 598 | }
|
|---|
| 599 |
|
|---|
| 600 | tevent_debug(ev, TEVENT_DEBUG_WARNING,
|
|---|
| 601 | "tevent_common_loop_wait() out of events\n");
|
|---|
| 602 | return 0;
|
|---|
| 603 | }
|
|---|
| 604 |
|
|---|
| 605 | /*
|
|---|
| 606 | return on failure or (with 0) if all fd events are removed
|
|---|
| 607 | */
|
|---|
| 608 | int _tevent_loop_wait(struct tevent_context *ev, const char *location)
|
|---|
| 609 | {
|
|---|
| 610 | return ev->ops->loop_wait(ev, location);
|
|---|
| 611 | }
|
|---|