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