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
- 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 static gboolean
53 crm_trigger_prepare(GSource * source, gint * timeout)
54 {
55 crm_trigger_t *trig = (crm_trigger_t *) source;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74 *timeout = 500;
75
76 return trig->trigger;
77 }
78
79 static gboolean
80 crm_trigger_check(GSource * source)
81 {
82 crm_trigger_t *trig = (crm_trigger_t *) source;
83
84 return trig->trigger;
85 }
86
87 static gboolean
88 crm_trigger_dispatch(GSource * source, GSourceFunc callback, gpointer userdata)
89 {
90 int rc = TRUE;
91 crm_trigger_t *trig = (crm_trigger_t *) source;
92
93 if (trig->running) {
94
95 return TRUE;
96 }
97 trig->trigger = FALSE;
98
99 if (callback) {
100 rc = callback(trig->user_data);
101 if (rc < 0) {
102 crm_trace("Trigger handler %p not yet complete", trig);
103 trig->running = TRUE;
104 rc = TRUE;
105 }
106 }
107 return rc;
108 }
109
110 static void
111 crm_trigger_finalize(GSource * source)
112 {
113 crm_trace("Trigger %p destroyed", source);
114 }
115
116 static GSourceFuncs crm_trigger_funcs = {
117 crm_trigger_prepare,
118 crm_trigger_check,
119 crm_trigger_dispatch,
120 crm_trigger_finalize,
121 };
122
123 static crm_trigger_t *
124 mainloop_setup_trigger(GSource * source, int priority, int (*dispatch) (gpointer user_data),
125 gpointer userdata)
126 {
127 crm_trigger_t *trigger = NULL;
128
129 trigger = (crm_trigger_t *) source;
130
131 trigger->id = 0;
132 trigger->trigger = FALSE;
133 trigger->user_data = userdata;
134
135 if (dispatch) {
136 g_source_set_callback(source, dispatch, trigger, NULL);
137 }
138
139 g_source_set_priority(source, priority);
140 g_source_set_can_recurse(source, FALSE);
141
142 trigger->id = g_source_attach(source, NULL);
143 return trigger;
144 }
145
146 void
147 mainloop_trigger_complete(crm_trigger_t * trig)
148 {
149 crm_trace("Trigger handler %p complete", trig);
150 trig->running = FALSE;
151 }
152
153
154
155
156
157
158 crm_trigger_t *
159 mainloop_add_trigger(int priority, int (*dispatch) (gpointer user_data), gpointer userdata)
160 {
161 GSource *source = NULL;
162
163 CRM_ASSERT(sizeof(crm_trigger_t) > sizeof(GSource));
164 source = g_source_new(&crm_trigger_funcs, sizeof(crm_trigger_t));
165 CRM_ASSERT(source != NULL);
166
167 return mainloop_setup_trigger(source, priority, dispatch, userdata);
168 }
169
170 void
171 mainloop_set_trigger(crm_trigger_t * source)
172 {
173 if(source) {
174 source->trigger = TRUE;
175 }
176 }
177
178 gboolean
179 mainloop_destroy_trigger(crm_trigger_t * source)
180 {
181 GSource *gs = NULL;
182
183 if(source == NULL) {
184 return TRUE;
185 }
186
187 gs = (GSource *)source;
188
189 g_source_destroy(gs);
190 g_source_unref(gs);
191
192
193
194
195
196
197
198 return TRUE;
199 }
200
201
202
203
204 typedef struct signal_s {
205 crm_trigger_t trigger;
206 void (*handler) (int sig);
207 int signal;
208 } crm_signal_t;
209
210
211 static crm_signal_t *crm_signals[NSIG];
212
213
214
215
216
217
218
219
220
221
222
223
224 static gboolean
225 crm_signal_dispatch(GSource * source, GSourceFunc callback, gpointer userdata)
226 {
227 crm_signal_t *sig = (crm_signal_t *) source;
228
229 if(sig->signal != SIGCHLD) {
230 crm_notice("Caught '%s' signal "CRM_XS" %d (%s handler)",
231 strsignal(sig->signal), sig->signal,
232 (sig->handler? "invoking" : "no"));
233 }
234
235 sig->trigger.trigger = FALSE;
236 if (sig->handler) {
237 sig->handler(sig->signal);
238 }
239 return TRUE;
240 }
241
242
243
244
245
246
247
248
249
250
251 static void
252 mainloop_signal_handler(int sig)
253 {
254 if (sig > 0 && sig < NSIG && crm_signals[sig] != NULL) {
255 mainloop_set_trigger((crm_trigger_t *) crm_signals[sig]);
256 }
257 }
258
259
260 static GSourceFuncs crm_signal_funcs = {
261 crm_trigger_prepare,
262 crm_trigger_check,
263 crm_signal_dispatch,
264 crm_trigger_finalize,
265 };
266
267
268
269
270
271
272
273
274
275
276
277
278
279 sighandler_t
280 crm_signal_handler(int sig, sighandler_t dispatch)
281 {
282 sigset_t mask;
283 struct sigaction sa;
284 struct sigaction old;
285
286 if (sigemptyset(&mask) < 0) {
287 crm_err("Could not set handler for signal %d: %s",
288 sig, pcmk_strerror(errno));
289 return SIG_ERR;
290 }
291
292 memset(&sa, 0, sizeof(struct sigaction));
293 sa.sa_handler = dispatch;
294 sa.sa_flags = SA_RESTART;
295 sa.sa_mask = mask;
296
297 if (sigaction(sig, &sa, &old) < 0) {
298 crm_err("Could not set handler for signal %d: %s",
299 sig, pcmk_strerror(errno));
300 return SIG_ERR;
301 }
302 return old.sa_handler;
303 }
304
305 static void
306 mainloop_destroy_signal_entry(int sig)
307 {
308 crm_signal_t *tmp = crm_signals[sig];
309
310 crm_signals[sig] = NULL;
311
312 crm_trace("Destroying signal %d", sig);
313 mainloop_destroy_trigger((crm_trigger_t *) tmp);
314 }
315
316
317
318
319
320
321
322
323
324
325
326
327 gboolean
328 mainloop_add_signal(int sig, void (*dispatch) (int sig))
329 {
330 GSource *source = NULL;
331 int priority = G_PRIORITY_HIGH - 1;
332
333 if (sig == SIGTERM) {
334
335
336
337
338 priority--;
339 }
340
341 if (sig >= NSIG || sig < 0) {
342 crm_err("Signal %d is out of range", sig);
343 return FALSE;
344
345 } else if (crm_signals[sig] != NULL && crm_signals[sig]->handler == dispatch) {
346 crm_trace("Signal handler for %d is already installed", sig);
347 return TRUE;
348
349 } else if (crm_signals[sig] != NULL) {
350 crm_err("Different signal handler for %d is already installed", sig);
351 return FALSE;
352 }
353
354 CRM_ASSERT(sizeof(crm_signal_t) > sizeof(GSource));
355 source = g_source_new(&crm_signal_funcs, sizeof(crm_signal_t));
356
357 crm_signals[sig] = (crm_signal_t *) mainloop_setup_trigger(source, priority, NULL, NULL);
358 CRM_ASSERT(crm_signals[sig] != NULL);
359
360 crm_signals[sig]->handler = dispatch;
361 crm_signals[sig]->signal = sig;
362
363 if (crm_signal_handler(sig, mainloop_signal_handler) == SIG_ERR) {
364 mainloop_destroy_signal_entry(sig);
365 return FALSE;
366 }
367 #if 0
368
369
370
371
372
373 if (siginterrupt(sig, 1) < 0) {
374 crm_perror(LOG_INFO, "Could not enable system call interruptions for signal %d", sig);
375 }
376 #endif
377
378 return TRUE;
379 }
380
381 gboolean
382 mainloop_destroy_signal(int sig)
383 {
384 if (sig >= NSIG || sig < 0) {
385 crm_err("Signal %d is out of range", sig);
386 return FALSE;
387
388 } else if (crm_signal_handler(sig, NULL) == SIG_ERR) {
389 crm_perror(LOG_ERR, "Could not uninstall signal handler for signal %d", sig);
390 return FALSE;
391
392 } else if (crm_signals[sig] == NULL) {
393 return TRUE;
394 }
395 mainloop_destroy_signal_entry(sig);
396 return TRUE;
397 }
398
399 static qb_array_t *gio_map = NULL;
400
401 void
402 mainloop_cleanup(void)
403 {
404 if (gio_map) {
405 qb_array_free(gio_map);
406 }
407
408 for (int sig = 0; sig < NSIG; ++sig) {
409 mainloop_destroy_signal_entry(sig);
410 }
411 }
412
413
414
415
416 struct gio_to_qb_poll {
417 int32_t is_used;
418 guint source;
419 int32_t events;
420 void *data;
421 qb_ipcs_dispatch_fn_t fn;
422 enum qb_loop_priority p;
423 };
424
425 static gboolean
426 gio_read_socket(GIOChannel * gio, GIOCondition condition, gpointer data)
427 {
428 struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
429 gint fd = g_io_channel_unix_get_fd(gio);
430
431 crm_trace("%p.%d %d", data, fd, condition);
432
433
434
435 CRM_ASSERT(adaptor->is_used > 0);
436
437 return (adaptor->fn(fd, condition, adaptor->data) == 0);
438 }
439
440 static void
441 gio_poll_destroy(gpointer data)
442 {
443 struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
444
445 adaptor->is_used--;
446 CRM_ASSERT(adaptor->is_used >= 0);
447
448 if (adaptor->is_used == 0) {
449 crm_trace("Marking adaptor %p unused", adaptor);
450 adaptor->source = 0;
451 }
452 }
453
454
455
456
457
458
459
460
461
462 static gint
463 conv_prio_libqb2glib(enum qb_loop_priority prio)
464 {
465 gint ret = G_PRIORITY_DEFAULT;
466 switch (prio) {
467 case QB_LOOP_LOW:
468 ret = G_PRIORITY_LOW;
469 break;
470 case QB_LOOP_HIGH:
471 ret = G_PRIORITY_HIGH;
472 break;
473 default:
474 crm_trace("Invalid libqb's loop priority %d, assuming QB_LOOP_MED",
475 prio);
476
477 case QB_LOOP_MED:
478 break;
479 }
480 return ret;
481 }
482
483
484
485
486
487
488
489
490
491 static enum qb_ipcs_rate_limit
492 conv_libqb_prio2ratelimit(enum qb_loop_priority prio)
493 {
494
495 enum qb_ipcs_rate_limit ret = QB_IPCS_RATE_NORMAL;
496 switch (prio) {
497 case QB_LOOP_LOW:
498 ret = QB_IPCS_RATE_SLOW;
499 break;
500 case QB_LOOP_HIGH:
501 ret = QB_IPCS_RATE_FAST;
502 break;
503 default:
504 crm_trace("Invalid libqb's loop priority %d, assuming QB_LOOP_MED",
505 prio);
506
507 case QB_LOOP_MED:
508 break;
509 }
510 return ret;
511 }
512
513 static int32_t
514 gio_poll_dispatch_update(enum qb_loop_priority p, int32_t fd, int32_t evts,
515 void *data, qb_ipcs_dispatch_fn_t fn, int32_t add)
516 {
517 struct gio_to_qb_poll *adaptor;
518 GIOChannel *channel;
519 int32_t res = 0;
520
521 res = qb_array_index(gio_map, fd, (void **)&adaptor);
522 if (res < 0) {
523 crm_err("Array lookup failed for fd=%d: %d", fd, res);
524 return res;
525 }
526
527 crm_trace("Adding fd=%d to mainloop as adaptor %p", fd, adaptor);
528
529 if (add && adaptor->source) {
530 crm_err("Adaptor for descriptor %d is still in-use", fd);
531 return -EEXIST;
532 }
533 if (!add && !adaptor->is_used) {
534 crm_err("Adaptor for descriptor %d is not in-use", fd);
535 return -ENOENT;
536 }
537
538
539 channel = g_io_channel_unix_new(fd);
540 if (!channel) {
541 crm_err("No memory left to add fd=%d", fd);
542 return -ENOMEM;
543 }
544
545 if (adaptor->source) {
546 g_source_remove(adaptor->source);
547 adaptor->source = 0;
548 }
549
550
551 evts |= (G_IO_HUP | G_IO_NVAL | G_IO_ERR);
552
553 adaptor->fn = fn;
554 adaptor->events = evts;
555 adaptor->data = data;
556 adaptor->p = p;
557 adaptor->is_used++;
558 adaptor->source =
559 g_io_add_watch_full(channel, conv_prio_libqb2glib(p), evts,
560 gio_read_socket, adaptor, gio_poll_destroy);
561
562
563
564
565
566
567
568
569
570
571 g_io_channel_unref(channel);
572
573 crm_trace("Added to mainloop with gsource id=%d", adaptor->source);
574 if (adaptor->source > 0) {
575 return 0;
576 }
577
578 return -EINVAL;
579 }
580
581 static int32_t
582 gio_poll_dispatch_add(enum qb_loop_priority p, int32_t fd, int32_t evts,
583 void *data, qb_ipcs_dispatch_fn_t fn)
584 {
585 return gio_poll_dispatch_update(p, fd, evts, data, fn, QB_TRUE);
586 }
587
588 static int32_t
589 gio_poll_dispatch_mod(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_FALSE);
593 }
594
595 static int32_t
596 gio_poll_dispatch_del(int32_t fd)
597 {
598 struct gio_to_qb_poll *adaptor;
599
600 crm_trace("Looking for fd=%d", fd);
601 if (qb_array_index(gio_map, fd, (void **)&adaptor) == 0) {
602 if (adaptor->source) {
603 g_source_remove(adaptor->source);
604 adaptor->source = 0;
605 }
606 }
607 return 0;
608 }
609
610 struct qb_ipcs_poll_handlers gio_poll_funcs = {
611 .job_add = NULL,
612 .dispatch_add = gio_poll_dispatch_add,
613 .dispatch_mod = gio_poll_dispatch_mod,
614 .dispatch_del = gio_poll_dispatch_del,
615 };
616
617 static enum qb_ipc_type
618 pick_ipc_type(enum qb_ipc_type requested)
619 {
620 const char *env = getenv("PCMK_ipc_type");
621
622 if (env && strcmp("shared-mem", env) == 0) {
623 return QB_IPC_SHM;
624 } else if (env && strcmp("socket", env) == 0) {
625 return QB_IPC_SOCKET;
626 } else if (env && strcmp("posix", env) == 0) {
627 return QB_IPC_POSIX_MQ;
628 } else if (env && strcmp("sysv", env) == 0) {
629 return QB_IPC_SYSV_MQ;
630 } else if (requested == QB_IPC_NATIVE) {
631
632
633
634
635
636
637 return QB_IPC_SHM;
638 }
639 return requested;
640 }
641
642 qb_ipcs_service_t *
643 mainloop_add_ipc_server(const char *name, enum qb_ipc_type type,
644 struct qb_ipcs_service_handlers *callbacks)
645 {
646 return mainloop_add_ipc_server_with_prio(name, type, callbacks, QB_LOOP_MED);
647 }
648
649 qb_ipcs_service_t *
650 mainloop_add_ipc_server_with_prio(const char *name, enum qb_ipc_type type,
651 struct qb_ipcs_service_handlers *callbacks,
652 enum qb_loop_priority prio)
653 {
654 int rc = 0;
655 qb_ipcs_service_t *server = NULL;
656
657 if (gio_map == NULL) {
658 gio_map = qb_array_create_2(64, sizeof(struct gio_to_qb_poll), 1);
659 }
660
661 server = qb_ipcs_create(name, 0, pick_ipc_type(type), callbacks);
662
663 if (server == NULL) {
664 crm_err("Could not create %s IPC server: %s (%d)", name, pcmk_strerror(rc), rc);
665 return NULL;
666 }
667
668 if (prio != QB_LOOP_MED) {
669 qb_ipcs_request_rate_limit(server, conv_libqb_prio2ratelimit(prio));
670 }
671
672 #ifdef HAVE_IPCS_GET_BUFFER_SIZE
673
674 qb_ipcs_enforce_buffer_size(server, crm_ipc_default_buffer_size());
675 #endif
676
677 qb_ipcs_poll_handlers_set(server, &gio_poll_funcs);
678
679 rc = qb_ipcs_run(server);
680 if (rc < 0) {
681 crm_err("Could not start %s IPC server: %s (%d)", name, pcmk_strerror(rc), rc);
682 return NULL;
683 }
684
685 return server;
686 }
687
688 void
689 mainloop_del_ipc_server(qb_ipcs_service_t * server)
690 {
691 if (server) {
692 qb_ipcs_destroy(server);
693 }
694 }
695
696 struct mainloop_io_s {
697 char *name;
698 void *userdata;
699
700 int fd;
701 guint source;
702 crm_ipc_t *ipc;
703 GIOChannel *channel;
704
705 int (*dispatch_fn_ipc) (const char *buffer, ssize_t length, gpointer userdata);
706 int (*dispatch_fn_io) (gpointer userdata);
707 void (*destroy_fn) (gpointer userdata);
708
709 };
710
711 static gboolean
712 mainloop_gio_callback(GIOChannel * gio, GIOCondition condition, gpointer data)
713 {
714 gboolean keep = TRUE;
715 mainloop_io_t *client = data;
716
717 CRM_ASSERT(client->fd == g_io_channel_unix_get_fd(gio));
718
719 if (condition & G_IO_IN) {
720 if (client->ipc) {
721 long rc = 0;
722 int max = 10;
723
724 do {
725 rc = crm_ipc_read(client->ipc);
726 if (rc <= 0) {
727 crm_trace("Message acquisition from %s[%p] failed: %s (%ld)",
728 client->name, client, pcmk_strerror(rc), rc);
729
730 } else if (client->dispatch_fn_ipc) {
731 const char *buffer = crm_ipc_buffer(client->ipc);
732
733 crm_trace("New message from %s[%p] = %ld (I/O condition=%d)", client->name, client, rc, condition);
734 if (client->dispatch_fn_ipc(buffer, rc, client->userdata) < 0) {
735 crm_trace("Connection to %s no longer required", client->name);
736 keep = FALSE;
737 }
738 }
739
740 } while (keep && rc > 0 && --max > 0);
741
742 } else {
743 crm_trace("New message from %s[%p] %u", client->name, client, condition);
744 if (client->dispatch_fn_io) {
745 if (client->dispatch_fn_io(client->userdata) < 0) {
746 crm_trace("Connection to %s no longer required", client->name);
747 keep = FALSE;
748 }
749 }
750 }
751 }
752
753 if (client->ipc && crm_ipc_connected(client->ipc) == FALSE) {
754 crm_err("Connection to %s closed " CRM_XS "client=%p condition=%d",
755 client->name, client, condition);
756 keep = FALSE;
757
758 } else if (condition & (G_IO_HUP | G_IO_NVAL | G_IO_ERR)) {
759 crm_trace("The connection %s[%p] has been closed (I/O condition=%d)",
760 client->name, client, condition);
761 keep = FALSE;
762
763 } else if ((condition & G_IO_IN) == 0) {
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791 crm_err("Strange condition: %d", condition);
792 }
793
794
795
796
797 return keep;
798 }
799
800 static void
801 mainloop_gio_destroy(gpointer c)
802 {
803 mainloop_io_t *client = c;
804 char *c_name = strdup(client->name);
805
806
807
808
809 crm_trace("Destroying client %s[%p]", c_name, c);
810
811 if (client->ipc) {
812 crm_ipc_close(client->ipc);
813 }
814
815 if (client->destroy_fn) {
816 void (*destroy_fn) (gpointer userdata) = client->destroy_fn;
817
818 client->destroy_fn = NULL;
819 destroy_fn(client->userdata);
820 }
821
822 if (client->ipc) {
823 crm_ipc_t *ipc = client->ipc;
824
825 client->ipc = NULL;
826 crm_ipc_destroy(ipc);
827 }
828
829 crm_trace("Destroyed client %s[%p]", c_name, c);
830
831 free(client->name); client->name = NULL;
832 free(client);
833
834 free(c_name);
835 }
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855 int
856 pcmk__add_mainloop_ipc(crm_ipc_t *ipc, int priority, void *userdata,
857 struct ipc_client_callbacks *callbacks,
858 mainloop_io_t **source)
859 {
860 CRM_CHECK((ipc != NULL) && (callbacks != NULL), return EINVAL);
861
862 if (!crm_ipc_connect(ipc)) {
863 return ENOTCONN;
864 }
865 *source = mainloop_add_fd(crm_ipc_name(ipc), priority, crm_ipc_get_fd(ipc),
866 userdata, NULL);
867 if (*source == NULL) {
868 int rc = errno;
869
870 crm_ipc_close(ipc);
871 return rc;
872 }
873 (*source)->ipc = ipc;
874 (*source)->destroy_fn = callbacks->destroy;
875 (*source)->dispatch_fn_ipc = callbacks->dispatch;
876 return pcmk_rc_ok;
877 }
878
879 mainloop_io_t *
880 mainloop_add_ipc_client(const char *name, int priority, size_t max_size,
881 void *userdata, struct ipc_client_callbacks *callbacks)
882 {
883 crm_ipc_t *ipc = crm_ipc_new(name, max_size);
884 mainloop_io_t *source = NULL;
885 int rc = pcmk__add_mainloop_ipc(ipc, priority, userdata, callbacks,
886 &source);
887
888 if (rc != pcmk_rc_ok) {
889 if (crm_log_level == LOG_STDOUT) {
890 fprintf(stderr, "Connection to %s failed: %s",
891 name, pcmk_rc_str(rc));
892 }
893 crm_ipc_destroy(ipc);
894 return NULL;
895 }
896 return source;
897 }
898
899 void
900 mainloop_del_ipc_client(mainloop_io_t * client)
901 {
902 mainloop_del_fd(client);
903 }
904
905 crm_ipc_t *
906 mainloop_get_ipc_client(mainloop_io_t * client)
907 {
908 if (client) {
909 return client->ipc;
910 }
911 return NULL;
912 }
913
914 mainloop_io_t *
915 mainloop_add_fd(const char *name, int priority, int fd, void *userdata,
916 struct mainloop_fd_callbacks * callbacks)
917 {
918 mainloop_io_t *client = NULL;
919
920 if (fd >= 0) {
921 client = calloc(1, sizeof(mainloop_io_t));
922 if (client == NULL) {
923 return NULL;
924 }
925 client->name = strdup(name);
926 client->userdata = userdata;
927
928 if (callbacks) {
929 client->destroy_fn = callbacks->destroy;
930 client->dispatch_fn_io = callbacks->dispatch;
931 }
932
933 client->fd = fd;
934 client->channel = g_io_channel_unix_new(fd);
935 client->source =
936 g_io_add_watch_full(client->channel, priority,
937 (G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR), mainloop_gio_callback,
938 client, mainloop_gio_destroy);
939
940
941
942
943
944
945
946
947
948
949 g_io_channel_unref(client->channel);
950 crm_trace("Added connection %d for %s[%p].%d", client->source, client->name, client, fd);
951 } else {
952 errno = EINVAL;
953 }
954
955 return client;
956 }
957
958 void
959 mainloop_del_fd(mainloop_io_t * client)
960 {
961 if (client != NULL) {
962 crm_trace("Removing client %s[%p]", client->name, client);
963 if (client->source) {
964
965
966
967 g_source_remove(client->source);
968 }
969 }
970 }
971
972 static GListPtr child_list = NULL;
973
974 pid_t
975 mainloop_child_pid(mainloop_child_t * child)
976 {
977 return child->pid;
978 }
979
980 const char *
981 mainloop_child_name(mainloop_child_t * child)
982 {
983 return child->desc;
984 }
985
986 int
987 mainloop_child_timeout(mainloop_child_t * child)
988 {
989 return child->timeout;
990 }
991
992 void *
993 mainloop_child_userdata(mainloop_child_t * child)
994 {
995 return child->privatedata;
996 }
997
998 void
999 mainloop_clear_child_userdata(mainloop_child_t * child)
1000 {
1001 child->privatedata = NULL;
1002 }
1003
1004
1005 static void
1006 child_free(mainloop_child_t *child)
1007 {
1008 if (child->timerid != 0) {
1009 crm_trace("Removing timer %d", child->timerid);
1010 g_source_remove(child->timerid);
1011 child->timerid = 0;
1012 }
1013 free(child->desc);
1014 free(child);
1015 }
1016
1017
1018 static int
1019 child_kill_helper(mainloop_child_t *child)
1020 {
1021 int rc;
1022 if (child->flags & mainloop_leave_pid_group) {
1023 crm_debug("Kill pid %d only. leave group intact.", child->pid);
1024 rc = kill(child->pid, SIGKILL);
1025 } else {
1026 crm_debug("Kill pid %d's group", child->pid);
1027 rc = kill(-child->pid, SIGKILL);
1028 }
1029
1030 if (rc < 0) {
1031 if (errno != ESRCH) {
1032 crm_perror(LOG_ERR, "kill(%d, KILL) failed", child->pid);
1033 }
1034 return -errno;
1035 }
1036 return 0;
1037 }
1038
1039 static gboolean
1040 child_timeout_callback(gpointer p)
1041 {
1042 mainloop_child_t *child = p;
1043 int rc = 0;
1044
1045 child->timerid = 0;
1046 if (child->timeout) {
1047 crm_crit("%s process (PID %d) will not die!", child->desc, (int)child->pid);
1048 return FALSE;
1049 }
1050
1051 rc = child_kill_helper(child);
1052 if (rc == -ESRCH) {
1053
1054 return FALSE;
1055 }
1056
1057 child->timeout = TRUE;
1058 crm_warn("%s process (PID %d) timed out", child->desc, (int)child->pid);
1059
1060 child->timerid = g_timeout_add(5000, child_timeout_callback, child);
1061 return FALSE;
1062 }
1063
1064 static bool
1065 child_waitpid(mainloop_child_t *child, int flags)
1066 {
1067 int rc = 0;
1068 int core = 0;
1069 int signo = 0;
1070 int status = 0;
1071 int exitcode = 0;
1072 bool callback_needed = true;
1073
1074 rc = waitpid(child->pid, &status, flags);
1075 if (rc == 0) {
1076 crm_trace("Child process %d (%s) still active",
1077 child->pid, child->desc);
1078 callback_needed = false;
1079
1080 } else if (rc != child->pid) {
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090 signo = SIGCHLD;
1091 exitcode = 1;
1092 crm_notice("Wait for child process %d (%s) interrupted: %s",
1093 child->pid, child->desc, pcmk_strerror(errno));
1094
1095 } else if (WIFEXITED(status)) {
1096 exitcode = WEXITSTATUS(status);
1097 crm_trace("Child process %d (%s) exited with status %d",
1098 child->pid, child->desc, exitcode);
1099
1100 } else if (WIFSIGNALED(status)) {
1101 signo = WTERMSIG(status);
1102 crm_trace("Child process %d (%s) exited with signal %d (%s)",
1103 child->pid, child->desc, signo, strsignal(signo));
1104
1105 #ifdef WCOREDUMP
1106 } else if (WCOREDUMP(status)) {
1107 core = 1;
1108 crm_err("Child process %d (%s) dumped core",
1109 child->pid, child->desc);
1110 #endif
1111
1112 } else {
1113 crm_trace("Child process %d (%s) stopped or continued",
1114 child->pid, child->desc);
1115 callback_needed = false;
1116 }
1117
1118 if (callback_needed && child->callback) {
1119 child->callback(child, child->pid, core, signo, exitcode);
1120 }
1121 return callback_needed;
1122 }
1123
1124 static void
1125 child_death_dispatch(int signal)
1126 {
1127 for (GList *iter = child_list; iter; ) {
1128 GList *saved = iter;
1129 mainloop_child_t *child = iter->data;
1130
1131 iter = iter->next;
1132 if (child_waitpid(child, WNOHANG)) {
1133 crm_trace("Removing completed process %d from child list",
1134 child->pid);
1135 child_list = g_list_remove_link(child_list, saved);
1136 g_list_free(saved);
1137 child_free(child);
1138 }
1139 }
1140 }
1141
1142 static gboolean
1143 child_signal_init(gpointer p)
1144 {
1145 crm_trace("Installed SIGCHLD handler");
1146
1147 mainloop_add_signal(SIGCHLD, child_death_dispatch);
1148
1149
1150 child_death_dispatch(SIGCHLD);
1151 return FALSE;
1152 }
1153
1154 gboolean
1155 mainloop_child_kill(pid_t pid)
1156 {
1157 GListPtr iter;
1158 mainloop_child_t *child = NULL;
1159 mainloop_child_t *match = NULL;
1160
1161
1162 int waitflags = 0, rc = 0;
1163
1164 for (iter = child_list; iter != NULL && match == NULL; iter = iter->next) {
1165 child = iter->data;
1166 if (pid == child->pid) {
1167 match = child;
1168 }
1169 }
1170
1171 if (match == NULL) {
1172 return FALSE;
1173 }
1174
1175 rc = child_kill_helper(match);
1176 if(rc == -ESRCH) {
1177
1178
1179
1180
1181
1182 crm_trace("Waiting for signal that child process %d completed",
1183 match->pid);
1184 return TRUE;
1185
1186 } else if(rc != 0) {
1187
1188
1189
1190 waitflags = WNOHANG;
1191 }
1192
1193 if (!child_waitpid(match, waitflags)) {
1194
1195 return FALSE;
1196 }
1197
1198 child_list = g_list_remove(child_list, match);
1199 child_free(match);
1200 return TRUE;
1201 }
1202
1203
1204
1205
1206
1207
1208
1209
1210 void
1211 mainloop_child_add_with_flags(pid_t pid, int timeout, const char *desc, void *privatedata, enum mainloop_child_flags flags,
1212 void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode))
1213 {
1214 static bool need_init = TRUE;
1215 mainloop_child_t *child = g_new(mainloop_child_t, 1);
1216
1217 child->pid = pid;
1218 child->timerid = 0;
1219 child->timeout = FALSE;
1220 child->privatedata = privatedata;
1221 child->callback = callback;
1222 child->flags = flags;
1223
1224 if(desc) {
1225 child->desc = strdup(desc);
1226 }
1227
1228 if (timeout) {
1229 child->timerid = g_timeout_add(timeout, child_timeout_callback, child);
1230 }
1231
1232 child_list = g_list_append(child_list, child);
1233
1234 if(need_init) {
1235 need_init = FALSE;
1236
1237
1238
1239
1240 g_timeout_add(1, child_signal_init, NULL);
1241 }
1242 }
1243
1244 void
1245 mainloop_child_add(pid_t pid, int timeout, const char *desc, void *privatedata,
1246 void (*callback) (mainloop_child_t * p, pid_t pid, int core, int signo, int exitcode))
1247 {
1248 mainloop_child_add_with_flags(pid, timeout, desc, privatedata, 0, callback);
1249 }
1250
1251 struct mainloop_timer_s {
1252 guint id;
1253 guint period_ms;
1254 bool repeat;
1255 char *name;
1256 GSourceFunc cb;
1257 void *userdata;
1258 };
1259
1260 static gboolean
1261 mainloop_timer_cb(gpointer user_data)
1262 {
1263 int id = 0;
1264 bool repeat = FALSE;
1265 struct mainloop_timer_s *t = user_data;
1266
1267 CRM_ASSERT(t != NULL);
1268
1269 id = t->id;
1270 t->id = 0;
1271
1272
1273
1274 if(t->cb) {
1275 crm_trace("Invoking callbacks for timer %s", t->name);
1276 repeat = t->repeat;
1277 if(t->cb(t->userdata) == FALSE) {
1278 crm_trace("Timer %s complete", t->name);
1279 repeat = FALSE;
1280 }
1281 }
1282
1283 if(repeat) {
1284
1285 t->id = id;
1286 }
1287
1288 return repeat;
1289 }
1290
1291 bool
1292 mainloop_timer_running(mainloop_timer_t *t)
1293 {
1294 if(t && t->id != 0) {
1295 return TRUE;
1296 }
1297 return FALSE;
1298 }
1299
1300 void
1301 mainloop_timer_start(mainloop_timer_t *t)
1302 {
1303 mainloop_timer_stop(t);
1304 if(t && t->period_ms > 0) {
1305 crm_trace("Starting timer %s", t->name);
1306 t->id = g_timeout_add(t->period_ms, mainloop_timer_cb, t);
1307 }
1308 }
1309
1310 void
1311 mainloop_timer_stop(mainloop_timer_t *t)
1312 {
1313 if(t && t->id != 0) {
1314 crm_trace("Stopping timer %s", t->name);
1315 g_source_remove(t->id);
1316 t->id = 0;
1317 }
1318 }
1319
1320 guint
1321 mainloop_timer_set_period(mainloop_timer_t *t, guint period_ms)
1322 {
1323 guint last = 0;
1324
1325 if(t) {
1326 last = t->period_ms;
1327 t->period_ms = period_ms;
1328 }
1329
1330 if(t && t->id != 0 && last != t->period_ms) {
1331 mainloop_timer_start(t);
1332 }
1333 return last;
1334 }
1335
1336 mainloop_timer_t *
1337 mainloop_timer_add(const char *name, guint period_ms, bool repeat, GSourceFunc cb, void *userdata)
1338 {
1339 mainloop_timer_t *t = calloc(1, sizeof(mainloop_timer_t));
1340
1341 if(t) {
1342 if(name) {
1343 t->name = crm_strdup_printf("%s-%u-%d", name, period_ms, repeat);
1344 } else {
1345 t->name = crm_strdup_printf("%p-%u-%d", t, period_ms, repeat);
1346 }
1347 t->id = 0;
1348 t->period_ms = period_ms;
1349 t->repeat = repeat;
1350 t->cb = cb;
1351 t->userdata = userdata;
1352 crm_trace("Created timer %s with %p %p", t->name, userdata, t->userdata);
1353 }
1354 return t;
1355 }
1356
1357 void
1358 mainloop_timer_del(mainloop_timer_t *t)
1359 {
1360 if(t) {
1361 crm_trace("Destroying timer %s", t->name);
1362 mainloop_timer_stop(t);
1363 free(t->name);
1364 free(t);
1365 }
1366 }
1367
1368
1369
1370
1371
1372 static gboolean
1373 drain_timeout_cb(gpointer user_data)
1374 {
1375 bool *timeout_popped = (bool*) user_data;
1376
1377 *timeout_popped = TRUE;
1378 return FALSE;
1379 }
1380
1381
1382
1383
1384
1385
1386
1387 void
1388 pcmk_quit_main_loop(GMainLoop *mloop, unsigned int n)
1389 {
1390 if ((mloop != NULL) && g_main_loop_is_running(mloop)) {
1391 GMainContext *ctx = g_main_loop_get_context(mloop);
1392
1393
1394
1395
1396 for (int i = 0; (i < n) && g_main_context_pending(ctx); ++i) {
1397 g_main_context_dispatch(ctx);
1398 }
1399 g_main_loop_quit(mloop);
1400 }
1401 }
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415 void
1416 pcmk_drain_main_loop(GMainLoop *mloop, guint timer_ms, bool (*check)(guint))
1417 {
1418 bool timeout_popped = FALSE;
1419 guint timer = 0;
1420 GMainContext *ctx = NULL;
1421
1422 CRM_CHECK(mloop && check, return);
1423
1424 ctx = g_main_loop_get_context(mloop);
1425 if (ctx) {
1426 time_t start_time = time(NULL);
1427
1428 timer = g_timeout_add(timer_ms, drain_timeout_cb, &timeout_popped);
1429 while (!timeout_popped
1430 && check(timer_ms - (time(NULL) - start_time) * 1000)) {
1431 g_main_context_iteration(ctx, TRUE);
1432 }
1433 }
1434 if (!timeout_popped && (timer > 0)) {
1435 g_source_remove(timer);
1436 }
1437 }
1438
1439
1440 gboolean crm_signal(int sig, void (*dispatch) (int sig));
1441
1442
1443
1444
1445
1446 gboolean
1447 crm_signal(int sig, void (*dispatch) (int sig))
1448 {
1449 return crm_signal_handler(sig, dispatch) != SIG_ERR;
1450 }
1451