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