1 /*
2 * Copyright 2004-2026 the Pacemaker project contributors
3 *
4 * The version control history for this file may have further details.
5 *
6 * This source code is licensed under the GNU Lesser General Public License
7 * version 2.1 or later (LGPLv2.1+) WITHOUT ANY WARRANTY.
8 */
9
10 #include <crm_internal.h>
11
12 #include <stdbool.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <signal.h>
16 #include <errno.h>
17
18 #include <sys/wait.h>
19
20 #include <crm/crm.h>
21 #include <crm/common/xml.h>
22 #include <crm/common/mainloop.h>
23
24 #include <qb/qbarray.h>
25
26 struct trigger_s {
27 GSource source;
28 gboolean running;
29 gboolean trigger;
30 void *user_data;
31 unsigned int id;
32 };
33
34 struct mainloop_timer_s {
35 unsigned int id;
36 unsigned int period_ms;
37 bool repeat;
38 char *name;
39 GSourceFunc cb;
40 void *userdata;
41 };
42
43 static GHashTable *mainloop_children = NULL;
44 static qb_array_t *gio_map = NULL;
45
46 static void
47 child_free(mainloop_child_t *child)
48 {
49 if (child->timerid != 0) {
50 pcmk__trace("Removing timer %d", child->timerid);
51 g_source_remove(child->timerid);
52 child->timerid = 0;
53 }
54
55 free(child->desc);
56 free(child);
57 }
58
59 static gboolean
60 crm_trigger_prepare(GSource *source, int *timeout)
61 {
62 crm_trigger_t *trig = (crm_trigger_t *) source;
63
64 /* cluster-glue's FD and IPC related sources make use of
65 * g_source_add_poll() but do not set a timeout in their prepare
66 * functions
67 *
68 * This means mainloop's poll() will block until an event for one
69 * of these sources occurs - any /other/ type of source, such as
70 * this one or g_idle_*, that doesn't use g_source_add_poll() is
71 * S-O-L and won't be processed until there is something fd-based
72 * happens.
73 *
74 * Luckily the timeout we can set here affects all sources and
75 * puts an upper limit on how long poll() can take.
76 *
77 * So unconditionally set a small-ish timeout, not too small that
78 * we're in constant motion, which will act as an upper bound on
79 * how long the signal handling might be delayed for.
80 */
81 *timeout = 500; /* Timeout in ms */
82
83 return trig->trigger;
84 }
85
86 static gboolean
87 crm_trigger_check(GSource * source)
88 {
89 crm_trigger_t *trig = (crm_trigger_t *) source;
90
91 return trig->trigger;
92 }
93
94 /*!
95 * \internal
96 * \brief GSource dispatch function for crm_trigger_t
97 *
98 * \param[in] source crm_trigger_t being dispatched
99 * \param[in] callback Callback passed at source creation
100 * \param[in,out] userdata User data passed at source creation
101 *
102 * \return G_SOURCE_REMOVE to remove source, G_SOURCE_CONTINUE to keep it
103 */
104 static gboolean
105 crm_trigger_dispatch(GSource *source, GSourceFunc callback, void *userdata)
106 {
107 gboolean rc = G_SOURCE_CONTINUE;
108 crm_trigger_t *trig = (crm_trigger_t *) source;
109
110 if (trig->running) {
111 /* Wait until the existing job is complete before starting the next one */
112 return G_SOURCE_CONTINUE;
113 }
114 trig->trigger = FALSE;
115
116 if (callback) {
117 int callback_rc = callback(trig->user_data);
118
119 if (callback_rc < 0) {
120 pcmk__trace("Trigger handler %p not yet complete", trig);
121 trig->running = TRUE;
122 } else if (callback_rc == 0) {
123 rc = G_SOURCE_REMOVE;
124 }
125 }
126 return rc;
127 }
128
129 static void
130 crm_trigger_finalize(GSource * source)
131 {
132 pcmk__trace("Trigger %p destroyed", source);
133 }
134
135 static GSourceFuncs crm_trigger_funcs = {
136 crm_trigger_prepare,
137 crm_trigger_check,
138 crm_trigger_dispatch,
139 crm_trigger_finalize,
140 };
141
142 static crm_trigger_t *
143 mainloop_setup_trigger(GSource * source, int priority,
144 int (*dispatch)(void *user_data), void *userdata)
145 {
146 crm_trigger_t *trigger = NULL;
147
148 trigger = (crm_trigger_t *) source;
149
150 trigger->id = 0;
151 trigger->trigger = FALSE;
152 trigger->user_data = userdata;
153
154 if (dispatch) {
155 g_source_set_callback(source, dispatch, trigger, NULL);
156 }
157
158 g_source_set_priority(source, priority);
159 g_source_set_can_recurse(source, FALSE);
160
161 trigger->id = g_source_attach(source, NULL);
162 return trigger;
163 }
164
165 void
166 mainloop_trigger_complete(crm_trigger_t * trig)
167 {
168 pcmk__trace("Trigger handler %p complete", trig);
169 trig->running = FALSE;
170 }
171
172 /*!
173 * \brief Create a trigger to be used as a mainloop source
174 *
175 * \param[in] priority Relative priority of source (lower number is higher priority)
176 * \param[in] dispatch Trigger dispatch function (should return 0 to remove the
177 * trigger from the mainloop, -1 if the trigger should be
178 * kept but the job is still running and not complete, and
179 * 1 if the trigger should be kept and the job is complete)
180 * \param[in] userdata Pointer to pass to \p dispatch
181 *
182 * \return Newly allocated mainloop source for trigger
183 */
184 crm_trigger_t *
185 mainloop_add_trigger(int priority, int (*dispatch) (void *user_data),
186 void *userdata)
187 {
188 GSource *source = NULL;
189
190 pcmk__assert(sizeof(crm_trigger_t) > sizeof(GSource));
191 source = g_source_new(&crm_trigger_funcs, sizeof(crm_trigger_t));
192
193 return mainloop_setup_trigger(source, priority, dispatch, userdata);
194 }
195
196 void
197 mainloop_set_trigger(crm_trigger_t * source)
198 {
199 if(source) {
200 source->trigger = TRUE;
201 }
202 }
203
204 gboolean
205 mainloop_destroy_trigger(crm_trigger_t * source)
206 {
207 GSource *gs = NULL;
208
209 if(source == NULL) {
210 return TRUE;
211 }
212
213 gs = (GSource *)source;
214
215 g_source_destroy(gs); /* Remove from mainloop, ref_count-- */
216 g_source_unref(gs); /* The caller no longer carries a reference to source
217 *
218 * At this point the source should be free'd,
219 * unless we're currently processing said
220 * source, in which case mainloop holds an
221 * additional reference and it will be free'd
222 * once our processing completes
223 */
224 return TRUE;
225 }
226
227 // Define a custom glib source for signal handling
228
229 // Data structure for custom glib source
230 typedef struct {
231 crm_trigger_t trigger; // trigger that invoked source (must be first)
232 void (*handler) (int sig); // signal handler
233 int signal; // signal that was received
234 } crm_signal_t;
235
236 // Table to associate signal handlers with signal numbers
237 static crm_signal_t *crm_signals[NSIG];
238
239 /*!
240 * \internal
241 * \brief Dispatch an event from custom glib source for signals
242 *
243 * Given an signal event, clear the event trigger and call any registered
244 * signal handler.
245 *
246 * \param[in] source glib source that triggered this dispatch
247 * \param[in] callback (ignored)
248 * \param[in] userdata (ignored)
249 */
250 static gboolean
251 crm_signal_dispatch(GSource *source, GSourceFunc callback, void *userdata)
252 {
253 crm_signal_t *sig = (crm_signal_t *) source;
254
255 if(sig->signal != SIGCHLD) {
256 pcmk__notice("Caught '%s' signal " QB_XS " %d (%s handler)",
257 strsignal(sig->signal), sig->signal,
258 ((sig->handler != NULL)? "invoking" : "no"));
259 }
260
261 sig->trigger.trigger = FALSE;
262 if (sig->handler) {
263 sig->handler(sig->signal);
264 }
265 return TRUE;
266 }
267
268 /*!
269 * \internal
270 * \brief Handle a signal by setting a trigger for signal source
271 *
272 * \param[in] sig Signal number that was received
273 *
274 * \note This is the true signal handler for the mainloop signal source, and
275 * must be async-safe.
276 */
277 static void
278 mainloop_signal_handler(int sig)
279 {
280 if (sig > 0 && sig < NSIG && crm_signals[sig] != NULL) {
281 mainloop_set_trigger((crm_trigger_t *) crm_signals[sig]);
282 }
283 }
284
285 // Functions implementing our custom glib source for signal handling
286 static GSourceFuncs crm_signal_funcs = {
287 crm_trigger_prepare,
288 crm_trigger_check,
289 crm_signal_dispatch,
290 crm_trigger_finalize,
291 };
292
293 /*!
294 * \internal
295 * \brief Set a true signal handler
296 *
297 * signal()-like interface to sigaction()
298 *
299 * \param[in] sig Signal number to register handler for
300 * \param[in] dispatch Signal handler
301 *
302 * \return The previous value of the signal handler, or SIG_ERR on error
303 * \note The dispatch function must be async-safe.
304 */
305 sighandler_t
306 crm_signal_handler(int sig, sighandler_t dispatch)
307 {
308 sigset_t mask;
309 struct sigaction sa;
310 struct sigaction old;
311
312 if (sigemptyset(&mask) < 0) {
313 pcmk__err("Could not %sset handler for signal %d: %s",
314 ((dispatch == NULL)? "un" : ""), sig, strerror(errno));
315 return SIG_ERR;
316 }
317
318 memset(&sa, 0, sizeof(struct sigaction));
319 sa.sa_handler = dispatch;
320 sa.sa_flags = SA_RESTART;
321 sa.sa_mask = mask;
322
323 if (sigaction(sig, &sa, &old) < 0) {
324 pcmk__err("Could not %sset handler for signal %d: %s",
325 ((dispatch == NULL)? "un" : ""), sig, strerror(errno));
326 return SIG_ERR;
327 }
328 return old.sa_handler;
329 }
330
331 static void
332 mainloop_destroy_signal_entry(int sig)
333 {
334 crm_signal_t *tmp = crm_signals[sig];
335
336 if (tmp != NULL) {
337 crm_signals[sig] = NULL;
338 pcmk__trace("Unregistering mainloop handler for signal %d", sig);
339 mainloop_destroy_trigger((crm_trigger_t *) tmp);
340 }
341 }
342
343 /*!
344 * \internal
345 * \brief Add a signal handler to a mainloop
346 *
347 * \param[in] sig Signal number to handle
348 * \param[in] dispatch Signal handler function (\c NULL to ignore the signal)
349 *
350 * \note The true signal handler merely sets a mainloop trigger to call this
351 * dispatch function via the mainloop. Therefore, the dispatch function
352 * does not need to be async-safe.
353 * \note The added signal handler gets freed by \c mainloop_cleanup() if it is
354 * not freed manually using \c mainloop_destroy_signal().
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 /* TERM is higher priority than other signals,
364 * signals are higher priority than other ipc.
365 * Yes, minus: smaller is "higher"
366 */
367 priority--;
368 }
369
370 if (sig >= NSIG || sig < 0) {
371 pcmk__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 pcmk__trace("Signal handler for %d is already installed", sig);
376 return TRUE;
377
378 } else if (crm_signals[sig] != NULL) {
379 pcmk__err("Different signal handler for %d is already installed", sig);
380 return FALSE;
381 }
382
383 pcmk__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 pcmk__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 pcmk__err("Signal %d is out of range", sig);
405 return FALSE;
406
407 } else if (crm_signal_handler(sig, NULL) == SIG_ERR) {
408 // Error already logged
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 /*!
419 * \internal
420 * \brief Free data structures used for the mainloop
421 *
422 * \todo This is incomplete. Free other data structures created in this file.
423 */
424 void
425 mainloop_cleanup(void)
426 {
427 g_clear_pointer(&mainloop_children, g_hash_table_destroy);
428 g_clear_pointer(&gio_map, qb_array_free);
429
430 for (int sig = 0; sig < NSIG; ++sig) {
431 mainloop_destroy_signal_entry(sig);
432 }
433 }
434
435 /*
436 * libqb...
437 */
438 struct gio_to_qb_poll {
439 int32_t is_used;
440 unsigned int source;
441 int32_t events;
442 void *data;
443 qb_ipcs_dispatch_fn_t fn;
444 enum qb_loop_priority p;
445 };
446
447 static gboolean
448 gio_read_socket(GIOChannel * gio, GIOCondition condition, void *data)
449 {
450 struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
451 int fd = g_io_channel_unix_get_fd(gio);
452
453 pcmk__trace("%p.%d %d", data, fd, condition);
454
455 /* if this assert get's hit, then there is a race condition between
456 * when we destroy a fd and when mainloop actually gives it up */
457 pcmk__assert(adaptor->is_used > 0);
458
459 return (adaptor->fn(fd, condition, adaptor->data) == 0);
460 }
461
462 static void
463 gio_poll_destroy(void *data)
464 {
465 struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
466
467 adaptor->is_used--;
468 pcmk__assert(adaptor->is_used >= 0);
469
470 if (adaptor->is_used == 0) {
471 pcmk__trace("Marking adaptor %p unused", adaptor);
472 adaptor->source = 0;
473 }
474 }
475
476 /*!
477 * \internal
478 * \brief Convert libqb's poll priority into GLib's one
479 *
480 * \param[in] prio libqb's poll priority (#QB_LOOP_MED assumed as fallback)
481 *
482 * \return best matching GLib's priority
483 */
484 static int
485 conv_prio_libqb2glib(enum qb_loop_priority prio)
486 {
487 switch (prio) {
488 case QB_LOOP_LOW: return G_PRIORITY_LOW;
489 case QB_LOOP_HIGH: return G_PRIORITY_HIGH;
490 default: return G_PRIORITY_DEFAULT; // QB_LOOP_MED
491 }
492 }
493
494 /*!
495 * \internal
496 * \brief Convert libqb's poll priority to rate limiting spec
497 *
498 * \param[in] prio libqb's poll priority (#QB_LOOP_MED assumed as fallback)
499 *
500 * \return best matching rate limiting spec
501 * \note This is the inverse of libqb's qb_ipcs_request_rate_limit().
502 */
503 static enum qb_ipcs_rate_limit
504 conv_libqb_prio2ratelimit(enum qb_loop_priority prio)
505 {
506 switch (prio) {
507 case QB_LOOP_LOW: return QB_IPCS_RATE_SLOW;
508 case QB_LOOP_HIGH: return QB_IPCS_RATE_FAST;
509 default: return QB_IPCS_RATE_NORMAL; // QB_LOOP_MED
510 }
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 pcmk__err("Array lookup failed for fd=%d: %d", fd, res);
524 return res;
525 }
526
527 pcmk__trace("Adding fd=%d to mainloop as adaptor %p", fd, adaptor);
528
529 if (add && adaptor->source) {
530 pcmk__err("Adaptor for descriptor %d is still in-use", fd);
531 return -EEXIST;
532 }
533 if (!add && !adaptor->is_used) {
534 pcmk__err("Adaptor for descriptor %d is not in-use", fd);
535 return -ENOENT;
536 }
537
538 /* channel is created with ref_count = 1 */
539 channel = g_io_channel_unix_new(fd);
540 if (!channel) {
541 pcmk__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 /* Because unlike the poll() API, glib doesn't tell us about HUPs by default */
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 /* Now that mainloop now holds a reference to channel,
563 * thanks to g_io_add_watch_full(), drop ours from g_io_channel_unix_new().
564 *
565 * This means that channel will be free'd by:
566 * g_main_context_dispatch()
567 * -> g_source_destroy_internal()
568 * -> g_source_callback_unref()
569 * shortly after gio_poll_destroy() completes
570 */
571 g_io_channel_unref(channel);
572
573 pcmk__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 pcmk__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 qb_ipcs_service_t *
618 mainloop_add_ipc_server(const char *name, enum qb_ipc_type type,
619 struct qb_ipcs_service_handlers *callbacks)
620 {
621 return mainloop_add_ipc_server_with_prio(name, type, callbacks, QB_LOOP_MED);
622 }
623
624 qb_ipcs_service_t *
625 mainloop_add_ipc_server_with_prio(const char *name, enum qb_ipc_type type,
626 struct qb_ipcs_service_handlers *callbacks,
627 enum qb_loop_priority prio)
628 {
629 int rc = 0;
630 qb_ipcs_service_t *server = NULL;
631
632 if (gio_map == NULL) {
633 gio_map = qb_array_create_2(64, sizeof(struct gio_to_qb_poll), 1);
634 }
635
636 server = qb_ipcs_create(name, 0, QB_IPC_SHM, callbacks);
637
638 if (server == NULL) {
639 pcmk__err("Could not create %s IPC server: %s (%d)", name,
640 pcmk_rc_str(errno), errno);
641 return NULL;
642 }
643
644 if (prio != QB_LOOP_MED) {
645 qb_ipcs_request_rate_limit(server, conv_libqb_prio2ratelimit(prio));
646 }
647
648 // Enforce a minimum IPC buffer size on all clients
649 qb_ipcs_enforce_buffer_size(server, crm_ipc_default_buffer_size());
650 qb_ipcs_poll_handlers_set(server, &gio_poll_funcs);
651
652 rc = qb_ipcs_run(server);
653 if (rc < 0) {
654 pcmk__err("Could not start %s IPC server: %s (%d)", name,
655 pcmk_strerror(rc), rc);
656 return NULL; // qb_ipcs_run() destroys server on failure
657 }
658
659 return server;
660 }
661
662 void
663 mainloop_del_ipc_server(qb_ipcs_service_t * server)
664 {
665 if (server) {
666 qb_ipcs_destroy(server);
667 }
668 }
669
670 /*!
671 * \internal
672 * \brief I/O watch callback function (GIOFunc)
673 *
674 * \param[in] gio I/O channel being watched
675 * \param[in] condition I/O condition satisfied
676 * \param[in] data User data passed when source was created
677 *
678 * \return G_SOURCE_REMOVE to remove source, G_SOURCE_CONTINUE to keep it
679 */
680 static gboolean
681 mainloop_gio_callback(GIOChannel *gio, GIOCondition condition, void *data)
682 {
683 gboolean rc = G_SOURCE_CONTINUE;
684 mainloop_io_t *client = data;
685
686 pcmk__assert(client->fd == g_io_channel_unix_get_fd(gio));
687
688 if (condition & G_IO_IN) {
689 if (client->ipc) {
690 long read_rc = 0L;
691 int max = 10;
692
693 do {
694 read_rc = crm_ipc_read(client->ipc);
695 if (read_rc <= 0) {
696 pcmk__trace("Could not read IPC message from %s: %s (%ld)",
697 client->name, pcmk_strerror(read_rc), read_rc);
698
699 if (read_rc == -EAGAIN) {
700 continue;
701 }
702
703 } else if (client->dispatch_fn_ipc) {
704 const char *buffer = crm_ipc_buffer(client->ipc);
705
706 pcmk__trace("New %ld-byte IPC message from %s after I/O "
707 "condition %d",
708 read_rc, client->name, (int) condition);
709 if (client->dispatch_fn_ipc(buffer, read_rc, client->userdata) < 0) {
710 pcmk__trace("Connection to %s no longer required",
711 client->name);
712 rc = G_SOURCE_REMOVE;
713 }
714 }
715
716 pcmk__ipc_free_client_buffer(client->ipc);
717
718 } while ((rc == G_SOURCE_CONTINUE) && (--max > 0)
719 && ((read_rc > 0) || (read_rc == -EAGAIN)));
720
721 } else {
722 pcmk__trace("New I/O event for %s after I/O condition %d",
723 client->name, (int) condition);
724 if (client->dispatch_fn_io) {
725 if (client->dispatch_fn_io(client->userdata) < 0) {
726 pcmk__trace("Connection to %s no longer required",
727 client->name);
728 rc = G_SOURCE_REMOVE;
729 }
730 }
731 }
732 }
733
734 if (client->ipc && !crm_ipc_connected(client->ipc)) {
735 pcmk__err("Connection to %s closed " QB_XS " client=%p condition=%d",
736 client->name, client, condition);
737 rc = G_SOURCE_REMOVE;
738
739 } else if (condition & (G_IO_HUP | G_IO_NVAL | G_IO_ERR)) {
740 pcmk__trace("The connection %s[%p] has been closed (I/O condition=%d)",
741 client->name, client, condition);
742 rc = G_SOURCE_REMOVE;
743
744 } else if ((condition & G_IO_IN) == 0) {
745 /*
746 #define GLIB_SYSDEF_POLLIN =1
747 #define GLIB_SYSDEF_POLLPRI =2
748 #define GLIB_SYSDEF_POLLOUT =4
749 #define GLIB_SYSDEF_POLLERR =8
750 #define GLIB_SYSDEF_POLLHUP =16
751 #define GLIB_SYSDEF_POLLNVAL =32
752
753 typedef enum
754 {
755 G_IO_IN GLIB_SYSDEF_POLLIN,
756 G_IO_OUT GLIB_SYSDEF_POLLOUT,
757 G_IO_PRI GLIB_SYSDEF_POLLPRI,
758 G_IO_ERR GLIB_SYSDEF_POLLERR,
759 G_IO_HUP GLIB_SYSDEF_POLLHUP,
760 G_IO_NVAL GLIB_SYSDEF_POLLNVAL
761 } GIOCondition;
762
763 A bitwise combination representing a condition to watch for on an event source.
764
765 G_IO_IN There is data to read.
766 G_IO_OUT Data can be written (without blocking).
767 G_IO_PRI There is urgent data to read.
768 G_IO_ERR Error condition.
769 G_IO_HUP Hung up (the connection has been broken, usually for pipes and sockets).
770 G_IO_NVAL Invalid request. The file descriptor is not open.
771 */
772 pcmk__err("Strange condition: %d", condition);
773 }
774
775 /* G_SOURCE_REMOVE results in mainloop_gio_destroy() being called
776 * just before the source is removed from mainloop
777 */
778 return rc;
779 }
780
781 static void
|
(3) Event deallocator: |
Deallocator for "struct mainloop_io_s". |
| Also see events: |
[allocation][allocation] |
782 mainloop_gio_destroy(void *c)
783 {
784 mainloop_io_t *client = c;
785 char *c_name = strdup(client->name);
786
787 /* client->source is valid but about to be destroyed (ref_count == 0) in gmain.c
788 * client->channel will still have ref_count > 0... should be == 1
789 */
790 pcmk__trace("Destroying client %s[%p]", c_name, c);
791
792 if (client->ipc) {
793 crm_ipc_close(client->ipc);
794 }
795
796 if (client->destroy_fn) {
797 void (*destroy_fn)(void *userdata) = client->destroy_fn;
798
799 client->destroy_fn = NULL;
800 destroy_fn(client->userdata);
801 }
802
803 if (client->ipc) {
804 crm_ipc_t *ipc = client->ipc;
805
806 client->ipc = NULL;
807 crm_ipc_destroy(ipc);
808 }
809
810 pcmk__trace("Destroyed client %s[%p]", c_name, c);
811
812 free(client->name);
813 free(client);
814
815 free(c_name);
816 }
817
818 /*!
819 * \brief Connect to IPC and add it as a main loop source
820 *
821 * \param[in,out] ipc IPC connection to add
822 * \param[in] priority Event source priority to use for connection
823 * \param[in] userdata Data to register with callbacks
824 * \param[in] callbacks Dispatch and destroy callbacks for connection
825 * \param[out] source Newly allocated event source
826 *
827 * \return Standard Pacemaker return code
828 *
829 * \note On failure, the caller is still responsible for ipc. On success, the
830 * caller should call mainloop_del_ipc_client() when source is no longer
831 * needed, which will lead to the disconnection of the IPC later in the
832 * main loop if it is connected. However the IPC disconnects,
833 * mainloop_gio_destroy() will free ipc and source after calling the
834 * destroy callback.
835 */
836 int
837 pcmk__add_mainloop_ipc(crm_ipc_t *ipc, int priority, void *userdata,
838 const struct ipc_client_callbacks *callbacks,
839 mainloop_io_t **source)
840 {
841 int rc = pcmk_rc_ok;
842 int fd = -1;
843 const char *ipc_name = NULL;
844
845 CRM_CHECK((ipc != NULL) && (callbacks != NULL), return EINVAL);
846
847 ipc_name = pcmk__s(crm_ipc_name(ipc), "Pacemaker");
848 rc = pcmk__connect_generic_ipc(ipc);
849 if (rc != pcmk_rc_ok) {
850 pcmk__debug("Connection to %s failed: %s", ipc_name, pcmk_rc_str(rc));
851 return rc;
852 }
853
854 rc = pcmk__ipc_fd(ipc, &fd);
855 if (rc != pcmk_rc_ok) {
856 pcmk__debug("Could not obtain file descriptor for %s IPC: %s", ipc_name,
857 pcmk_rc_str(rc));
858 crm_ipc_close(ipc);
859 return rc;
860 }
861
862 *source = mainloop_add_fd(ipc_name, priority, fd, userdata, NULL);
863 if (*source == NULL) {
864 rc = errno;
865 crm_ipc_close(ipc);
866 return rc;
867 }
868
869 (*source)->ipc = ipc;
870 (*source)->destroy_fn = callbacks->destroy;
871 (*source)->dispatch_fn_ipc = callbacks->dispatch;
872 return pcmk_rc_ok;
873 }
874
875 /*!
876 * \brief Get period for mainloop timer
877 *
878 * \param[in] timer Timer
879 *
880 * \return Period in ms
881 */
882 unsigned int
883 pcmk__mainloop_timer_get_period(const mainloop_timer_t *timer)
884 {
885 if (timer) {
886 return timer->period_ms;
887 }
888 return 0;
889 }
890
891 mainloop_io_t *
892 mainloop_add_ipc_client(const char *name, int priority, size_t max_size,
893 void *userdata, struct ipc_client_callbacks *callbacks)
894 {
895 crm_ipc_t *ipc = crm_ipc_new(name, 0);
896 mainloop_io_t *source = NULL;
897 int rc = pcmk__add_mainloop_ipc(ipc, priority, userdata, callbacks,
898 &source);
899
900 if (rc != pcmk_rc_ok) {
901 if (crm_log_level == PCMK__LOG_STDOUT) {
902 fprintf(stderr, "Connection to %s failed: %s",
903 name, pcmk_rc_str(rc));
904 }
905 crm_ipc_destroy(ipc);
906 if (rc > 0) {
907 errno = rc;
908 } else {
909 errno = ENOTCONN;
910 }
911 return NULL;
912 }
913 return source;
914 }
915
916 void
917 mainloop_del_ipc_client(mainloop_io_t * client)
918 {
919 mainloop_del_fd(client);
920 }
921
922 crm_ipc_t *
923 mainloop_get_ipc_client(mainloop_io_t * client)
924 {
925 if (client) {
926 return client->ipc;
927 }
928 return NULL;
929 }
930
931 mainloop_io_t *
932 mainloop_add_fd(const char *name, int priority, int fd, void *userdata,
933 struct mainloop_fd_callbacks * callbacks)
934 {
935 mainloop_io_t *client = NULL;
936 const GIOCondition condition = G_IO_IN|G_IO_HUP|G_IO_NVAL|G_IO_ERR;
937
938 if (fd < 0) {
939 errno = EINVAL;
940 return NULL;
941 }
942
943 client = pcmk__assert_alloc(1, sizeof(mainloop_io_t));
944 client->name = pcmk__str_copy(name);
945 client->userdata = userdata;
946
947 if (callbacks != NULL) {
948 client->destroy_fn = callbacks->destroy;
949 client->dispatch_fn_io = callbacks->dispatch;
950 }
951
952 client->fd = fd;
|
CID (unavailable; MK=b13c37cce9c4cfa0c98303204ab57333) (#1 of 1): Resource not released (INCOMPLETE_DEALLOCATOR): |
|
(1) Event allocation: |
Memory is allocated. |
|
(2) Event allocation: |
The field "client->channel" is allocated, but not released in the identified deallocator. |
| Also see events: |
[deallocator] |
953 client->channel = g_io_channel_unix_new(fd);
954 client->source = g_io_add_watch_full(client->channel, priority, condition,
955 mainloop_gio_callback, client,
956 mainloop_gio_destroy);
957
958 /* Now that mainloop now holds a reference to channel, thanks to
959 * g_io_add_watch_full(), drop ours from g_io_channel_unix_new().
960 *
961 * This means that channel will be free'd by:
962 * g_main_context_dispatch() or g_source_remove()
963 * -> g_source_destroy_internal()
964 * -> g_source_callback_unref()
965 * shortly after mainloop_gio_destroy() completes
966 */
967 g_io_channel_unref(client->channel);
968
969 pcmk__trace("Added connection %d for %s[%p].%d", client->source,
970 client->name, client, fd);
971 return client;
972 }
973
974 void
975 mainloop_del_fd(mainloop_io_t *client)
976 {
977 if ((client == NULL) || (client->source == 0)) {
978 return;
979 }
980
981 pcmk__trace("Removing client %s[%p]", client->name, client);
982
983 /* g_source_remove() marks the source as destroyed, unsets the source
984 * callback (mainloop_gio_callback()), and destroys the callback data (the
985 * client) via the notify function (mainloop_gio_destroy()). We can rely on
986 * mainloop_gio_callback() not getting called again for this source, and on
987 * the client being destroyed.
988 */
989 g_source_remove(client->source);
990 }
991
992 pid_t
993 mainloop_child_pid(mainloop_child_t * child)
994 {
995 return child->pid;
996 }
997
998 const char *
999 mainloop_child_name(mainloop_child_t * child)
1000 {
1001 return child->desc;
1002 }
1003
1004 int
1005 mainloop_child_timeout(mainloop_child_t * child)
1006 {
1007 return child->timeout;
1008 }
1009
1010 void *
1011 mainloop_child_userdata(mainloop_child_t * child)
1012 {
1013 return child->privatedata;
1014 }
1015
1016 void
1017 mainloop_clear_child_userdata(mainloop_child_t * child)
1018 {
1019 child->privatedata = NULL;
1020 }
1021
1022 static int
1023 child_kill_helper(const mainloop_child_t *child)
1024 {
1025 int rc = 0;
1026
1027 if (pcmk__is_set(child->flags, mainloop_leave_pid_group)) {
1028 pcmk__debug("Killing PID %lld only. Leaving its process group intact.",
1029 (long long) child->pid);
1030 rc = kill(child->pid, SIGKILL);
1031
1032 } else {
1033 pcmk__debug("Killing PID %lld's entire process group",
1034 (long long) child->pid);
1035 rc = kill(-child->pid, SIGKILL);
1036 }
1037
1038 if (rc == 0) {
1039 return pcmk_rc_ok;
1040 }
1041
1042 rc = errno;
1043 if (rc == ESRCH) {
1044 return rc;
1045 }
1046
1047 pcmk__err("kill(%lld, KILL) failed: %s", (long long) child->pid,
1048 strerror(rc));
1049 return rc;
1050 }
1051
1052 static gboolean
1053 child_timeout_callback(void *p)
1054 {
1055 mainloop_child_t *child = p;
1056 int rc = pcmk_rc_ok;
1057
1058 child->timerid = 0;
1059 if (child->timeout) {
1060 pcmk__warn("%s process (PID %lld) will not die!", child->desc,
1061 (long long) child->pid);
1062 return FALSE;
1063 }
1064
1065 rc = child_kill_helper(child);
1066 if (rc == ESRCH) {
1067 /* Nothing left to do. pid doesn't exist */
1068 return FALSE;
1069 }
1070
1071 child->timeout = TRUE;
1072 pcmk__debug("%s process (PID %lld) timed out", child->desc,
1073 (long long) child->pid);
1074
1075 child->timerid = pcmk__create_timer(5000, child_timeout_callback, child);
1076 return FALSE;
1077 }
1078
1079 static bool
1080 child_waitpid(mainloop_child_t *child, int flags)
1081 {
1082 int rc = 0;
1083 int core = 0;
1084 int signo = 0;
1085 int status = 0;
1086 int exitcode = 0;
1087
1088 rc = waitpid(child->pid, &status, flags);
1089
1090 if (rc == 0) { // WNOHANG in flags, and child status is not available
1091 pcmk__trace("Child process %lld (%s) still active",
1092 (long long) child->pid, child->desc);
1093 return false;
1094 }
1095
1096 if (rc != child->pid) {
1097 /* According to POSIX, possible conditions:
1098 * - child->pid was non-positive (process group or any child),
1099 * and rc is specific child
1100 * - errno ECHILD (pid does not exist or is not child)
1101 * - errno EINVAL (invalid flags)
1102 * - errno EINTR (caller interrupted by signal)
1103 *
1104 * @TODO Handle these cases more specifically.
1105 */
1106 signo = SIGCHLD;
1107 exitcode = 1;
1108 pcmk__notice("Wait for child process %lld (%s) interrupted: %s",
1109 (long long) child->pid, child->desc, strerror(errno));
1110
1111 } else if (WIFEXITED(status)) {
1112 exitcode = WEXITSTATUS(status);
1113 pcmk__trace("Child process %lld (%s) exited with status %d",
1114 (long long) child->pid, child->desc, exitcode);
1115
1116 } else if (WIFSIGNALED(status)) {
1117 signo = WTERMSIG(status);
1118 pcmk__trace("Child process %lld (%s) exited with signal %d (%s)",
1119 (long long) child->pid, child->desc, signo,
1120 strsignal(signo));
1121
1122 #ifdef WCOREDUMP // AIX, SunOS, maybe others
1123 } else if (WCOREDUMP(status)) {
1124 core = 1;
1125 pcmk__err("Child process %lld (%s) dumped core", (long long) child->pid,
1126 child->desc);
1127 #endif
1128
1129 } else { // flags must contain WUNTRACED and/or WCONTINUED to reach this
1130 pcmk__trace("Child process %lld (%s) stopped or continued",
1131 (long long) child->pid, child->desc);
1132 return false;
1133 }
1134
1135 if (child->exit_fn != NULL) {
1136 child->exit_fn(child, core, signo, exitcode);
1137 }
1138
1139 return true;
1140 }
1141
1142 static gboolean
1143 child_waitpid_no_hang(void *key, void *value, void *user_data)
1144 {
1145 mainloop_child_t *child = value;
1146
1147 if (!child_waitpid(child, WNOHANG)) {
1148 return FALSE;
1149 }
1150
1151 pcmk__trace("Removing completed process %lld from child table",
1152 (long long) child->pid);
1153 return TRUE;
1154 }
1155
1156 static void
1157 child_death_dispatch(int signal)
1158 {
1159 if (mainloop_children == NULL) {
1160 return;
1161 }
1162
1163 g_hash_table_foreach_remove(mainloop_children, child_waitpid_no_hang, NULL);
1164 }
1165
1166 static gboolean
1167 child_signal_init(void *p)
1168 {
1169 pcmk__trace("Installed SIGCHLD handler");
1170 /* Do NOT use g_child_watch_add() and friends, they rely on pthreads */
1171 mainloop_add_signal(SIGCHLD, child_death_dispatch);
1172
1173 /* In case they terminated before the signal handler was installed */
1174 child_death_dispatch(SIGCHLD);
1175 return FALSE;
1176 }
1177
1178 gboolean
1179 mainloop_child_kill(pid_t pid)
1180 {
1181 /* It is impossible to block SIGKILL. This allows us to call waitpid()
1182 * without the WNOHANG flag.
1183 */
1184 int waitflags = 0;
1185 int rc = pcmk_rc_ok;
1186 char *pid_s = NULL;
1187 mainloop_child_t *child = NULL;
1188 gboolean killed = FALSE;
1189
1190 if (mainloop_children == NULL) {
1191 // We're not tracking any children, so don't kill this PID
1192 goto done;
1193 }
1194
1195 pid_s = pcmk__assert_asprintf("%lld", (long long) pid);
1196 child = g_hash_table_lookup(mainloop_children, pid_s);
1197
1198 if (child == NULL) {
1199 // We're not tracking a child with this PID, so don't kill it
1200 goto done;
1201 }
1202
1203 rc = child_kill_helper(child);
1204 if (rc == ESRCH) {
1205 /* kill() didn't find the PID. Assume this means the process is in some
1206 * intermediate stage of exiting. Wait until we get SIGCHLD and let
1207 * the handler clean it up as normal, so that we get the correct return
1208 * code/status. The blocking alternative would be to call
1209 * child_waitpid(child, 0).
1210 *
1211 * Treat this as success in the meantime.
1212 */
1213 pcmk__trace("Waiting for signal that child process %lld completed",
1214 (long long) child->pid);
1215 killed = TRUE;
1216 goto done;
1217 }
1218
1219 if (rc != pcmk_rc_ok) {
1220 /* If kill() failed for some other reason, set the WNOHANG flag, since
1221 * we can't be certain what happened.
1222 */
1223 waitflags = WNOHANG;
1224 }
1225
1226 if (!child_waitpid(child, waitflags)) {
1227 /* waitpid() didn't find the child. This shouldn't happen if kill()
1228 * succeeded. In any case, there's no obviously good way to proceed.
1229 * Treat this as a failure.
1230 *
1231 * @TODO Should we call the child's exit_fn with a failure here, and/or
1232 * free the mainloop_child_t? We can hope that we successfully wait on
1233 * it in response to a SIGCHLD that comes later. But we might just never
1234 * do anything with this child again.
1235 *
1236 * @TODO Consider using GSubprocess for all subprocess tracking.
1237 */
1238 goto done;
1239 }
1240
1241 g_hash_table_remove(mainloop_children, pid_s);
1242 killed = TRUE;
1243
1244 done:
1245 free(pid_s);
1246 return killed;
1247 }
1248
1249 /* Create/Log a new tracked process
1250 * To track a process group, use -pid
1251 *
1252 * Newly created child will be freed by mainloop_cleanup(), if not sooner.
1253 *
1254 * @TODO Using a non-positive pid (i.e. any child, or process group) would
1255 * likely not be useful since we will free the child after the first
1256 * completed process.
1257 */
1258 void
1259 mainloop_child_add_with_flags(pid_t pid, int timeout, const char *desc,
1260 void *privatedata,
1261 enum mainloop_child_flags flags,
1262 pcmk__mainloop_child_exit_fn_t exit_fn)
1263 {
1264 static bool need_init = TRUE;
1265 bool is_new = false;
1266 mainloop_child_t *child = pcmk__assert_alloc(1, sizeof(mainloop_child_t));
1267
1268 child->pid = pid;
1269 child->timerid = 0;
1270 child->timeout = FALSE;
1271 child->privatedata = privatedata;
1272 child->exit_fn = exit_fn;
1273 child->flags = flags;
1274 child->desc = pcmk__str_copy(desc);
1275
1276 if (timeout) {
1277 child->timerid = pcmk__create_timer(timeout, child_timeout_callback, child);
1278 }
1279
1280 if (mainloop_children == NULL) {
1281 mainloop_children = pcmk__strkey_table(free,
1282 (GDestroyNotify) child_free);
1283 }
1284
1285 is_new = g_hash_table_insert(mainloop_children,
1286 pcmk__assert_asprintf("%lld", (long long) pid),
1287 child);
1288
1289 // It should be impossible to have this PID in mainloop_children already
1290 CRM_LOG_ASSERT(is_new);
1291
1292 if(need_init) {
1293 need_init = FALSE;
1294 /* SIGCHLD processing has to be invoked from mainloop.
1295 * We do not want it to be possible to both add a child pid
1296 * to mainloop, and have the pid's exit callback invoked within
1297 * the same callstack. */
1298 pcmk__create_timer(1, child_signal_init, NULL);
1299 }
1300 }
1301
1302 // Newly created child will be freed by mainloop_cleanup(), if not sooner
1303 void
1304 mainloop_child_add(pid_t pid, int timeout, const char *desc, void *privatedata,
1305 pcmk__mainloop_child_exit_fn_t exit_fn)
1306 {
1307 mainloop_child_add_with_flags(pid, timeout, desc, privatedata, 0, exit_fn);
1308 }
1309
1310 static gboolean
1311 mainloop_timer_cb(void *user_data)
1312 {
1313 int id = 0;
1314 bool repeat = FALSE;
1315 struct mainloop_timer_s *t = user_data;
1316
1317 pcmk__assert(t != NULL);
1318
1319 id = t->id;
1320 t->id = 0; /* Ensure it's unset during callbacks so that
1321 * mainloop_timer_running() works as expected
1322 */
1323
1324 if(t->cb) {
1325 pcmk__trace("Invoking callbacks for timer %s", t->name);
1326 repeat = t->repeat;
1327 if(t->cb(t->userdata) == FALSE) {
1328 pcmk__trace("Timer %s complete", t->name);
1329 repeat = FALSE;
1330 }
1331 }
1332
1333 if(repeat) {
1334 /* Restore if repeating */
1335 t->id = id;
1336 }
1337
1338 return repeat;
1339 }
1340
1341 bool
1342 mainloop_timer_running(mainloop_timer_t *t)
1343 {
1344 if(t && t->id != 0) {
1345 return TRUE;
1346 }
1347 return FALSE;
1348 }
1349
1350 void
1351 mainloop_timer_start(mainloop_timer_t *t)
1352 {
1353 mainloop_timer_stop(t);
1354 if(t && t->period_ms > 0) {
1355 pcmk__trace("Starting timer %s", t->name);
1356 t->id = pcmk__create_timer(t->period_ms, mainloop_timer_cb, t);
1357 }
1358 }
1359
1360 void
1361 mainloop_timer_stop(mainloop_timer_t *t)
1362 {
1363 if(t && t->id != 0) {
1364 pcmk__trace("Stopping timer %s", t->name);
1365 g_source_remove(t->id);
1366 t->id = 0;
1367 }
1368 }
1369
1370 unsigned int
1371 mainloop_timer_set_period(mainloop_timer_t *t, unsigned int period_ms)
1372 {
1373 unsigned int last = 0;
1374
1375 if(t) {
1376 last = t->period_ms;
1377 t->period_ms = period_ms;
1378 }
1379
1380 if(t && t->id != 0 && last != t->period_ms) {
1381 mainloop_timer_start(t);
1382 }
1383 return last;
1384 }
1385
1386 mainloop_timer_t *
1387 mainloop_timer_add(const char *name, unsigned int period_ms, bool repeat,
1388 GSourceFunc cb, void *userdata)
1389 {
1390 mainloop_timer_t *t = pcmk__assert_alloc(1, sizeof(mainloop_timer_t));
1391
1392 if (name != NULL) {
1393 t->name = pcmk__assert_asprintf("%s-%u-%d", name, period_ms, repeat);
1394 } else {
1395 t->name = pcmk__assert_asprintf("%p-%u-%d", t, period_ms, repeat);
1396 }
1397 t->id = 0;
1398 t->period_ms = period_ms;
1399 t->repeat = repeat;
1400 t->cb = cb;
1401 t->userdata = userdata;
1402 pcmk__trace("Created timer %s with %p %p", t->name, userdata, t->userdata);
1403 return t;
1404 }
1405
1406 void
1407 mainloop_timer_del(mainloop_timer_t *t)
1408 {
1409 if(t) {
1410 pcmk__trace("Destroying timer %s", t->name);
1411 mainloop_timer_stop(t);
1412 free(t->name);
1413 free(t);
1414 }
1415 }
1416
1417 /*
1418 * Helpers to make sure certain events aren't lost at shutdown
1419 */
1420
1421 static gboolean
1422 drain_timeout_cb(void *user_data)
1423 {
1424 bool *timeout_popped = (bool*) user_data;
1425
1426 *timeout_popped = TRUE;
1427 return FALSE;
1428 }
1429
1430 /*!
1431 * \brief Drain some remaining main loop events then quit it
1432 *
1433 * \param[in,out] mloop Main loop to drain and quit
1434 * \param[in] n Drain up to this many pending events
1435 */
1436 void
1437 pcmk_quit_main_loop(GMainLoop *mloop, unsigned int n)
1438 {
1439 if ((mloop != NULL) && g_main_loop_is_running(mloop)) {
1440 GMainContext *ctx = g_main_loop_get_context(mloop);
1441
1442 /* Drain up to n events in case some memory clean-up is pending
1443 * (helpful to reduce noise in valgrind output).
1444 */
1445 for (int i = 0; (i < n) && g_main_context_pending(ctx); ++i) {
1446 g_main_context_dispatch(ctx);
1447 }
1448 g_main_loop_quit(mloop);
1449 }
1450 }
1451
1452 /*!
1453 * \brief Process main loop events while a certain condition is met
1454 *
1455 * \param[in,out] mloop Main loop to process
1456 * \param[in] timer_ms Don't process longer than this amount of time
1457 * \param[in] check Function that returns true if events should be
1458 * processed
1459 *
1460 * \note This function is intended to be called at shutdown if certain important
1461 * events should not be missed. The caller would likely quit the main loop
1462 * or exit after calling this function. The check() function will be
1463 * passed the remaining timeout in milliseconds.
1464 */
1465 void
1466 pcmk_drain_main_loop(GMainLoop *mloop, unsigned int timer_ms,
1467 bool (*check)(unsigned int))
1468 {
1469 bool timeout_popped = FALSE;
1470 unsigned int timer = 0;
1471 GMainContext *ctx = NULL;
1472
1473 CRM_CHECK(mloop && check, return);
1474
1475 ctx = g_main_loop_get_context(mloop);
1476 if (ctx) {
1477 time_t start_time = time(NULL);
1478
1479 timer = pcmk__create_timer(timer_ms, drain_timeout_cb, &timeout_popped);
1480 while (!timeout_popped
1481 && check(timer_ms - (time(NULL) - start_time) * 1000)) {
1482 g_main_context_iteration(ctx, TRUE);
1483 }
1484 }
1485 if (!timeout_popped && (timer > 0)) {
1486 g_source_remove(timer);
1487 }
1488 }
1489