This source file includes following definitions.
- crm_trigger_prepare
- crm_trigger_check
- crm_trigger_dispatch
- crm_trigger_finalize
- mainloop_setup_trigger
- mainloop_trigger_complete
- mainloop_add_trigger
- mainloop_set_trigger
- mainloop_destroy_trigger
- crm_signal_dispatch
- mainloop_signal_handler
- crm_signal_handler
- mainloop_destroy_signal_entry
- mainloop_add_signal
- mainloop_destroy_signal
- mainloop_cleanup
- gio_read_socket
- gio_poll_destroy
- conv_prio_libqb2glib
- conv_libqb_prio2ratelimit
- gio_poll_dispatch_update
- gio_poll_dispatch_add
- gio_poll_dispatch_mod
- gio_poll_dispatch_del
- pick_ipc_type
- mainloop_add_ipc_server
- mainloop_add_ipc_server_with_prio
- mainloop_del_ipc_server
- mainloop_gio_callback
- mainloop_gio_destroy
- pcmk__add_mainloop_ipc
- pcmk__mainloop_timer_get_period
- mainloop_add_ipc_client
- mainloop_del_ipc_client
- mainloop_get_ipc_client
- mainloop_add_fd
- mainloop_del_fd
- mainloop_child_pid
- mainloop_child_name
- mainloop_child_timeout
- mainloop_child_userdata
- mainloop_clear_child_userdata
- child_free
- child_kill_helper
- child_timeout_callback
- child_waitpid
- child_death_dispatch
- child_signal_init
- mainloop_child_kill
- mainloop_child_add_with_flags
- mainloop_child_add
- mainloop_timer_cb
- mainloop_timer_running
- mainloop_timer_start
- mainloop_timer_stop
- mainloop_timer_set_period
- mainloop_timer_add
- mainloop_timer_del
- drain_timeout_cb
- pcmk_quit_main_loop
- pcmk_drain_main_loop
- crm_signal
1
2
3
4
5
6
7
8
9
10 #include <crm_internal.h>
11
12 #ifndef _GNU_SOURCE
13 # define _GNU_SOURCE
14 #endif
15
16 #include <stdlib.h>
17 #include <string.h>
18 #include <signal.h>
19 #include <errno.h>
20
21 #include <sys/wait.h>
22
23 #include <crm/crm.h>
24 #include <crm/common/xml.h>
25 #include <crm/common/mainloop.h>
26 #include <crm/common/ipc_internal.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
37 enum mainloop_child_flags flags;
38
39
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 *timeout = 500;
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
96
97
98
99
100
101
102
103
104
105
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
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
168 mainloop_trigger_complete(crm_trigger_t * trig)
169 {
170 crm_trace("Trigger handler %p complete", trig);
171 trig->running = FALSE;
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185
186 crm_trigger_t *
187 mainloop_add_trigger(int priority, int (*dispatch) (gpointer user_data),
188 gpointer userdata)
189 {
190 GSource *source = NULL;
191
192 pcmk__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
199 mainloop_set_trigger(crm_trigger_t * source)
200 {
201 if(source) {
202 source->trigger = TRUE;
203 }
204 }
205
206 gboolean
207 mainloop_destroy_trigger(crm_trigger_t * source)
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);
218 g_source_unref(gs);
219
220
221
222
223
224
225
226 return TRUE;
227 }
228
229
230
231
232 typedef struct signal_s {
233 crm_trigger_t trigger;
234 void (*handler) (int sig);
235 int signal;
236 } crm_signal_t;
237
238
239 static crm_signal_t *crm_signals[NSIG];
240
241
242
243
244
245
246
247
248
249
250
251
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
270
271
272
273
274
275
276
277
278
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
288 static GSourceFuncs crm_signal_funcs = {
289 crm_trigger_prepare,
290 crm_trigger_check,
291 crm_signal_dispatch,
292 crm_trigger_finalize,
293 };
294
295
296
297
298
299
300
301
302
303
304
305
306
307 sighandler_t
308 crm_signal_handler(int sig, sighandler_t dispatch)
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);
341 mainloop_destroy_trigger((crm_trigger_t *) tmp);
342 }
343
344
345
346
347
348
349
350
351
352
353
354
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
363
364
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 pcmk__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 pcmk__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
400 mainloop_destroy_signal(int sig)
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
420 mainloop_cleanup(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
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
452
453 pcmk__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 pcmk__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
472
473
474
475
476
477
478
479
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;
487 }
488 }
489
490
491
492
493
494
495
496
497
498
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;
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
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
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
559
560
561
562
563
564
565
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
628
629
630
631
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
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;
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
705
706
707
708
709
710
711
712
713
714
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 pcmk__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
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798 crm_err("Strange condition: %d", condition);
799 }
800
801
802
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
814
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
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
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
901
902
903
904
905
906
907
908 guint
909 pcmk__mainloop_timer_get_period(const mainloop_timer_t *timer)
910 {
911 if (timer) {
912 return timer->period_ms;
913 }
914 return 0;
915 }
916
917 mainloop_io_t *
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
943 mainloop_del_ipc_client(mainloop_io_t * client)
944 {
945 mainloop_del_fd(client);
946 }
947
948 crm_ipc_t *
949 mainloop_get_ipc_client(mainloop_io_t * client)
950 {
951 if (client) {
952 return client->ipc;
953 }
954 return NULL;
955 }
956
957 mainloop_io_t *
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
984
985
986
987
988
989
990
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
1002 mainloop_del_fd(mainloop_io_t * client)
1003 {
1004 if (client != NULL) {
1005 crm_trace("Removing client %s[%p]", client->name, client);
1006 if (client->source) {
1007
1008
1009
1010 g_source_remove(client->source);
1011 }
1012 }
1013 }
1014
1015 static GList *child_list = NULL;
1016
1017 pid_t
1018 mainloop_child_pid(mainloop_child_t * child)
1019 {
1020 return child->pid;
1021 }
1022
1023 const char *
1024 mainloop_child_name(mainloop_child_t * child)
1025 {
1026 return child->desc;
1027 }
1028
1029 int
1030 mainloop_child_timeout(mainloop_child_t * child)
1031 {
1032 return child->timeout;
1033 }
1034
1035 void *
1036 mainloop_child_userdata(mainloop_child_t * child)
1037 {
1038 return child->privatedata;
1039 }
1040
1041 void
1042 mainloop_clear_child_userdata(mainloop_child_t * child)
1043 {
1044 child->privatedata = NULL;
1045 }
1046
1047
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
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
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) {
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
1125
1126
1127
1128
1129
1130
1131
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
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 {
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
1190 mainloop_add_signal(SIGCHLD, child_death_dispatch);
1191
1192
1193 child_death_dispatch(SIGCHLD);
1194 return FALSE;
1195 }
1196
1197 gboolean
1198 mainloop_child_kill(pid_t pid)
1199 {
1200 GList *iter;
1201 mainloop_child_t *child = NULL;
1202 mainloop_child_t *match = NULL;
1203
1204
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
1221
1222
1223
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
1231
1232
1233 waitflags = WNOHANG;
1234 }
1235
1236 if (!child_waitpid(match, waitflags)) {
1237
1238 return FALSE;
1239 }
1240
1241 child_list = g_list_remove(child_list, match);
1242 child_free(match);
1243 return TRUE;
1244 }
1245
1246
1247
1248
1249
1250
1251
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;
1258 mainloop_child_t *child = pcmk__assert_alloc(1, sizeof(mainloop_child_t));
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
1277
1278
1279
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 pcmk__assert(t != NULL);
1299
1300 id = t->id;
1301 t->id = 0;
1302
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
1316 t->id = id;
1317 }
1318
1319 return repeat;
1320 }
1321
1322 bool
1323 mainloop_timer_running(mainloop_timer_t *t)
1324 {
1325 if(t && t->id != 0) {
1326 return TRUE;
1327 }
1328 return FALSE;
1329 }
1330
1331 void
1332 mainloop_timer_start(mainloop_timer_t *t)
1333 {
1334 mainloop_timer_stop(t);
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
1342 mainloop_timer_stop(mainloop_timer_t *t)
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
1352 mainloop_timer_set_period(mainloop_timer_t *t, guint period_ms)
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) {
1362 mainloop_timer_start(t);
1363 }
1364 return last;
1365 }
1366
1367 mainloop_timer_t *
1368 mainloop_timer_add(const char *name, guint period_ms, bool repeat, GSourceFunc cb, void *userdata)
1369 {
1370 mainloop_timer_t *t = pcmk__assert_alloc(1, sizeof(mainloop_timer_t));
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
1387 mainloop_timer_del(mainloop_timer_t *t)
1388 {
1389 if(t) {
1390 crm_trace("Destroying timer %s", t->name);
1391 mainloop_timer_stop(t);
1392 free(t->name);
1393 free(t);
1394 }
1395 }
1396
1397
1398
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
1410
1411
1412
1413
1414
1415
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
1423
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
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
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
1470
1471
1472 #include <crm/common/mainloop_compat.h>
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
1481