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. pcmk__mainloop_timer_get_period
  33. mainloop_add_ipc_client
  34. mainloop_del_ipc_client
  35. mainloop_get_ipc_client
  36. mainloop_add_fd
  37. mainloop_del_fd
  38. mainloop_child_pid
  39. mainloop_child_name
  40. mainloop_child_timeout
  41. mainloop_child_userdata
  42. mainloop_clear_child_userdata
  43. child_free
  44. child_kill_helper
  45. child_timeout_callback
  46. child_waitpid
  47. child_death_dispatch
  48. child_signal_init
  49. mainloop_child_kill
  50. mainloop_child_add_with_flags
  51. mainloop_child_add
  52. mainloop_timer_cb
  53. mainloop_timer_running
  54. mainloop_timer_start
  55. mainloop_timer_stop
  56. mainloop_timer_set_period
  57. mainloop_timer_add
  58. mainloop_timer_del
  59. drain_timeout_cb
  60. pcmk_quit_main_loop
  61. pcmk_drain_main_loop
  62. crm_signal

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

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