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 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
200 mainloop_set_trigger(crm_trigger_t * source)
201 {
202 if(source) {
203 source->trigger = TRUE;
204 }
205 }
206
207 gboolean
208 mainloop_destroy_trigger(crm_trigger_t * source)
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);
219 g_source_unref(gs);
220
221
222
223
224
225
226
227 return TRUE;
228 }
229
230
231
232
233 typedef struct signal_s {
234 crm_trigger_t trigger;
235 void (*handler) (int sig);
236 int signal;
237 } crm_signal_t;
238
239
240 static crm_signal_t *crm_signals[NSIG];
241
242
243
244
245
246
247
248
249
250
251
252
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
271
272
273
274
275
276
277
278
279
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
289 static GSourceFuncs crm_signal_funcs = {
290 crm_trigger_prepare,
291 crm_trigger_check,
292 crm_signal_dispatch,
293 crm_trigger_finalize,
294 };
295
296
297
298
299
300
301
302
303
304
305
306
307
308 sighandler_t
309 crm_signal_handler(int sig, sighandler_t dispatch)
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);
342 mainloop_destroy_trigger((crm_trigger_t *) tmp);
343 }
344
345
346
347
348
349
350
351
352
353
354
355
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
364
365
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
397 return TRUE;
398 }
399
400 gboolean
401 mainloop_destroy_signal(int sig)
402 {
403 if (sig >= NSIG || sig < 0) {
404 crm_err("Signal %d is out of range", sig);
405 return FALSE;
406
407 } else if (crm_signal_handler(sig, NULL) == SIG_ERR) {
408 crm_perror(LOG_ERR, "Could not uninstall signal handler for signal %d", sig);
409 return FALSE;
410
411 } else if (crm_signals[sig] == NULL) {
412 return TRUE;
413 }
414 mainloop_destroy_signal_entry(sig);
415 return TRUE;
416 }
417
418 static qb_array_t *gio_map = NULL;
419
420 void
421 mainloop_cleanup(void)
422 {
423 if (gio_map) {
424 qb_array_free(gio_map);
425 }
426
427 for (int sig = 0; sig < NSIG; ++sig) {
428 mainloop_destroy_signal_entry(sig);
429 }
430 }
431
432
433
434
435 struct gio_to_qb_poll {
436 int32_t is_used;
437 guint source;
438 int32_t events;
439 void *data;
440 qb_ipcs_dispatch_fn_t fn;
441 enum qb_loop_priority p;
442 };
443
444 static gboolean
445 gio_read_socket(GIOChannel * gio, GIOCondition condition, gpointer data)
446 {
447 struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
448 gint fd = g_io_channel_unix_get_fd(gio);
449
450 crm_trace("%p.%d %d", data, fd, condition);
451
452
453
454 CRM_ASSERT(adaptor->is_used > 0);
455
456 return (adaptor->fn(fd, condition, adaptor->data) == 0);
457 }
458
459 static void
460 gio_poll_destroy(gpointer data)
461 {
462 struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
463
464 adaptor->is_used--;
465 CRM_ASSERT(adaptor->is_used >= 0);
466
467 if (adaptor->is_used == 0) {
468 crm_trace("Marking adaptor %p unused", adaptor);
469 adaptor->source = 0;
470 }
471 }
472
473
474
475
476
477
478
479
480
481 static gint
482 conv_prio_libqb2glib(enum qb_loop_priority prio)
483 {
484 switch (prio) {
485 case QB_LOOP_LOW: return G_PRIORITY_LOW;
486 case QB_LOOP_HIGH: return G_PRIORITY_HIGH;
487 default: return G_PRIORITY_DEFAULT;
488 }
489 }
490
491
492
493
494
495
496
497
498
499
500 static enum qb_ipcs_rate_limit
501 conv_libqb_prio2ratelimit(enum qb_loop_priority prio)
502 {
503 switch (prio) {
504 case QB_LOOP_LOW: return QB_IPCS_RATE_SLOW;
505 case QB_LOOP_HIGH: return QB_IPCS_RATE_FAST;
506 default: return QB_IPCS_RATE_NORMAL;
507 }
508 }
509
510 static int32_t
511 gio_poll_dispatch_update(enum qb_loop_priority p, int32_t fd, int32_t evts,
512 void *data, qb_ipcs_dispatch_fn_t fn, int32_t add)
513 {
514 struct gio_to_qb_poll *adaptor;
515 GIOChannel *channel;
516 int32_t res = 0;
517
518 res = qb_array_index(gio_map, fd, (void **)&adaptor);
519 if (res < 0) {
520 crm_err("Array lookup failed for fd=%d: %d", fd, res);
521 return res;
522 }
523
524 crm_trace("Adding fd=%d to mainloop as adaptor %p", fd, adaptor);
525
526 if (add && adaptor->source) {
527 crm_err("Adaptor for descriptor %d is still in-use", fd);
528 return -EEXIST;
529 }
530 if (!add && !adaptor->is_used) {
531 crm_err("Adaptor for descriptor %d is not in-use", fd);
532 return -ENOENT;
533 }
534
535
536 channel = g_io_channel_unix_new(fd);
537 if (!channel) {
538 crm_err("No memory left to add fd=%d", fd);
539 return -ENOMEM;
540 }
541
542 if (adaptor->source) {
543 g_source_remove(adaptor->source);
544 adaptor->source = 0;
545 }
546
547
548 evts |= (G_IO_HUP | G_IO_NVAL | G_IO_ERR);
549
550 adaptor->fn = fn;
551 adaptor->events = evts;
552 adaptor->data = data;
553 adaptor->p = p;
554 adaptor->is_used++;
555 adaptor->source =
556 g_io_add_watch_full(channel, conv_prio_libqb2glib(p), evts,
557 gio_read_socket, adaptor, gio_poll_destroy);
558
559
560
561
562
563
564
565
566
567
568 g_io_channel_unref(channel);
569
570 crm_trace("Added to mainloop with gsource id=%d", adaptor->source);
571 if (adaptor->source > 0) {
572 return 0;
573 }
574
575 return -EINVAL;
576 }
577
578 static int32_t
579 gio_poll_dispatch_add(enum qb_loop_priority p, int32_t fd, int32_t evts,
580 void *data, qb_ipcs_dispatch_fn_t fn)
581 {
582 return gio_poll_dispatch_update(p, fd, evts, data, fn, QB_TRUE);
583 }
584
585 static int32_t
586 gio_poll_dispatch_mod(enum qb_loop_priority p, int32_t fd, int32_t evts,
587 void *data, qb_ipcs_dispatch_fn_t fn)
588 {
589 return gio_poll_dispatch_update(p, fd, evts, data, fn, QB_FALSE);
590 }
591
592 static int32_t
593 gio_poll_dispatch_del(int32_t fd)
594 {
595 struct gio_to_qb_poll *adaptor;
596
597 crm_trace("Looking for fd=%d", fd);
598 if (qb_array_index(gio_map, fd, (void **)&adaptor) == 0) {
599 if (adaptor->source) {
600 g_source_remove(adaptor->source);
601 adaptor->source = 0;
602 }
603 }
604 return 0;
605 }
606
607 struct qb_ipcs_poll_handlers gio_poll_funcs = {
608 .job_add = NULL,
609 .dispatch_add = gio_poll_dispatch_add,
610 .dispatch_mod = gio_poll_dispatch_mod,
611 .dispatch_del = gio_poll_dispatch_del,
612 };
613
614 static enum qb_ipc_type
615 pick_ipc_type(enum qb_ipc_type requested)
616 {
617 const char *env = pcmk__env_option(PCMK__ENV_IPC_TYPE);
618
619 if (env && strcmp("shared-mem", env) == 0) {
620 return QB_IPC_SHM;
621 } else if (env && strcmp("socket", env) == 0) {
622 return QB_IPC_SOCKET;
623 } else if (env && strcmp("posix", env) == 0) {
624 return QB_IPC_POSIX_MQ;
625 } else if (env && strcmp("sysv", env) == 0) {
626 return QB_IPC_SYSV_MQ;
627 } else if (requested == QB_IPC_NATIVE) {
628
629
630
631
632
633
634 return QB_IPC_SHM;
635 }
636 return requested;
637 }
638
639 qb_ipcs_service_t *
640 mainloop_add_ipc_server(const char *name, enum qb_ipc_type type,
641 struct qb_ipcs_service_handlers *callbacks)
642 {
643 return mainloop_add_ipc_server_with_prio(name, type, callbacks, QB_LOOP_MED);
644 }
645
646 qb_ipcs_service_t *
647 mainloop_add_ipc_server_with_prio(const char *name, enum qb_ipc_type type,
648 struct qb_ipcs_service_handlers *callbacks,
649 enum qb_loop_priority prio)
650 {
651 int rc = 0;
652 qb_ipcs_service_t *server = NULL;
653
654 if (gio_map == NULL) {
655 gio_map = qb_array_create_2(64, sizeof(struct gio_to_qb_poll), 1);
656 }
657
658 server = qb_ipcs_create(name, 0, pick_ipc_type(type), callbacks);
659
660 if (server == NULL) {
661 crm_err("Could not create %s IPC server: %s (%d)",
662 name, pcmk_rc_str(errno), errno);
663 return NULL;
664 }
665
666 if (prio != QB_LOOP_MED) {
667 qb_ipcs_request_rate_limit(server, conv_libqb_prio2ratelimit(prio));
668 }
669
670
671 qb_ipcs_enforce_buffer_size(server, crm_ipc_default_buffer_size());
672 qb_ipcs_poll_handlers_set(server, &gio_poll_funcs);
673
674 rc = qb_ipcs_run(server);
675 if (rc < 0) {
676 crm_err("Could not start %s IPC server: %s (%d)", name, pcmk_strerror(rc), rc);
677 return NULL;
678 }
679
680 return server;
681 }
682
683 void
684 mainloop_del_ipc_server(qb_ipcs_service_t * server)
685 {
686 if (server) {
687 qb_ipcs_destroy(server);
688 }
689 }
690
691 struct mainloop_io_s {
692 char *name;
693 void *userdata;
694
695 int fd;
696 guint source;
697 crm_ipc_t *ipc;
698 GIOChannel *channel;
699
700 int (*dispatch_fn_ipc) (const char *buffer, ssize_t length, gpointer userdata);
701 int (*dispatch_fn_io) (gpointer userdata);
702 void (*destroy_fn) (gpointer userdata);
703
704 };
705
706
707
708
709
710
711
712
713
714
715
716 static gboolean
717 mainloop_gio_callback(GIOChannel *gio, GIOCondition condition, gpointer data)
718 {
719 gboolean rc = G_SOURCE_CONTINUE;
720 mainloop_io_t *client = data;
721
722 CRM_ASSERT(client->fd == g_io_channel_unix_get_fd(gio));
723
724 if (condition & G_IO_IN) {
725 if (client->ipc) {
726 long read_rc = 0L;
727 int max = 10;
728
729 do {
730 read_rc = crm_ipc_read(client->ipc);
731 if (read_rc <= 0) {
732 crm_trace("Could not read IPC message from %s: %s (%ld)",
733 client->name, pcmk_strerror(read_rc), read_rc);
734
735 } else if (client->dispatch_fn_ipc) {
736 const char *buffer = crm_ipc_buffer(client->ipc);
737
738 crm_trace("New %ld-byte IPC message from %s "
739 "after I/O condition %d",
740 read_rc, client->name, (int) condition);
741 if (client->dispatch_fn_ipc(buffer, read_rc, client->userdata) < 0) {
742 crm_trace("Connection to %s no longer required", client->name);
743 rc = G_SOURCE_REMOVE;
744 }
745 }
746
747 } while ((rc == G_SOURCE_CONTINUE) && (read_rc > 0) && --max > 0);
748
749 } else {
750 crm_trace("New I/O event for %s after I/O condition %d",
751 client->name, (int) condition);
752 if (client->dispatch_fn_io) {
753 if (client->dispatch_fn_io(client->userdata) < 0) {
754 crm_trace("Connection to %s no longer required", client->name);
755 rc = G_SOURCE_REMOVE;
756 }
757 }
758 }
759 }
760
761 if (client->ipc && !crm_ipc_connected(client->ipc)) {
762 crm_err("Connection to %s closed " CRM_XS "client=%p condition=%d",
763 client->name, client, condition);
764 rc = G_SOURCE_REMOVE;
765
766 } else if (condition & (G_IO_HUP | G_IO_NVAL | G_IO_ERR)) {
767 crm_trace("The connection %s[%p] has been closed (I/O condition=%d)",
768 client->name, client, condition);
769 rc = G_SOURCE_REMOVE;
770
771 } else if ((condition & G_IO_IN) == 0) {
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
799 crm_err("Strange condition: %d", condition);
800 }
801
802
803
804
805 return rc;
806 }
807
808 static void
809 mainloop_gio_destroy(gpointer c)
810 {
811 mainloop_io_t *client = c;
812 char *c_name = strdup(client->name);
813
814
815
816
817 crm_trace("Destroying client %s[%p]", c_name, c);
818
819 if (client->ipc) {
820 crm_ipc_close(client->ipc);
821 }
822
823 if (client->destroy_fn) {
824 void (*destroy_fn) (gpointer userdata) = client->destroy_fn;
825
826 client->destroy_fn = NULL;
827 destroy_fn(client->userdata);
828 }
829
830 if (client->ipc) {
831 crm_ipc_t *ipc = client->ipc;
832
833 client->ipc = NULL;
834 crm_ipc_destroy(ipc);
835 }
836
837 crm_trace("Destroyed client %s[%p]", c_name, c);
838
839 free(client->name); client->name = NULL;
840 free(client);
841
842 free(c_name);
843 }
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863 int
864 pcmk__add_mainloop_ipc(crm_ipc_t *ipc, int priority, void *userdata,
865 const struct ipc_client_callbacks *callbacks,
866 mainloop_io_t **source)
867 {
868 int rc = pcmk_rc_ok;
869 int fd = -1;
870 const char *ipc_name = NULL;
871
872 CRM_CHECK((ipc != NULL) && (callbacks != NULL), return EINVAL);
873
874 ipc_name = pcmk__s(crm_ipc_name(ipc), "Pacemaker");
875 rc = pcmk__connect_generic_ipc(ipc);
876 if (rc != pcmk_rc_ok) {
877 crm_debug("Connection to %s failed: %s", ipc_name, pcmk_rc_str(rc));
878 return rc;
879 }
880
881 rc = pcmk__ipc_fd(ipc, &fd);
882 if (rc != pcmk_rc_ok) {
883 crm_debug("Could not obtain file descriptor for %s IPC: %s",
884 ipc_name, pcmk_rc_str(rc));
885 crm_ipc_close(ipc);
886 return rc;
887 }
888
889 *source = mainloop_add_fd(ipc_name, priority, fd, userdata, NULL);
890 if (*source == NULL) {
891 rc = errno;
892 crm_ipc_close(ipc);
893 return rc;
894 }
895
896 (*source)->ipc = ipc;
897 (*source)->destroy_fn = callbacks->destroy;
898 (*source)->dispatch_fn_ipc = callbacks->dispatch;
899 return pcmk_rc_ok;
900 }
901
902
903
904
905
906
907
908
909 guint
910 pcmk__mainloop_timer_get_period(const mainloop_timer_t *timer)
911 {
912 if (timer) {
913 return timer->period_ms;
914 }
915 return 0;
916 }
917
918 mainloop_io_t *
919 mainloop_add_ipc_client(const char *name, int priority, size_t max_size,
920 void *userdata, struct ipc_client_callbacks *callbacks)
921 {
922 crm_ipc_t *ipc = crm_ipc_new(name, max_size);
923 mainloop_io_t *source = NULL;
924 int rc = pcmk__add_mainloop_ipc(ipc, priority, userdata, callbacks,
925 &source);
926
927 if (rc != pcmk_rc_ok) {
928 if (crm_log_level == LOG_STDOUT) {
929 fprintf(stderr, "Connection to %s failed: %s",
930 name, pcmk_rc_str(rc));
931 }
932 crm_ipc_destroy(ipc);
933 if (rc > 0) {
934 errno = rc;
935 } else {
936 errno = ENOTCONN;
937 }
938 return NULL;
939 }
940 return source;
941 }
942
943 void
944 mainloop_del_ipc_client(mainloop_io_t * client)
945 {
946 mainloop_del_fd(client);
947 }
948
949 crm_ipc_t *
950 mainloop_get_ipc_client(mainloop_io_t * client)
951 {
952 if (client) {
953 return client->ipc;
954 }
955 return NULL;
956 }
957
958 mainloop_io_t *
959 mainloop_add_fd(const char *name, int priority, int fd, void *userdata,
960 struct mainloop_fd_callbacks * callbacks)
961 {
962 mainloop_io_t *client = NULL;
963
964 if (fd >= 0) {
965 client = calloc(1, sizeof(mainloop_io_t));
966 if (client == NULL) {
967 return NULL;
968 }
969 client->name = strdup(name);
970 client->userdata = userdata;
971
972 if (callbacks) {
973 client->destroy_fn = callbacks->destroy;
974 client->dispatch_fn_io = callbacks->dispatch;
975 }
976
977 client->fd = fd;
978 client->channel = g_io_channel_unix_new(fd);
979 client->source =
980 g_io_add_watch_full(client->channel, priority,
981 (G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR), mainloop_gio_callback,
982 client, mainloop_gio_destroy);
983
984
985
986
987
988
989
990
991
992
993 g_io_channel_unref(client->channel);
994 crm_trace("Added connection %d for %s[%p].%d", client->source, client->name, client, fd);
995 } else {
996 errno = EINVAL;
997 }
998
999 return client;
1000 }
1001
1002 void
1003 mainloop_del_fd(mainloop_io_t * client)
1004 {
1005 if (client != NULL) {
1006 crm_trace("Removing client %s[%p]", client->name, client);
1007 if (client->source) {
1008
1009
1010
1011 g_source_remove(client->source);
1012 }
1013 }
1014 }
1015
1016 static GList *child_list = NULL;
1017
1018 pid_t
1019 mainloop_child_pid(mainloop_child_t * child)
1020 {
1021 return child->pid;
1022 }
1023
1024 const char *
1025 mainloop_child_name(mainloop_child_t * child)
1026 {
1027 return child->desc;
1028 }
1029
1030 int
1031 mainloop_child_timeout(mainloop_child_t * child)
1032 {
1033 return child->timeout;
1034 }
1035
1036 void *
1037 mainloop_child_userdata(mainloop_child_t * child)
1038 {
1039 return child->privatedata;
1040 }
1041
1042 void
1043 mainloop_clear_child_userdata(mainloop_child_t * child)
1044 {
1045 child->privatedata = NULL;
1046 }
1047
1048
1049 static void
1050 child_free(mainloop_child_t *child)
1051 {
1052 if (child->timerid != 0) {
1053 crm_trace("Removing timer %d", child->timerid);
1054 g_source_remove(child->timerid);
1055 child->timerid = 0;
1056 }
1057 free(child->desc);
1058 free(child);
1059 }
1060
1061
1062 static int
1063 child_kill_helper(mainloop_child_t *child)
1064 {
1065 int rc;
1066 if (child->flags & mainloop_leave_pid_group) {
1067 crm_debug("Kill pid %d only. leave group intact.", child->pid);
1068 rc = kill(child->pid, SIGKILL);
1069 } else {
1070 crm_debug("Kill pid %d's group", child->pid);
1071 rc = kill(-child->pid, SIGKILL);
1072 }
1073
1074 if (rc < 0) {
1075 if (errno != ESRCH) {
1076 crm_perror(LOG_ERR, "kill(%d, KILL) failed", child->pid);
1077 }
1078 return -errno;
1079 }
1080 return 0;
1081 }
1082
1083 static gboolean
1084 child_timeout_callback(gpointer p)
1085 {
1086 mainloop_child_t *child = p;
1087 int rc = 0;
1088
1089 child->timerid = 0;
1090 if (child->timeout) {
1091 crm_warn("%s process (PID %d) will not die!", child->desc, (int)child->pid);
1092 return FALSE;
1093 }
1094
1095 rc = child_kill_helper(child);
1096 if (rc == -ESRCH) {
1097
1098 return FALSE;
1099 }
1100
1101 child->timeout = TRUE;
1102 crm_debug("%s process (PID %d) timed out", child->desc, (int)child->pid);
1103
1104 child->timerid = g_timeout_add(5000, child_timeout_callback, child);
1105 return FALSE;
1106 }
1107
1108 static bool
1109 child_waitpid(mainloop_child_t *child, int flags)
1110 {
1111 int rc = 0;
1112 int core = 0;
1113 int signo = 0;
1114 int status = 0;
1115 int exitcode = 0;
1116 bool callback_needed = true;
1117
1118 rc = waitpid(child->pid, &status, flags);
1119 if (rc == 0) {
1120 crm_trace("Child process %d (%s) still active",
1121 child->pid, child->desc);
1122 callback_needed = false;
1123
1124 } else if (rc != child->pid) {
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134 signo = SIGCHLD;
1135 exitcode = 1;
1136 crm_notice("Wait for child process %d (%s) interrupted: %s",
1137 child->pid, child->desc, pcmk_rc_str(errno));
1138
1139 } else if (WIFEXITED(status)) {
1140 exitcode = WEXITSTATUS(status);
1141 crm_trace("Child process %d (%s) exited with status %d",
1142 child->pid, child->desc, exitcode);
1143
1144 } else if (WIFSIGNALED(status)) {
1145 signo = WTERMSIG(status);
1146 crm_trace("Child process %d (%s) exited with signal %d (%s)",
1147 child->pid, child->desc, signo, strsignal(signo));
1148
1149 #ifdef WCOREDUMP
1150 } else if (WCOREDUMP(status)) {
1151 core = 1;
1152 crm_err("Child process %d (%s) dumped core",
1153 child->pid, child->desc);
1154 #endif
1155
1156 } else {
1157 crm_trace("Child process %d (%s) stopped or continued",
1158 child->pid, child->desc);
1159 callback_needed = false;
1160 }
1161
1162 if (callback_needed && child->callback) {
1163 child->callback(child, child->pid, core, signo, exitcode);
1164 }
1165 return callback_needed;
1166 }
1167
1168 static void
1169 child_death_dispatch(int signal)
1170 {
1171 for (GList *iter = child_list; iter; ) {
1172 GList *saved = iter;
1173 mainloop_child_t *child = iter->data;
1174
1175 iter = iter->next;
1176 if (child_waitpid(child, WNOHANG)) {
1177 crm_trace("Removing completed process %d from child list",
1178 child->pid);
1179 child_list = g_list_remove_link(child_list, saved);
1180 g_list_free(saved);
1181 child_free(child);
1182 }
1183 }
1184 }
1185
1186 static gboolean
1187 child_signal_init(gpointer p)
1188 {
1189 crm_trace("Installed SIGCHLD handler");
1190
1191 mainloop_add_signal(SIGCHLD, child_death_dispatch);
1192
1193
1194 child_death_dispatch(SIGCHLD);
1195 return FALSE;
1196 }
1197
1198 gboolean
1199 mainloop_child_kill(pid_t pid)
1200 {
1201 GList *iter;
1202 mainloop_child_t *child = NULL;
1203 mainloop_child_t *match = NULL;
1204
1205
1206 int waitflags = 0, rc = 0;
1207
1208 for (iter = child_list; iter != NULL && match == NULL; iter = iter->next) {
1209 child = iter->data;
1210 if (pid == child->pid) {
1211 match = child;
1212 }
1213 }
1214
1215 if (match == NULL) {
1216 return FALSE;
1217 }
1218
1219 rc = child_kill_helper(match);
1220 if(rc == -ESRCH) {
1221
1222
1223
1224
1225
1226 crm_trace("Waiting for signal that child process %d completed",
1227 match->pid);
1228 return TRUE;
1229
1230 } else if(rc != 0) {
1231
1232
1233
1234 waitflags = WNOHANG;
1235 }
1236
1237 if (!child_waitpid(match, waitflags)) {
1238
1239 return FALSE;
1240 }
1241
1242 child_list = g_list_remove(child_list, match);
1243 child_free(match);
1244 return TRUE;
1245 }
1246
1247
1248
1249
1250
1251
1252
1253
1254 void
1255 mainloop_child_add_with_flags(pid_t pid, int timeout, const char *desc, void *privatedata, enum mainloop_child_flags flags,
1256 void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode))
1257 {
1258 static bool need_init = TRUE;
1259 mainloop_child_t *child = calloc(1, sizeof(mainloop_child_t));
1260
1261 child->pid = pid;
1262 child->timerid = 0;
1263 child->timeout = FALSE;
1264 child->privatedata = privatedata;
1265 child->callback = callback;
1266 child->flags = flags;
1267 pcmk__str_update(&child->desc, desc);
1268
1269 if (timeout) {
1270 child->timerid = g_timeout_add(timeout, child_timeout_callback, child);
1271 }
1272
1273 child_list = g_list_append(child_list, child);
1274
1275 if(need_init) {
1276 need_init = FALSE;
1277
1278
1279
1280
1281 g_timeout_add(1, child_signal_init, NULL);
1282 }
1283 }
1284
1285 void
1286 mainloop_child_add(pid_t pid, int timeout, const char *desc, void *privatedata,
1287 void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode))
1288 {
1289 mainloop_child_add_with_flags(pid, timeout, desc, privatedata, 0, callback);
1290 }
1291
1292 static gboolean
1293 mainloop_timer_cb(gpointer user_data)
1294 {
1295 int id = 0;
1296 bool repeat = FALSE;
1297 struct mainloop_timer_s *t = user_data;
1298
1299 CRM_ASSERT(t != NULL);
1300
1301 id = t->id;
1302 t->id = 0;
1303
1304
1305
1306 if(t->cb) {
1307 crm_trace("Invoking callbacks for timer %s", t->name);
1308 repeat = t->repeat;
1309 if(t->cb(t->userdata) == FALSE) {
1310 crm_trace("Timer %s complete", t->name);
1311 repeat = FALSE;
1312 }
1313 }
1314
1315 if(repeat) {
1316
1317 t->id = id;
1318 }
1319
1320 return repeat;
1321 }
1322
1323 bool
1324 mainloop_timer_running(mainloop_timer_t *t)
1325 {
1326 if(t && t->id != 0) {
1327 return TRUE;
1328 }
1329 return FALSE;
1330 }
1331
1332 void
1333 mainloop_timer_start(mainloop_timer_t *t)
1334 {
1335 mainloop_timer_stop(t);
1336 if(t && t->period_ms > 0) {
1337 crm_trace("Starting timer %s", t->name);
1338 t->id = g_timeout_add(t->period_ms, mainloop_timer_cb, t);
1339 }
1340 }
1341
1342 void
1343 mainloop_timer_stop(mainloop_timer_t *t)
1344 {
1345 if(t && t->id != 0) {
1346 crm_trace("Stopping timer %s", t->name);
1347 g_source_remove(t->id);
1348 t->id = 0;
1349 }
1350 }
1351
1352 guint
1353 mainloop_timer_set_period(mainloop_timer_t *t, guint period_ms)
1354 {
1355 guint last = 0;
1356
1357 if(t) {
1358 last = t->period_ms;
1359 t->period_ms = period_ms;
1360 }
1361
1362 if(t && t->id != 0 && last != t->period_ms) {
1363 mainloop_timer_start(t);
1364 }
1365 return last;
1366 }
1367
1368 mainloop_timer_t *
1369 mainloop_timer_add(const char *name, guint period_ms, bool repeat, GSourceFunc cb, void *userdata)
1370 {
1371 mainloop_timer_t *t = calloc(1, sizeof(mainloop_timer_t));
1372
1373 if(t) {
1374 if(name) {
1375 t->name = crm_strdup_printf("%s-%u-%d", name, period_ms, repeat);
1376 } else {
1377 t->name = crm_strdup_printf("%p-%u-%d", t, period_ms, repeat);
1378 }
1379 t->id = 0;
1380 t->period_ms = period_ms;
1381 t->repeat = repeat;
1382 t->cb = cb;
1383 t->userdata = userdata;
1384 crm_trace("Created timer %s with %p %p", t->name, userdata, t->userdata);
1385 }
1386 return t;
1387 }
1388
1389 void
1390 mainloop_timer_del(mainloop_timer_t *t)
1391 {
1392 if(t) {
1393 crm_trace("Destroying timer %s", t->name);
1394 mainloop_timer_stop(t);
1395 free(t->name);
1396 free(t);
1397 }
1398 }
1399
1400
1401
1402
1403
1404 static gboolean
1405 drain_timeout_cb(gpointer user_data)
1406 {
1407 bool *timeout_popped = (bool*) user_data;
1408
1409 *timeout_popped = TRUE;
1410 return FALSE;
1411 }
1412
1413
1414
1415
1416
1417
1418
1419 void
1420 pcmk_quit_main_loop(GMainLoop *mloop, unsigned int n)
1421 {
1422 if ((mloop != NULL) && g_main_loop_is_running(mloop)) {
1423 GMainContext *ctx = g_main_loop_get_context(mloop);
1424
1425
1426
1427
1428 for (int i = 0; (i < n) && g_main_context_pending(ctx); ++i) {
1429 g_main_context_dispatch(ctx);
1430 }
1431 g_main_loop_quit(mloop);
1432 }
1433 }
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448 void
1449 pcmk_drain_main_loop(GMainLoop *mloop, guint timer_ms, bool (*check)(guint))
1450 {
1451 bool timeout_popped = FALSE;
1452 guint timer = 0;
1453 GMainContext *ctx = NULL;
1454
1455 CRM_CHECK(mloop && check, return);
1456
1457 ctx = g_main_loop_get_context(mloop);
1458 if (ctx) {
1459 time_t start_time = time(NULL);
1460
1461 timer = g_timeout_add(timer_ms, drain_timeout_cb, &timeout_popped);
1462 while (!timeout_popped
1463 && check(timer_ms - (time(NULL) - start_time) * 1000)) {
1464 g_main_context_iteration(ctx, TRUE);
1465 }
1466 }
1467 if (!timeout_popped && (timer > 0)) {
1468 g_source_remove(timer);
1469 }
1470 }
1471
1472
1473
1474
1475 #include <crm/common/mainloop_compat.h>
1476
1477 gboolean
1478 crm_signal(int sig, void (*dispatch) (int sig))
1479 {
1480 return crm_signal_handler(sig, dispatch) != SIG_ERR;
1481 }
1482
1483
1484