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