root/lib/tevent/tevent.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. tevent_register_backend
  2. tevent_set_default_backend
  3. tevent_backend_init
  4. tevent_backend_list
  5. tevent_common_context_destructor
  6. tevent_context_init_ops
  7. tevent_context_init_byname
  8. tevent_context_init
  9. _tevent_add_fd
  10. tevent_fd_set_close_fn
  11. tevent_fd_auto_close_fn
  12. tevent_fd_set_auto_close
  13. tevent_fd_get_flags
  14. tevent_fd_set_flags
  15. tevent_signal_support
  16. tevent_set_abort_fn
  17. tevent_abort
  18. _tevent_add_timer
  19. _tevent_create_immediate
  20. _tevent_schedule_immediate
  21. _tevent_add_signal
  22. tevent_loop_allow_nesting
  23. tevent_loop_set_nesting_hook
  24. tevent_abort_nesting
  25. _tevent_loop_once
  26. _tevent_loop_until
  27. tevent_common_loop_wait
  28. _tevent_loop_wait

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

/* [<][>][^][v][top][bottom][index][help] */