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