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