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