root/lib/common/mainloop.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. crm_trigger_prepare
  2. crm_trigger_check
  3. crm_trigger_dispatch
  4. crm_trigger_finalize
  5. mainloop_setup_trigger
  6. mainloop_trigger_complete
  7. mainloop_add_trigger
  8. mainloop_set_trigger
  9. mainloop_destroy_trigger
  10. crm_signal_dispatch
  11. mainloop_signal_handler
  12. crm_signal_handler
  13. mainloop_destroy_signal_entry
  14. mainloop_add_signal
  15. mainloop_destroy_signal
  16. mainloop_cleanup
  17. gio_read_socket
  18. gio_poll_destroy
  19. conv_prio_libqb2glib
  20. conv_libqb_prio2ratelimit
  21. gio_poll_dispatch_update
  22. gio_poll_dispatch_add
  23. gio_poll_dispatch_mod
  24. gio_poll_dispatch_del
  25. pick_ipc_type
  26. mainloop_add_ipc_server
  27. mainloop_add_ipc_server_with_prio
  28. mainloop_del_ipc_server
  29. mainloop_gio_callback
  30. mainloop_gio_destroy
  31. pcmk__add_mainloop_ipc
  32. mainloop_add_ipc_client
  33. mainloop_del_ipc_client
  34. mainloop_get_ipc_client
  35. mainloop_add_fd
  36. mainloop_del_fd
  37. mainloop_child_pid
  38. mainloop_child_name
  39. mainloop_child_timeout
  40. mainloop_child_userdata
  41. mainloop_clear_child_userdata
  42. child_free
  43. child_kill_helper
  44. child_timeout_callback
  45. child_waitpid
  46. child_death_dispatch
  47. child_signal_init
  48. mainloop_child_kill
  49. mainloop_child_add_with_flags
  50. mainloop_child_add
  51. mainloop_timer_cb
  52. mainloop_timer_running
  53. mainloop_timer_start
  54. mainloop_timer_stop
  55. mainloop_timer_set_period
  56. mainloop_timer_add
  57. mainloop_timer_del
  58. drain_timeout_cb
  59. pcmk_quit_main_loop
  60. pcmk_drain_main_loop
  61. crm_signal

   1 /*
   2  * Copyright 2004-2020 the Pacemaker project contributors
   3  *
   4  * The version control history for this file may have further details.
   5  *
   6  * This source code is licensed under the GNU Lesser General Public License
   7  * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
   8  */
   9 
  10 #include <crm_internal.h>
  11 
  12 #ifndef _GNU_SOURCE
  13 #  define _GNU_SOURCE
  14 #endif
  15 
  16 #include <stdlib.h>
  17 #include <string.h>
  18 #include <signal.h>
  19 #include <errno.h>
  20 
  21 #include <sys/wait.h>
  22 
  23 #include <crm/crm.h>
  24 #include <crm/common/xml.h>
  25 #include <crm/common/mainloop.h>
  26 #include <crm/common/ipc_internal.h>
  27 
  28 #include <qb/qbarray.h>
  29 
  30 struct mainloop_child_s {
  31     pid_t pid;
  32     char *desc;
  33     unsigned timerid;
  34     gboolean timeout;
  35     void *privatedata;
  36 
  37     enum mainloop_child_flags flags;
  38 
  39     /* Called when a process dies */
  40     void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode);
  41 };
  42 
  43 struct trigger_s {
  44     GSource source;
  45     gboolean running;
  46     gboolean trigger;
  47     void *user_data;
  48     guint id;
  49 
  50 };
  51 
  52 static gboolean
  53 crm_trigger_prepare(GSource * source, gint * timeout)
     /* [previous][next][first][last][top][bottom][index][help] */
  54 {
  55     crm_trigger_t *trig = (crm_trigger_t *) source;
  56 
  57     /* cluster-glue's FD and IPC related sources make use of
  58      * g_source_add_poll() but do not set a timeout in their prepare
  59      * functions
  60      *
  61      * This means mainloop's poll() will block until an event for one
  62      * of these sources occurs - any /other/ type of source, such as
  63      * this one or g_idle_*, that doesn't use g_source_add_poll() is
  64      * S-O-L and won't be processed until there is something fd-based
  65      * happens.
  66      *
  67      * Luckily the timeout we can set here affects all sources and
  68      * puts an upper limit on how long poll() can take.
  69      *
  70      * So unconditionally set a small-ish timeout, not too small that
  71      * we're in constant motion, which will act as an upper bound on
  72      * how long the signal handling might be delayed for.
  73      */
  74     *timeout = 500;             /* Timeout in ms */
  75 
  76     return trig->trigger;
  77 }
  78 
  79 static gboolean
  80 crm_trigger_check(GSource * source)
     /* [previous][next][first][last][top][bottom][index][help] */
  81 {
  82     crm_trigger_t *trig = (crm_trigger_t *) source;
  83 
  84     return trig->trigger;
  85 }
  86 
  87 static gboolean
  88 crm_trigger_dispatch(GSource * source, GSourceFunc callback, gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
  89 {
  90     int rc = TRUE;
  91     crm_trigger_t *trig = (crm_trigger_t *) source;
  92 
  93     if (trig->running) {
  94         /* Wait until the existing job is complete before starting the next one */
  95         return TRUE;
  96     }
  97     trig->trigger = FALSE;
  98 
  99     if (callback) {
 100         rc = callback(trig->user_data);
 101         if (rc < 0) {
 102             crm_trace("Trigger handler %p not yet complete", trig);
 103             trig->running = TRUE;
 104             rc = TRUE;
 105         }
 106     }
 107     return rc;
 108 }
 109 
 110 static void
 111 crm_trigger_finalize(GSource * source)
     /* [previous][next][first][last][top][bottom][index][help] */
 112 {
 113     crm_trace("Trigger %p destroyed", source);
 114 }
 115 
 116 static GSourceFuncs crm_trigger_funcs = {
 117     crm_trigger_prepare,
 118     crm_trigger_check,
 119     crm_trigger_dispatch,
 120     crm_trigger_finalize,
 121 };
 122 
 123 static crm_trigger_t *
 124 mainloop_setup_trigger(GSource * source, int priority, int (*dispatch) (gpointer user_data),
     /* [previous][next][first][last][top][bottom][index][help] */
 125                        gpointer userdata)
 126 {
 127     crm_trigger_t *trigger = NULL;
 128 
 129     trigger = (crm_trigger_t *) source;
 130 
 131     trigger->id = 0;
 132     trigger->trigger = FALSE;
 133     trigger->user_data = userdata;
 134 
 135     if (dispatch) {
 136         g_source_set_callback(source, dispatch, trigger, NULL);
 137     }
 138 
 139     g_source_set_priority(source, priority);
 140     g_source_set_can_recurse(source, FALSE);
 141 
 142     trigger->id = g_source_attach(source, NULL);
 143     return trigger;
 144 }
 145 
 146 void
 147 mainloop_trigger_complete(crm_trigger_t * trig)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 {
 149     crm_trace("Trigger handler %p complete", trig);
 150     trig->running = FALSE;
 151 }
 152 
 153 /* If dispatch returns:
 154  *  -1: Job running but not complete
 155  *   0: Remove the trigger from mainloop
 156  *   1: Leave the trigger in mainloop
 157  */
 158 crm_trigger_t *
 159 mainloop_add_trigger(int priority, int (*dispatch) (gpointer user_data), gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 160 {
 161     GSource *source = NULL;
 162 
 163     CRM_ASSERT(sizeof(crm_trigger_t) > sizeof(GSource));
 164     source = g_source_new(&crm_trigger_funcs, sizeof(crm_trigger_t));
 165     CRM_ASSERT(source != NULL);
 166 
 167     return mainloop_setup_trigger(source, priority, dispatch, userdata);
 168 }
 169 
 170 void
 171 mainloop_set_trigger(crm_trigger_t * source)
     /* [previous][next][first][last][top][bottom][index][help] */
 172 {
 173     if(source) {
 174         source->trigger = TRUE;
 175     }
 176 }
 177 
 178 gboolean
 179 mainloop_destroy_trigger(crm_trigger_t * source)
     /* [previous][next][first][last][top][bottom][index][help] */
 180 {
 181     GSource *gs = NULL;
 182 
 183     if(source == NULL) {
 184         return TRUE;
 185     }
 186 
 187     gs = (GSource *)source;
 188 
 189     g_source_destroy(gs); /* Remove from mainloop, ref_count-- */
 190     g_source_unref(gs); /* The caller no longer carries a reference to source
 191                          *
 192                          * At this point the source should be free'd,
 193                          * unless we're currently processing said
 194                          * source, in which case mainloop holds an
 195                          * additional reference and it will be free'd
 196                          * once our processing completes
 197                          */
 198     return TRUE;
 199 }
 200 
 201 // Define a custom glib source for signal handling
 202 
 203 // Data structure for custom glib source
 204 typedef struct signal_s {
 205     crm_trigger_t trigger;      // trigger that invoked source (must be first)
 206     void (*handler) (int sig);  // signal handler
 207     int signal;                 // signal that was received
 208 } crm_signal_t;
 209 
 210 // Table to associate signal handlers with signal numbers
 211 static crm_signal_t *crm_signals[NSIG];
 212 
 213 /*!
 214  * \internal
 215  * \brief Dispatch an event from custom glib source for signals
 216  *
 217  * Given an signal event, clear the event trigger and call any registered
 218  * signal handler.
 219  *
 220  * \param[in] source    glib source that triggered this dispatch
 221  * \param[in] callback  (ignored)
 222  * \param[in] userdata  (ignored)
 223  */
 224 static gboolean
 225 crm_signal_dispatch(GSource * source, GSourceFunc callback, gpointer userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
 226 {
 227     crm_signal_t *sig = (crm_signal_t *) source;
 228 
 229     if(sig->signal != SIGCHLD) {
 230         crm_notice("Caught '%s' signal "CRM_XS" %d (%s handler)",
 231                    strsignal(sig->signal), sig->signal,
 232                    (sig->handler? "invoking" : "no"));
 233     }
 234 
 235     sig->trigger.trigger = FALSE;
 236     if (sig->handler) {
 237         sig->handler(sig->signal);
 238     }
 239     return TRUE;
 240 }
 241 
 242 /*!
 243  * \internal
 244  * \brief Handle a signal by setting a trigger for signal source
 245  *
 246  * \param[in] sig  Signal number that was received
 247  *
 248  * \note This is the true signal handler for the mainloop signal source, and
 249  *       must be async-safe.
 250  */
 251 static void
 252 mainloop_signal_handler(int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 253 {
 254     if (sig > 0 && sig < NSIG && crm_signals[sig] != NULL) {
 255         mainloop_set_trigger((crm_trigger_t *) crm_signals[sig]);
 256     }
 257 }
 258 
 259 // Functions implementing our custom glib source for signal handling
 260 static GSourceFuncs crm_signal_funcs = {
 261     crm_trigger_prepare,
 262     crm_trigger_check,
 263     crm_signal_dispatch,
 264     crm_trigger_finalize,
 265 };
 266 
 267 /*!
 268  * \internal
 269  * \brief Set a true signal handler
 270  *
 271  * signal()-like interface to sigaction()
 272  *
 273  * \param[in] sig       Signal number to register handler for
 274  * \param[in] dispatch  Signal handler
 275  *
 276  * \return The previous value of the signal handler, or SIG_ERR on error
 277  * \note The dispatch function must be async-safe.
 278  */
 279 sighandler_t
 280 crm_signal_handler(int sig, sighandler_t dispatch)
     /* [previous][next][first][last][top][bottom][index][help] */
 281 {
 282     sigset_t mask;
 283     struct sigaction sa;
 284     struct sigaction old;
 285 
 286     if (sigemptyset(&mask) < 0) {
 287         crm_err("Could not set handler for signal %d: %s",
 288                 sig, pcmk_strerror(errno));
 289         return SIG_ERR;
 290     }
 291 
 292     memset(&sa, 0, sizeof(struct sigaction));
 293     sa.sa_handler = dispatch;
 294     sa.sa_flags = SA_RESTART;
 295     sa.sa_mask = mask;
 296 
 297     if (sigaction(sig, &sa, &old) < 0) {
 298         crm_err("Could not set handler for signal %d: %s",
 299                 sig, pcmk_strerror(errno));
 300         return SIG_ERR;
 301     }
 302     return old.sa_handler;
 303 }
 304 
 305 static void
 306 mainloop_destroy_signal_entry(int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 307 {
 308     crm_signal_t *tmp = crm_signals[sig];
 309 
 310     crm_signals[sig] = NULL;
 311 
 312     crm_trace("Destroying signal %d", sig);
 313     mainloop_destroy_trigger((crm_trigger_t *) tmp);
 314 }
 315 
 316 /*!
 317  * \internal
 318  * \brief Add a signal handler to a mainloop
 319  *
 320  * \param[in] sig       Signal number to handle
 321  * \param[in] dispatch  Signal handler function
 322  *
 323  * \note The true signal handler merely sets a mainloop trigger to call this
 324  *       dispatch function via the mainloop. Therefore, the dispatch function
 325  *       does not need to be async-safe.
 326  */
 327 gboolean
 328 mainloop_add_signal(int sig, void (*dispatch) (int sig))
     /* [previous][next][first][last][top][bottom][index][help] */
 329 {
 330     GSource *source = NULL;
 331     int priority = G_PRIORITY_HIGH - 1;
 332 
 333     if (sig == SIGTERM) {
 334         /* TERM is higher priority than other signals,
 335          *   signals are higher priority than other ipc.
 336          * Yes, minus: smaller is "higher"
 337          */
 338         priority--;
 339     }
 340 
 341     if (sig >= NSIG || sig < 0) {
 342         crm_err("Signal %d is out of range", sig);
 343         return FALSE;
 344 
 345     } else if (crm_signals[sig] != NULL && crm_signals[sig]->handler == dispatch) {
 346         crm_trace("Signal handler for %d is already installed", sig);
 347         return TRUE;
 348 
 349     } else if (crm_signals[sig] != NULL) {
 350         crm_err("Different signal handler for %d is already installed", sig);
 351         return FALSE;
 352     }
 353 
 354     CRM_ASSERT(sizeof(crm_signal_t) > sizeof(GSource));
 355     source = g_source_new(&crm_signal_funcs, sizeof(crm_signal_t));
 356 
 357     crm_signals[sig] = (crm_signal_t *) mainloop_setup_trigger(source, priority, NULL, NULL);
 358     CRM_ASSERT(crm_signals[sig] != NULL);
 359 
 360     crm_signals[sig]->handler = dispatch;
 361     crm_signals[sig]->signal = sig;
 362 
 363     if (crm_signal_handler(sig, mainloop_signal_handler) == SIG_ERR) {
 364         mainloop_destroy_signal_entry(sig);
 365         return FALSE;
 366     }
 367 #if 0
 368     /* If we want signals to interrupt mainloop's poll(), instead of waiting for
 369      * the timeout, then we should call siginterrupt() below
 370      *
 371      * For now, just enforce a low timeout
 372      */
 373     if (siginterrupt(sig, 1) < 0) {
 374         crm_perror(LOG_INFO, "Could not enable system call interruptions for signal %d", sig);
 375     }
 376 #endif
 377 
 378     return TRUE;
 379 }
 380 
 381 gboolean
 382 mainloop_destroy_signal(int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 383 {
 384     if (sig >= NSIG || sig < 0) {
 385         crm_err("Signal %d is out of range", sig);
 386         return FALSE;
 387 
 388     } else if (crm_signal_handler(sig, NULL) == SIG_ERR) {
 389         crm_perror(LOG_ERR, "Could not uninstall signal handler for signal %d", sig);
 390         return FALSE;
 391 
 392     } else if (crm_signals[sig] == NULL) {
 393         return TRUE;
 394     }
 395     mainloop_destroy_signal_entry(sig);
 396     return TRUE;
 397 }
 398 
 399 static qb_array_t *gio_map = NULL;
 400 
 401 void
 402 mainloop_cleanup(void) 
     /* [previous][next][first][last][top][bottom][index][help] */
 403 {
 404     if (gio_map) {
 405         qb_array_free(gio_map);
 406     }
 407 
 408     for (int sig = 0; sig < NSIG; ++sig) {
 409         mainloop_destroy_signal_entry(sig);
 410     }
 411 }
 412 
 413 /*
 414  * libqb...
 415  */
 416 struct gio_to_qb_poll {
 417     int32_t is_used;
 418     guint source;
 419     int32_t events;
 420     void *data;
 421     qb_ipcs_dispatch_fn_t fn;
 422     enum qb_loop_priority p;
 423 };
 424 
 425 static gboolean
 426 gio_read_socket(GIOChannel * gio, GIOCondition condition, gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 427 {
 428     struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
 429     gint fd = g_io_channel_unix_get_fd(gio);
 430 
 431     crm_trace("%p.%d %d", data, fd, condition);
 432 
 433     /* if this assert get's hit, then there is a race condition between
 434      * when we destroy a fd and when mainloop actually gives it up */
 435     CRM_ASSERT(adaptor->is_used > 0);
 436 
 437     return (adaptor->fn(fd, condition, adaptor->data) == 0);
 438 }
 439 
 440 static void
 441 gio_poll_destroy(gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 442 {
 443     struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
 444 
 445     adaptor->is_used--;
 446     CRM_ASSERT(adaptor->is_used >= 0);
 447 
 448     if (adaptor->is_used == 0) {
 449         crm_trace("Marking adaptor %p unused", adaptor);
 450         adaptor->source = 0;
 451     }
 452 }
 453 
 454 /*!
 455  * \internal
 456  * \brief Convert libqb's poll priority into GLib's one
 457  *
 458  * \param[in] prio  libqb's poll priority (#QB_LOOP_MED assumed as fallback)
 459  *
 460  * \return  best matching GLib's priority
 461  */
 462 static gint
 463 conv_prio_libqb2glib(enum qb_loop_priority prio)
     /* [previous][next][first][last][top][bottom][index][help] */
 464 {
 465     gint ret = G_PRIORITY_DEFAULT;
 466     switch (prio) {
 467         case QB_LOOP_LOW:
 468             ret = G_PRIORITY_LOW;
 469             break;
 470         case QB_LOOP_HIGH:
 471             ret = G_PRIORITY_HIGH;
 472             break;
 473         default:
 474             crm_trace("Invalid libqb's loop priority %d, assuming QB_LOOP_MED",
 475                       prio);
 476             /* fall-through */
 477         case QB_LOOP_MED:
 478             break;
 479     }
 480     return ret;
 481 }
 482 
 483 /*!
 484  * \internal
 485  * \brief Convert libqb's poll priority to rate limiting spec
 486  *
 487  * \param[in] prio  libqb's poll priority (#QB_LOOP_MED assumed as fallback)
 488  *
 489  * \return  best matching rate limiting spec
 490  */
 491 static enum qb_ipcs_rate_limit
 492 conv_libqb_prio2ratelimit(enum qb_loop_priority prio)
     /* [previous][next][first][last][top][bottom][index][help] */
 493 {
 494     /* this is an inversion of what libqb's qb_ipcs_request_rate_limit does */
 495     enum qb_ipcs_rate_limit ret = QB_IPCS_RATE_NORMAL;
 496     switch (prio) {
 497         case QB_LOOP_LOW:
 498             ret = QB_IPCS_RATE_SLOW;
 499             break;
 500         case QB_LOOP_HIGH:
 501             ret = QB_IPCS_RATE_FAST;
 502             break;
 503         default:
 504             crm_trace("Invalid libqb's loop priority %d, assuming QB_LOOP_MED",
 505                       prio);
 506             /* fall-through */
 507         case QB_LOOP_MED:
 508             break;
 509     }
 510     return ret;
 511 }
 512 
 513 static int32_t
 514 gio_poll_dispatch_update(enum qb_loop_priority p, int32_t fd, int32_t evts,
     /* [previous][next][first][last][top][bottom][index][help] */
 515                          void *data, qb_ipcs_dispatch_fn_t fn, int32_t add)
 516 {
 517     struct gio_to_qb_poll *adaptor;
 518     GIOChannel *channel;
 519     int32_t res = 0;
 520 
 521     res = qb_array_index(gio_map, fd, (void **)&adaptor);
 522     if (res < 0) {
 523         crm_err("Array lookup failed for fd=%d: %d", fd, res);
 524         return res;
 525     }
 526 
 527     crm_trace("Adding fd=%d to mainloop as adaptor %p", fd, adaptor);
 528 
 529     if (add && adaptor->source) {
 530         crm_err("Adaptor for descriptor %d is still in-use", fd);
 531         return -EEXIST;
 532     }
 533     if (!add && !adaptor->is_used) {
 534         crm_err("Adaptor for descriptor %d is not in-use", fd);
 535         return -ENOENT;
 536     }
 537 
 538     /* channel is created with ref_count = 1 */
 539     channel = g_io_channel_unix_new(fd);
 540     if (!channel) {
 541         crm_err("No memory left to add fd=%d", fd);
 542         return -ENOMEM;
 543     }
 544 
 545     if (adaptor->source) {
 546         g_source_remove(adaptor->source);
 547         adaptor->source = 0;
 548     }
 549 
 550     /* Because unlike the poll() API, glib doesn't tell us about HUPs by default */
 551     evts |= (G_IO_HUP | G_IO_NVAL | G_IO_ERR);
 552 
 553     adaptor->fn = fn;
 554     adaptor->events = evts;
 555     adaptor->data = data;
 556     adaptor->p = p;
 557     adaptor->is_used++;
 558     adaptor->source =
 559         g_io_add_watch_full(channel, conv_prio_libqb2glib(p), evts,
 560                             gio_read_socket, adaptor, gio_poll_destroy);
 561 
 562     /* Now that mainloop now holds a reference to channel,
 563      * thanks to g_io_add_watch_full(), drop ours from g_io_channel_unix_new().
 564      *
 565      * This means that channel will be free'd by:
 566      * g_main_context_dispatch()
 567      *  -> g_source_destroy_internal()
 568      *      -> g_source_callback_unref()
 569      * shortly after gio_poll_destroy() completes
 570      */
 571     g_io_channel_unref(channel);
 572 
 573     crm_trace("Added to mainloop with gsource id=%d", adaptor->source);
 574     if (adaptor->source > 0) {
 575         return 0;
 576     }
 577 
 578     return -EINVAL;
 579 }
 580 
 581 static int32_t
 582 gio_poll_dispatch_add(enum qb_loop_priority p, int32_t fd, int32_t evts,
     /* [previous][next][first][last][top][bottom][index][help] */
 583                       void *data, qb_ipcs_dispatch_fn_t fn)
 584 {
 585     return gio_poll_dispatch_update(p, fd, evts, data, fn, QB_TRUE);
 586 }
 587 
 588 static int32_t
 589 gio_poll_dispatch_mod(enum qb_loop_priority p, int32_t fd, int32_t evts,
     /* [previous][next][first][last][top][bottom][index][help] */
 590                       void *data, qb_ipcs_dispatch_fn_t fn)
 591 {
 592     return gio_poll_dispatch_update(p, fd, evts, data, fn, QB_FALSE);
 593 }
 594 
 595 static int32_t
 596 gio_poll_dispatch_del(int32_t fd)
     /* [previous][next][first][last][top][bottom][index][help] */
 597 {
 598     struct gio_to_qb_poll *adaptor;
 599 
 600     crm_trace("Looking for fd=%d", fd);
 601     if (qb_array_index(gio_map, fd, (void **)&adaptor) == 0) {
 602         if (adaptor->source) {
 603             g_source_remove(adaptor->source);
 604             adaptor->source = 0;
 605         }
 606     }
 607     return 0;
 608 }
 609 
 610 struct qb_ipcs_poll_handlers gio_poll_funcs = {
 611     .job_add = NULL,
 612     .dispatch_add = gio_poll_dispatch_add,
 613     .dispatch_mod = gio_poll_dispatch_mod,
 614     .dispatch_del = gio_poll_dispatch_del,
 615 };
 616 
 617 static enum qb_ipc_type
 618 pick_ipc_type(enum qb_ipc_type requested)
     /* [previous][next][first][last][top][bottom][index][help] */
 619 {
 620     const char *env = getenv("PCMK_ipc_type");
 621 
 622     if (env && strcmp("shared-mem", env) == 0) {
 623         return QB_IPC_SHM;
 624     } else if (env && strcmp("socket", env) == 0) {
 625         return QB_IPC_SOCKET;
 626     } else if (env && strcmp("posix", env) == 0) {
 627         return QB_IPC_POSIX_MQ;
 628     } else if (env && strcmp("sysv", env) == 0) {
 629         return QB_IPC_SYSV_MQ;
 630     } else if (requested == QB_IPC_NATIVE) {
 631         /* We prefer shared memory because the server never blocks on
 632          * send.  If part of a message fits into the socket, libqb
 633          * needs to block until the remainder can be sent also.
 634          * Otherwise the client will wait forever for the remaining
 635          * bytes.
 636          */
 637         return QB_IPC_SHM;
 638     }
 639     return requested;
 640 }
 641 
 642 qb_ipcs_service_t *
 643 mainloop_add_ipc_server(const char *name, enum qb_ipc_type type,
     /* [previous][next][first][last][top][bottom][index][help] */
 644                         struct qb_ipcs_service_handlers *callbacks)
 645 {
 646     return mainloop_add_ipc_server_with_prio(name, type, callbacks, QB_LOOP_MED);
 647 }
 648 
 649 qb_ipcs_service_t *
 650 mainloop_add_ipc_server_with_prio(const char *name, enum qb_ipc_type type,
     /* [previous][next][first][last][top][bottom][index][help] */
 651                                   struct qb_ipcs_service_handlers *callbacks,
 652                                   enum qb_loop_priority prio)
 653 {
 654     int rc = 0;
 655     qb_ipcs_service_t *server = NULL;
 656 
 657     if (gio_map == NULL) {
 658         gio_map = qb_array_create_2(64, sizeof(struct gio_to_qb_poll), 1);
 659     }
 660 
 661     server = qb_ipcs_create(name, 0, pick_ipc_type(type), callbacks);
 662 
 663     if (server == NULL) {
 664         crm_err("Could not create %s IPC server: %s (%d)", name, pcmk_strerror(rc), rc);
 665         return NULL;
 666     }
 667 
 668     if (prio != QB_LOOP_MED) {
 669         qb_ipcs_request_rate_limit(server, conv_libqb_prio2ratelimit(prio));
 670     }
 671 
 672 #ifdef HAVE_IPCS_GET_BUFFER_SIZE
 673     /* All clients should use at least ipc_buffer_max as their buffer size */
 674     qb_ipcs_enforce_buffer_size(server, crm_ipc_default_buffer_size());
 675 #endif
 676 
 677     qb_ipcs_poll_handlers_set(server, &gio_poll_funcs);
 678 
 679     rc = qb_ipcs_run(server);
 680     if (rc < 0) {
 681         crm_err("Could not start %s IPC server: %s (%d)", name, pcmk_strerror(rc), rc);
 682         return NULL;
 683     }
 684 
 685     return server;
 686 }
 687 
 688 void
 689 mainloop_del_ipc_server(qb_ipcs_service_t * server)
     /* [previous][next][first][last][top][bottom][index][help] */
 690 {
 691     if (server) {
 692         qb_ipcs_destroy(server);
 693     }
 694 }
 695 
 696 struct mainloop_io_s {
 697     char *name;
 698     void *userdata;
 699 
 700     int fd;
 701     guint source;
 702     crm_ipc_t *ipc;
 703     GIOChannel *channel;
 704 
 705     int (*dispatch_fn_ipc) (const char *buffer, ssize_t length, gpointer userdata);
 706     int (*dispatch_fn_io) (gpointer userdata);
 707     void (*destroy_fn) (gpointer userdata);
 708 
 709 };
 710 
 711 static gboolean
 712 mainloop_gio_callback(GIOChannel * gio, GIOCondition condition, gpointer data)
     /* [previous][next][first][last][top][bottom][index][help] */
 713 {
 714     gboolean keep = TRUE;
 715     mainloop_io_t *client = data;
 716 
 717     CRM_ASSERT(client->fd == g_io_channel_unix_get_fd(gio));
 718 
 719     if (condition & G_IO_IN) {
 720         if (client->ipc) {
 721             long rc = 0;
 722             int max = 10;
 723 
 724             do {
 725                 rc = crm_ipc_read(client->ipc);
 726                 if (rc <= 0) {
 727                     crm_trace("Message acquisition from %s[%p] failed: %s (%ld)",
 728                               client->name, client, pcmk_strerror(rc), rc);
 729 
 730                 } else if (client->dispatch_fn_ipc) {
 731                     const char *buffer = crm_ipc_buffer(client->ipc);
 732 
 733                     crm_trace("New message from %s[%p] = %ld (I/O condition=%d)", client->name, client, rc, condition);
 734                     if (client->dispatch_fn_ipc(buffer, rc, client->userdata) < 0) {
 735                         crm_trace("Connection to %s no longer required", client->name);
 736                         keep = FALSE;
 737                     }
 738                 }
 739 
 740             } while (keep && rc > 0 && --max > 0);
 741 
 742         } else {
 743             crm_trace("New message from %s[%p] %u", client->name, client, condition);
 744             if (client->dispatch_fn_io) {
 745                 if (client->dispatch_fn_io(client->userdata) < 0) {
 746                     crm_trace("Connection to %s no longer required", client->name);
 747                     keep = FALSE;
 748                 }
 749             }
 750         }
 751     }
 752 
 753     if (client->ipc && crm_ipc_connected(client->ipc) == FALSE) {
 754         crm_err("Connection to %s closed " CRM_XS "client=%p condition=%d",
 755                 client->name, client, condition);
 756         keep = FALSE;
 757 
 758     } else if (condition & (G_IO_HUP | G_IO_NVAL | G_IO_ERR)) {
 759         crm_trace("The connection %s[%p] has been closed (I/O condition=%d)",
 760                   client->name, client, condition);
 761         keep = FALSE;
 762 
 763     } else if ((condition & G_IO_IN) == 0) {
 764         /*
 765            #define      GLIB_SYSDEF_POLLIN     =1
 766            #define      GLIB_SYSDEF_POLLPRI    =2
 767            #define      GLIB_SYSDEF_POLLOUT    =4
 768            #define      GLIB_SYSDEF_POLLERR    =8
 769            #define      GLIB_SYSDEF_POLLHUP    =16
 770            #define      GLIB_SYSDEF_POLLNVAL   =32
 771 
 772            typedef enum
 773            {
 774            G_IO_IN      GLIB_SYSDEF_POLLIN,
 775            G_IO_OUT     GLIB_SYSDEF_POLLOUT,
 776            G_IO_PRI     GLIB_SYSDEF_POLLPRI,
 777            G_IO_ERR     GLIB_SYSDEF_POLLERR,
 778            G_IO_HUP     GLIB_SYSDEF_POLLHUP,
 779            G_IO_NVAL    GLIB_SYSDEF_POLLNVAL
 780            } GIOCondition;
 781 
 782            A bitwise combination representing a condition to watch for on an event source.
 783 
 784            G_IO_IN      There is data to read.
 785            G_IO_OUT     Data can be written (without blocking).
 786            G_IO_PRI     There is urgent data to read.
 787            G_IO_ERR     Error condition.
 788            G_IO_HUP     Hung up (the connection has been broken, usually for pipes and sockets).
 789            G_IO_NVAL    Invalid request. The file descriptor is not open.
 790          */
 791         crm_err("Strange condition: %d", condition);
 792     }
 793 
 794     /* keep == FALSE results in mainloop_gio_destroy() being called
 795      * just before the source is removed from mainloop
 796      */
 797     return keep;
 798 }
 799 
 800 static void
 801 mainloop_gio_destroy(gpointer c)
     /* [previous][next][first][last][top][bottom][index][help] */
 802 {
 803     mainloop_io_t *client = c;
 804     char *c_name = strdup(client->name);
 805 
 806     /* client->source is valid but about to be destroyed (ref_count == 0) in gmain.c
 807      * client->channel will still have ref_count > 0... should be == 1
 808      */
 809     crm_trace("Destroying client %s[%p]", c_name, c);
 810 
 811     if (client->ipc) {
 812         crm_ipc_close(client->ipc);
 813     }
 814 
 815     if (client->destroy_fn) {
 816         void (*destroy_fn) (gpointer userdata) = client->destroy_fn;
 817 
 818         client->destroy_fn = NULL;
 819         destroy_fn(client->userdata);
 820     }
 821 
 822     if (client->ipc) {
 823         crm_ipc_t *ipc = client->ipc;
 824 
 825         client->ipc = NULL;
 826         crm_ipc_destroy(ipc);
 827     }
 828 
 829     crm_trace("Destroyed client %s[%p]", c_name, c);
 830 
 831     free(client->name); client->name = NULL;
 832     free(client);
 833 
 834     free(c_name);
 835 }
 836 
 837 /*!
 838  * \brief Connect to IPC and add it as a main loop source
 839  *
 840  * \param[in]  ipc        IPC connection to add
 841  * \param[in]  priority   Event source priority to use for connection
 842  * \param[in]  userdata   Data to register with callbacks
 843  * \param[in]  callbacks  Dispatch and destroy callbacks for connection
 844  * \param[out] source     Newly allocated event source
 845  *
 846  * \return Standard Pacemaker return code
 847  *
 848  * \note On failure, the caller is still responsible for ipc. On success, the
 849  *       caller should call mainloop_del_ipc_client() when source is no longer
 850  *       needed, which will lead to the disconnection of the IPC later in the
 851  *       main loop if it is connected. However the IPC disconnects,
 852  *       mainloop_gio_destroy() will free ipc and source after calling the
 853  *       destroy callback.
 854  */
 855 int
 856 pcmk__add_mainloop_ipc(crm_ipc_t *ipc, int priority, void *userdata,
     /* [previous][next][first][last][top][bottom][index][help] */
 857                        struct ipc_client_callbacks *callbacks,
 858                        mainloop_io_t **source)
 859 {
 860     CRM_CHECK((ipc != NULL) && (callbacks != NULL), return EINVAL);
 861 
 862     if (!crm_ipc_connect(ipc)) {
 863         return ENOTCONN;
 864     }
 865     *source = mainloop_add_fd(crm_ipc_name(ipc), priority, crm_ipc_get_fd(ipc),
 866                               userdata, NULL);
 867     if (*source == NULL) {
 868         int rc = errno;
 869 
 870         crm_ipc_close(ipc);
 871         return rc;
 872     }
 873     (*source)->ipc = ipc;
 874     (*source)->destroy_fn = callbacks->destroy;
 875     (*source)->dispatch_fn_ipc = callbacks->dispatch;
 876     return pcmk_rc_ok;
 877 }
 878 
 879 mainloop_io_t *
 880 mainloop_add_ipc_client(const char *name, int priority, size_t max_size,
     /* [previous][next][first][last][top][bottom][index][help] */
 881                         void *userdata, struct ipc_client_callbacks *callbacks)
 882 {
 883     crm_ipc_t *ipc = crm_ipc_new(name, max_size);
 884     mainloop_io_t *source = NULL;
 885     int rc = pcmk__add_mainloop_ipc(ipc, priority, userdata, callbacks,
 886                                     &source);
 887 
 888     if (rc != pcmk_rc_ok) {
 889         if (crm_log_level == LOG_STDOUT) {
 890             fprintf(stderr, "Connection to %s failed: %s",
 891                     name, pcmk_rc_str(rc));
 892         }
 893         crm_ipc_destroy(ipc);
 894         return NULL;
 895     }
 896     return source;
 897 }
 898 
 899 void
 900 mainloop_del_ipc_client(mainloop_io_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
 901 {
 902     mainloop_del_fd(client);
 903 }
 904 
 905 crm_ipc_t *
 906 mainloop_get_ipc_client(mainloop_io_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
 907 {
 908     if (client) {
 909         return client->ipc;
 910     }
 911     return NULL;
 912 }
 913 
 914 mainloop_io_t *
 915 mainloop_add_fd(const char *name, int priority, int fd, void *userdata,
     /* [previous][next][first][last][top][bottom][index][help] */
 916                 struct mainloop_fd_callbacks * callbacks)
 917 {
 918     mainloop_io_t *client = NULL;
 919 
 920     if (fd >= 0) {
 921         client = calloc(1, sizeof(mainloop_io_t));
 922         if (client == NULL) {
 923             return NULL;
 924         }
 925         client->name = strdup(name);
 926         client->userdata = userdata;
 927 
 928         if (callbacks) {
 929             client->destroy_fn = callbacks->destroy;
 930             client->dispatch_fn_io = callbacks->dispatch;
 931         }
 932 
 933         client->fd = fd;
 934         client->channel = g_io_channel_unix_new(fd);
 935         client->source =
 936             g_io_add_watch_full(client->channel, priority,
 937                                 (G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR), mainloop_gio_callback,
 938                                 client, mainloop_gio_destroy);
 939 
 940         /* Now that mainloop now holds a reference to channel,
 941          * thanks to g_io_add_watch_full(), drop ours from g_io_channel_unix_new().
 942          *
 943          * This means that channel will be free'd by:
 944          * g_main_context_dispatch() or g_source_remove()
 945          *  -> g_source_destroy_internal()
 946          *      -> g_source_callback_unref()
 947          * shortly after mainloop_gio_destroy() completes
 948          */
 949         g_io_channel_unref(client->channel);
 950         crm_trace("Added connection %d for %s[%p].%d", client->source, client->name, client, fd);
 951     } else {
 952         errno = EINVAL;
 953     }
 954 
 955     return client;
 956 }
 957 
 958 void
 959 mainloop_del_fd(mainloop_io_t * client)
     /* [previous][next][first][last][top][bottom][index][help] */
 960 {
 961     if (client != NULL) {
 962         crm_trace("Removing client %s[%p]", client->name, client);
 963         if (client->source) {
 964             /* Results in mainloop_gio_destroy() being called just
 965              * before the source is removed from mainloop
 966              */
 967             g_source_remove(client->source);
 968         }
 969     }
 970 }
 971 
 972 static GListPtr child_list = NULL;
 973 
 974 pid_t
 975 mainloop_child_pid(mainloop_child_t * child)
     /* [previous][next][first][last][top][bottom][index][help] */
 976 {
 977     return child->pid;
 978 }
 979 
 980 const char *
 981 mainloop_child_name(mainloop_child_t * child)
     /* [previous][next][first][last][top][bottom][index][help] */
 982 {
 983     return child->desc;
 984 }
 985 
 986 int
 987 mainloop_child_timeout(mainloop_child_t * child)
     /* [previous][next][first][last][top][bottom][index][help] */
 988 {
 989     return child->timeout;
 990 }
 991 
 992 void *
 993 mainloop_child_userdata(mainloop_child_t * child)
     /* [previous][next][first][last][top][bottom][index][help] */
 994 {
 995     return child->privatedata;
 996 }
 997 
 998 void
 999 mainloop_clear_child_userdata(mainloop_child_t * child)
     /* [previous][next][first][last][top][bottom][index][help] */
1000 {
1001     child->privatedata = NULL;
1002 }
1003 
1004 /* good function name */
1005 static void
1006 child_free(mainloop_child_t *child)
     /* [previous][next][first][last][top][bottom][index][help] */
1007 {
1008     if (child->timerid != 0) {
1009         crm_trace("Removing timer %d", child->timerid);
1010         g_source_remove(child->timerid);
1011         child->timerid = 0;
1012     }
1013     free(child->desc);
1014     free(child);
1015 }
1016 
1017 /* terrible function name */
1018 static int
1019 child_kill_helper(mainloop_child_t *child)
     /* [previous][next][first][last][top][bottom][index][help] */
1020 {
1021     int rc;
1022     if (child->flags & mainloop_leave_pid_group) {
1023         crm_debug("Kill pid %d only. leave group intact.", child->pid);
1024         rc = kill(child->pid, SIGKILL);
1025     } else {
1026         crm_debug("Kill pid %d's group", child->pid);
1027         rc = kill(-child->pid, SIGKILL);
1028     }
1029 
1030     if (rc < 0) {
1031         if (errno != ESRCH) {
1032             crm_perror(LOG_ERR, "kill(%d, KILL) failed", child->pid);
1033         }
1034         return -errno;
1035     }
1036     return 0;
1037 }
1038 
1039 static gboolean
1040 child_timeout_callback(gpointer p)
     /* [previous][next][first][last][top][bottom][index][help] */
1041 {
1042     mainloop_child_t *child = p;
1043     int rc = 0;
1044 
1045     child->timerid = 0;
1046     if (child->timeout) {
1047         crm_crit("%s process (PID %d) will not die!", child->desc, (int)child->pid);
1048         return FALSE;
1049     }
1050 
1051     rc = child_kill_helper(child);
1052     if (rc == -ESRCH) {
1053         /* Nothing left to do. pid doesn't exist */
1054         return FALSE;
1055     }
1056 
1057     child->timeout = TRUE;
1058     crm_warn("%s process (PID %d) timed out", child->desc, (int)child->pid);
1059 
1060     child->timerid = g_timeout_add(5000, child_timeout_callback, child);
1061     return FALSE;
1062 }
1063 
1064 static bool
1065 child_waitpid(mainloop_child_t *child, int flags)
     /* [previous][next][first][last][top][bottom][index][help] */
1066 {
1067     int rc = 0;
1068     int core = 0;
1069     int signo = 0;
1070     int status = 0;
1071     int exitcode = 0;
1072     bool callback_needed = true;
1073 
1074     rc = waitpid(child->pid, &status, flags);
1075     if (rc == 0) { // WNOHANG in flags, and child status is not available
1076         crm_trace("Child process %d (%s) still active",
1077                   child->pid, child->desc);
1078         callback_needed = false;
1079 
1080     } else if (rc != child->pid) {
1081         /* According to POSIX, possible conditions:
1082          * - child->pid was non-positive (process group or any child),
1083          *   and rc is specific child
1084          * - errno ECHILD (pid does not exist or is not child)
1085          * - errno EINVAL (invalid flags)
1086          * - errno EINTR (caller interrupted by signal)
1087          *
1088          * @TODO Handle these cases more specifically.
1089          */
1090         signo = SIGCHLD;
1091         exitcode = 1;
1092         crm_notice("Wait for child process %d (%s) interrupted: %s",
1093                    child->pid, child->desc, pcmk_strerror(errno));
1094 
1095     } else if (WIFEXITED(status)) {
1096         exitcode = WEXITSTATUS(status);
1097         crm_trace("Child process %d (%s) exited with status %d",
1098                   child->pid, child->desc, exitcode);
1099 
1100     } else if (WIFSIGNALED(status)) {
1101         signo = WTERMSIG(status);
1102         crm_trace("Child process %d (%s) exited with signal %d (%s)",
1103                   child->pid, child->desc, signo, strsignal(signo));
1104 
1105 #ifdef WCOREDUMP // AIX, SunOS, maybe others
1106     } else if (WCOREDUMP(status)) {
1107         core = 1;
1108         crm_err("Child process %d (%s) dumped core",
1109                 child->pid, child->desc);
1110 #endif
1111 
1112     } else { // flags must contain WUNTRACED and/or WCONTINUED to reach this
1113         crm_trace("Child process %d (%s) stopped or continued",
1114                   child->pid, child->desc);
1115         callback_needed = false;
1116     }
1117 
1118     if (callback_needed && child->callback) {
1119         child->callback(child, child->pid, core, signo, exitcode);
1120     }
1121     return callback_needed;
1122 }
1123 
1124 static void
1125 child_death_dispatch(int signal)
     /* [previous][next][first][last][top][bottom][index][help] */
1126 {
1127     for (GList *iter = child_list; iter; ) {
1128         GList *saved = iter;
1129         mainloop_child_t *child = iter->data;
1130 
1131         iter = iter->next;
1132         if (child_waitpid(child, WNOHANG)) {
1133             crm_trace("Removing completed process %d from child list",
1134                       child->pid);
1135             child_list = g_list_remove_link(child_list, saved);
1136             g_list_free(saved);
1137             child_free(child);
1138         }
1139     }
1140 }
1141 
1142 static gboolean
1143 child_signal_init(gpointer p)
     /* [previous][next][first][last][top][bottom][index][help] */
1144 {
1145     crm_trace("Installed SIGCHLD handler");
1146     /* Do NOT use g_child_watch_add() and friends, they rely on pthreads */
1147     mainloop_add_signal(SIGCHLD, child_death_dispatch);
1148 
1149     /* In case they terminated before the signal handler was installed */
1150     child_death_dispatch(SIGCHLD);
1151     return FALSE;
1152 }
1153 
1154 gboolean
1155 mainloop_child_kill(pid_t pid)
     /* [previous][next][first][last][top][bottom][index][help] */
1156 {
1157     GListPtr iter;
1158     mainloop_child_t *child = NULL;
1159     mainloop_child_t *match = NULL;
1160     /* It is impossible to block SIGKILL, this allows us to
1161      * call waitpid without WNOHANG flag.*/
1162     int waitflags = 0, rc = 0;
1163 
1164     for (iter = child_list; iter != NULL && match == NULL; iter = iter->next) {
1165         child = iter->data;
1166         if (pid == child->pid) {
1167             match = child;
1168         }
1169     }
1170 
1171     if (match == NULL) {
1172         return FALSE;
1173     }
1174 
1175     rc = child_kill_helper(match);
1176     if(rc == -ESRCH) {
1177         /* It's gone, but hasn't shown up in waitpid() yet. Wait until we get
1178          * SIGCHLD and let handler clean it up as normal (so we get the correct
1179          * return code/status). The blocking alternative would be to call
1180          * child_waitpid(match, 0).
1181          */
1182         crm_trace("Waiting for signal that child process %d completed",
1183                   match->pid);
1184         return TRUE;
1185 
1186     } else if(rc != 0) {
1187         /* If KILL for some other reason set the WNOHANG flag since we
1188          * can't be certain what happened.
1189          */
1190         waitflags = WNOHANG;
1191     }
1192 
1193     if (!child_waitpid(match, waitflags)) {
1194         /* not much we can do if this occurs */
1195         return FALSE;
1196     }
1197 
1198     child_list = g_list_remove(child_list, match);
1199     child_free(match);
1200     return TRUE;
1201 }
1202 
1203 /* Create/Log a new tracked process
1204  * To track a process group, use -pid
1205  *
1206  * @TODO Using a non-positive pid (i.e. any child, or process group) would
1207  *       likely not be useful since we will free the child after the first
1208  *       completed process.
1209  */
1210 void
1211 mainloop_child_add_with_flags(pid_t pid, int timeout, const char *desc, void *privatedata, enum mainloop_child_flags flags, 
     /* [previous][next][first][last][top][bottom][index][help] */
1212                    void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode))
1213 {
1214     static bool need_init = TRUE;
1215     mainloop_child_t *child = g_new(mainloop_child_t, 1);
1216 
1217     child->pid = pid;
1218     child->timerid = 0;
1219     child->timeout = FALSE;
1220     child->privatedata = privatedata;
1221     child->callback = callback;
1222     child->flags = flags;
1223 
1224     if(desc) {
1225         child->desc = strdup(desc);
1226     }
1227 
1228     if (timeout) {
1229         child->timerid = g_timeout_add(timeout, child_timeout_callback, child);
1230     }
1231 
1232     child_list = g_list_append(child_list, child);
1233 
1234     if(need_init) {
1235         need_init = FALSE;
1236         /* SIGCHLD processing has to be invoked from mainloop.
1237          * We do not want it to be possible to both add a child pid
1238          * to mainloop, and have the pid's exit callback invoked within
1239          * the same callstack. */
1240         g_timeout_add(1, child_signal_init, NULL);
1241     }
1242 }
1243 
1244 void
1245 mainloop_child_add(pid_t pid, int timeout, const char *desc, void *privatedata,
     /* [previous][next][first][last][top][bottom][index][help] */
1246                    void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode))
1247 {
1248     mainloop_child_add_with_flags(pid, timeout, desc, privatedata, 0, callback);
1249 }
1250 
1251 struct mainloop_timer_s {
1252         guint id;
1253         guint period_ms;
1254         bool repeat;
1255         char *name;
1256         GSourceFunc cb;
1257         void *userdata;
1258 };
1259 
1260 static gboolean
1261 mainloop_timer_cb(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
1262 {
1263     int id = 0;
1264     bool repeat = FALSE;
1265     struct mainloop_timer_s *t = user_data;
1266 
1267     CRM_ASSERT(t != NULL);
1268 
1269     id = t->id;
1270     t->id = 0; /* Ensure it's unset during callbacks so that
1271                 * mainloop_timer_running() works as expected
1272                 */
1273 
1274     if(t->cb) {
1275         crm_trace("Invoking callbacks for timer %s", t->name);
1276         repeat = t->repeat;
1277         if(t->cb(t->userdata) == FALSE) {
1278             crm_trace("Timer %s complete", t->name);
1279             repeat = FALSE;
1280         }
1281     }
1282 
1283     if(repeat) {
1284         /* Restore if repeating */
1285         t->id = id;
1286     }
1287 
1288     return repeat;
1289 }
1290 
1291 bool
1292 mainloop_timer_running(mainloop_timer_t *t)
     /* [previous][next][first][last][top][bottom][index][help] */
1293 {
1294     if(t && t->id != 0) {
1295         return TRUE;
1296     }
1297     return FALSE;
1298 }
1299 
1300 void
1301 mainloop_timer_start(mainloop_timer_t *t)
     /* [previous][next][first][last][top][bottom][index][help] */
1302 {
1303     mainloop_timer_stop(t);
1304     if(t && t->period_ms > 0) {
1305         crm_trace("Starting timer %s", t->name);
1306         t->id = g_timeout_add(t->period_ms, mainloop_timer_cb, t);
1307     }
1308 }
1309 
1310 void
1311 mainloop_timer_stop(mainloop_timer_t *t)
     /* [previous][next][first][last][top][bottom][index][help] */
1312 {
1313     if(t && t->id != 0) {
1314         crm_trace("Stopping timer %s", t->name);
1315         g_source_remove(t->id);
1316         t->id = 0;
1317     }
1318 }
1319 
1320 guint
1321 mainloop_timer_set_period(mainloop_timer_t *t, guint period_ms)
     /* [previous][next][first][last][top][bottom][index][help] */
1322 {
1323     guint last = 0;
1324 
1325     if(t) {
1326         last = t->period_ms;
1327         t->period_ms = period_ms;
1328     }
1329 
1330     if(t && t->id != 0 && last != t->period_ms) {
1331         mainloop_timer_start(t);
1332     }
1333     return last;
1334 }
1335 
1336 mainloop_timer_t *
1337 mainloop_timer_add(const char *name, guint period_ms, bool repeat, GSourceFunc cb, void *userdata)
     /* [previous][next][first][last][top][bottom][index][help] */
1338 {
1339     mainloop_timer_t *t = calloc(1, sizeof(mainloop_timer_t));
1340 
1341     if(t) {
1342         if(name) {
1343             t->name = crm_strdup_printf("%s-%u-%d", name, period_ms, repeat);
1344         } else {
1345             t->name = crm_strdup_printf("%p-%u-%d", t, period_ms, repeat);
1346         }
1347         t->id = 0;
1348         t->period_ms = period_ms;
1349         t->repeat = repeat;
1350         t->cb = cb;
1351         t->userdata = userdata;
1352         crm_trace("Created timer %s with %p %p", t->name, userdata, t->userdata);
1353     }
1354     return t;
1355 }
1356 
1357 void
1358 mainloop_timer_del(mainloop_timer_t *t)
     /* [previous][next][first][last][top][bottom][index][help] */
1359 {
1360     if(t) {
1361         crm_trace("Destroying timer %s", t->name);
1362         mainloop_timer_stop(t);
1363         free(t->name);
1364         free(t);
1365     }
1366 }
1367 
1368 /*
1369  * Helpers to make sure certain events aren't lost at shutdown
1370  */
1371 
1372 static gboolean
1373 drain_timeout_cb(gpointer user_data)
     /* [previous][next][first][last][top][bottom][index][help] */
1374 {
1375     bool *timeout_popped = (bool*) user_data;
1376 
1377     *timeout_popped = TRUE;
1378     return FALSE;
1379 }
1380 
1381 /*!
1382  * \brief Drain some remaining main loop events then quit it
1383  *
1384  * \param[in] mloop  Main loop to drain and quit
1385  * \param[in] n      Drain up to this many pending events
1386  */
1387 void
1388 pcmk_quit_main_loop(GMainLoop *mloop, unsigned int n)
     /* [previous][next][first][last][top][bottom][index][help] */
1389 {
1390     if ((mloop != NULL) && g_main_loop_is_running(mloop)) {
1391         GMainContext *ctx = g_main_loop_get_context(mloop);
1392 
1393         /* Drain up to n events in case some memory clean-up is pending
1394          * (helpful to reduce noise in valgrind output).
1395          */
1396         for (int i = 0; (i < n) && g_main_context_pending(ctx); ++i) {
1397             g_main_context_dispatch(ctx);
1398         }
1399         g_main_loop_quit(mloop);
1400     }
1401 }
1402 
1403 /*!
1404  * \brief Process main loop events while a certain condition is met
1405  *
1406  * \param[in] mloop     Main loop to process
1407  * \param[in] timer_ms  Don't process longer than this amount of time
1408  * \param[in] check     Function that returns TRUE if events should be processed
1409  *
1410  * \note This function is intended to be called at shutdown if certain important
1411  *       events should not be missed. The caller would likely quit the main loop
1412  *       or exit after calling this function. The check() function will be
1413  *       passed the remaining timeout in milliseconds.
1414  */
1415 void
1416 pcmk_drain_main_loop(GMainLoop *mloop, guint timer_ms, bool (*check)(guint))
     /* [previous][next][first][last][top][bottom][index][help] */
1417 {
1418     bool timeout_popped = FALSE;
1419     guint timer = 0;
1420     GMainContext *ctx = NULL;
1421 
1422     CRM_CHECK(mloop && check, return);
1423 
1424     ctx = g_main_loop_get_context(mloop);
1425     if (ctx) {
1426         time_t start_time = time(NULL);
1427 
1428         timer = g_timeout_add(timer_ms, drain_timeout_cb, &timeout_popped);
1429         while (!timeout_popped
1430                && check(timer_ms - (time(NULL) - start_time) * 1000)) {
1431             g_main_context_iteration(ctx, TRUE);
1432         }
1433     }
1434     if (!timeout_popped && (timer > 0)) {
1435         g_source_remove(timer);
1436     }
1437 }
1438 
1439 // Deprecated functions kept only for backward API compatibility
1440 gboolean crm_signal(int sig, void (*dispatch) (int sig));
1441 
1442 /*
1443  * \brief Use crm_signal_handler() instead
1444  * \deprecated
1445  */
1446 gboolean
1447 crm_signal(int sig, void (*dispatch) (int sig))
     /* [previous][next][first][last][top][bottom][index][help] */
1448 {
1449     return crm_signal_handler(sig, dispatch) != SIG_ERR;
1450 }
1451 

/* [previous][next][first][last][top][bottom][index][help] */