28 #include <qb/qbarray.h>
30 struct mainloop_child_s {
52 struct mainloop_timer_s {
62 crm_trigger_prepare(GSource * source, gint *
timeout)
89 crm_trigger_check(GSource * source)
107 crm_trigger_dispatch(GSource * source, GSourceFunc callback, gpointer userdata)
109 gboolean
rc = G_SOURCE_CONTINUE;
114 return G_SOURCE_CONTINUE;
116 trig->trigger = FALSE;
119 int callback_rc = callback(trig->user_data);
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;
132 crm_trigger_finalize(GSource * source)
134 crm_trace(
"Trigger %p destroyed", source);
137 static GSourceFuncs crm_trigger_funcs = {
140 crm_trigger_dispatch,
141 crm_trigger_finalize,
145 mainloop_setup_trigger(GSource * source,
int priority,
int (*dispatch) (gpointer user_data),
153 trigger->trigger = FALSE;
154 trigger->user_data = userdata;
157 g_source_set_callback(source, dispatch, trigger, NULL);
160 g_source_set_priority(source, priority);
161 g_source_set_can_recurse(source, FALSE);
163 trigger->id = g_source_attach(source, NULL);
170 crm_trace(
"Trigger handler %p complete", trig);
171 trig->running = FALSE;
188 GSource *source = NULL;
191 source = g_source_new(&crm_trigger_funcs,
sizeof(
crm_trigger_t));
194 return mainloop_setup_trigger(source, priority, dispatch, userdata);
201 source->trigger = TRUE;
214 gs = (GSource *)source;
216 g_source_destroy(gs);
231 typedef struct signal_s {
233 void (*handler) (
int sig);
252 crm_signal_dispatch(GSource * source, GSourceFunc callback, gpointer userdata)
256 if(sig->signal != SIGCHLD) {
258 strsignal(sig->signal), sig->signal,
259 (sig->handler?
"invoking" :
"no"));
262 sig->trigger.trigger = FALSE;
264 sig->handler(sig->signal);
279 mainloop_signal_handler(
int sig)
281 if (sig > 0 && sig < NSIG && crm_signals[sig] != NULL) {
287 static GSourceFuncs crm_signal_funcs = {
291 crm_trigger_finalize,
311 struct sigaction old;
313 if (sigemptyset(&mask) < 0) {
314 crm_err(
"Could not set handler for signal %d: %s",
319 memset(&sa, 0,
sizeof(
struct sigaction));
320 sa.sa_handler = dispatch;
321 sa.sa_flags = SA_RESTART;
324 if (sigaction(sig, &sa, &old) < 0) {
325 crm_err(
"Could not set handler for signal %d: %s",
329 return old.sa_handler;
333 mainloop_destroy_signal_entry(
int sig)
337 crm_signals[sig] = NULL;
357 GSource *source = NULL;
358 int priority = G_PRIORITY_HIGH - 1;
360 if (sig == SIGTERM) {
368 if (sig >= NSIG || sig < 0) {
369 crm_err(
"Signal %d is out of range", sig);
372 }
else if (crm_signals[sig] != NULL && crm_signals[sig]->handler == dispatch) {
373 crm_trace(
"Signal handler for %d is already installed", sig);
376 }
else if (crm_signals[sig] != NULL) {
377 crm_err(
"Different signal handler for %d is already installed", sig);
382 source = g_source_new(&crm_signal_funcs,
sizeof(
crm_signal_t));
384 crm_signals[sig] = (
crm_signal_t *) mainloop_setup_trigger(source, priority, NULL, NULL);
387 crm_signals[sig]->handler = dispatch;
388 crm_signals[sig]->signal = sig;
391 mainloop_destroy_signal_entry(sig);
400 if (siginterrupt(sig, 1) < 0) {
401 crm_perror(LOG_INFO,
"Could not enable system call interruptions for signal %d", sig);
411 if (sig >= NSIG || sig < 0) {
412 crm_err(
"Signal %d is out of range", sig);
416 crm_perror(LOG_ERR,
"Could not uninstall signal handler for signal %d", sig);
419 }
else if (crm_signals[sig] == NULL) {
422 mainloop_destroy_signal_entry(sig);
426 static qb_array_t *gio_map = NULL;
432 qb_array_free(gio_map);
435 for (
int sig = 0; sig < NSIG; ++sig) {
436 mainloop_destroy_signal_entry(sig);
443 struct gio_to_qb_poll {
448 qb_ipcs_dispatch_fn_t fn;
449 enum qb_loop_priority p;
453 gio_read_socket(GIOChannel * gio, GIOCondition condition, gpointer
data)
455 struct gio_to_qb_poll *adaptor = (
struct gio_to_qb_poll *)data;
456 gint fd = g_io_channel_unix_get_fd(gio);
458 crm_trace(
"%p.%d %d", data, fd, condition);
464 return (adaptor->fn(fd, condition, adaptor->data) == 0);
468 gio_poll_destroy(gpointer data)
470 struct gio_to_qb_poll *adaptor = (
struct gio_to_qb_poll *)data;
475 if (adaptor->is_used == 0) {
476 crm_trace(
"Marking adaptor %p unused", adaptor);
490 conv_prio_libqb2glib(
enum qb_loop_priority prio)
492 gint ret = G_PRIORITY_DEFAULT;
495 ret = G_PRIORITY_LOW;
498 ret = G_PRIORITY_HIGH;
501 crm_trace(
"Invalid libqb's loop priority %d, assuming QB_LOOP_MED",
518 static enum qb_ipcs_rate_limit
519 conv_libqb_prio2ratelimit(
enum qb_loop_priority prio)
522 enum qb_ipcs_rate_limit ret = QB_IPCS_RATE_NORMAL;
525 ret = QB_IPCS_RATE_SLOW;
528 ret = QB_IPCS_RATE_FAST;
531 crm_trace(
"Invalid libqb's loop priority %d, assuming QB_LOOP_MED",
541 gio_poll_dispatch_update(
enum qb_loop_priority p, int32_t fd, int32_t evts,
542 void *data, qb_ipcs_dispatch_fn_t fn, int32_t add)
544 struct gio_to_qb_poll *adaptor;
548 res = qb_array_index(gio_map, fd, (
void **)&adaptor);
550 crm_err(
"Array lookup failed for fd=%d: %d", fd, res);
554 crm_trace(
"Adding fd=%d to mainloop as adaptor %p", fd, adaptor);
556 if (add && adaptor->source) {
557 crm_err(
"Adaptor for descriptor %d is still in-use", fd);
560 if (!add && !adaptor->is_used) {
561 crm_err(
"Adaptor for descriptor %d is not in-use", fd);
566 channel = g_io_channel_unix_new(fd);
568 crm_err(
"No memory left to add fd=%d", fd);
572 if (adaptor->source) {
573 g_source_remove(adaptor->source);
578 evts |= (G_IO_HUP | G_IO_NVAL | G_IO_ERR);
581 adaptor->events = evts;
582 adaptor->data =
data;
586 g_io_add_watch_full(channel, conv_prio_libqb2glib(p), evts,
587 gio_read_socket, adaptor, gio_poll_destroy);
598 g_io_channel_unref(channel);
600 crm_trace(
"Added to mainloop with gsource id=%d", adaptor->source);
601 if (adaptor->source > 0) {
609 gio_poll_dispatch_add(
enum qb_loop_priority p, int32_t fd, int32_t evts,
610 void *data, qb_ipcs_dispatch_fn_t fn)
612 return gio_poll_dispatch_update(p, fd, evts, data, fn, QB_TRUE);
616 gio_poll_dispatch_mod(
enum qb_loop_priority p, int32_t fd, int32_t evts,
617 void *data, qb_ipcs_dispatch_fn_t fn)
619 return gio_poll_dispatch_update(p, fd, evts, data, fn, QB_FALSE);
623 gio_poll_dispatch_del(int32_t fd)
625 struct gio_to_qb_poll *adaptor;
628 if (qb_array_index(gio_map, fd, (
void **)&adaptor) == 0) {
629 if (adaptor->source) {
630 g_source_remove(adaptor->source);
639 .dispatch_add = gio_poll_dispatch_add,
640 .dispatch_mod = gio_poll_dispatch_mod,
641 .dispatch_del = gio_poll_dispatch_del,
644 static enum qb_ipc_type
645 pick_ipc_type(
enum qb_ipc_type requested)
647 const char *env = getenv(
"PCMK_ipc_type");
649 if (env && strcmp(
"shared-mem", env) == 0) {
651 }
else if (env && strcmp(
"socket", env) == 0) {
652 return QB_IPC_SOCKET;
653 }
else if (env && strcmp(
"posix", env) == 0) {
654 return QB_IPC_POSIX_MQ;
655 }
else if (env && strcmp(
"sysv", env) == 0) {
656 return QB_IPC_SYSV_MQ;
657 }
else if (requested == QB_IPC_NATIVE) {
671 struct qb_ipcs_service_handlers *callbacks)
678 struct qb_ipcs_service_handlers *callbacks,
679 enum qb_loop_priority prio)
682 qb_ipcs_service_t *server = NULL;
684 if (gio_map == NULL) {
685 gio_map = qb_array_create_2(64,
sizeof(
struct gio_to_qb_poll), 1);
688 server = qb_ipcs_create(name, 0, pick_ipc_type(type), callbacks);
690 if (server == NULL) {
695 if (prio != QB_LOOP_MED) {
696 qb_ipcs_request_rate_limit(server, conv_libqb_prio2ratelimit(prio));
701 qb_ipcs_poll_handlers_set(server, &gio_poll_funcs);
703 rc = qb_ipcs_run(server);
716 qb_ipcs_destroy(server);
720 struct mainloop_io_s {
729 int (*dispatch_fn_ipc) (
const char *buffer, ssize_t length, gpointer userdata);
730 int (*dispatch_fn_io) (gpointer userdata);
731 void (*destroy_fn) (gpointer userdata);
746 mainloop_gio_callback(GIOChannel * gio, GIOCondition condition, gpointer data)
748 gboolean rc = G_SOURCE_CONTINUE;
751 CRM_ASSERT(client->fd == g_io_channel_unix_get_fd(gio));
753 if (condition & G_IO_IN) {
761 crm_trace(
"Could not read IPC message from %s: %s (%ld)",
764 }
else if (client->dispatch_fn_ipc) {
767 crm_trace(
"New %ld-byte IPC message from %s "
768 "after I/O condition %d",
769 read_rc, client->name, (
int) condition);
770 if (client->dispatch_fn_ipc(buffer, read_rc, client->userdata) < 0) {
771 crm_trace(
"Connection to %s no longer required", client->name);
772 rc = G_SOURCE_REMOVE;
776 }
while ((rc == G_SOURCE_CONTINUE) && (read_rc > 0) && --max > 0);
779 crm_trace(
"New I/O event for %s after I/O condition %d",
780 client->name, (
int) condition);
781 if (client->dispatch_fn_io) {
782 if (client->dispatch_fn_io(client->userdata) < 0) {
783 crm_trace(
"Connection to %s no longer required", client->name);
784 rc = G_SOURCE_REMOVE;
791 crm_err(
"Connection to %s closed " CRM_XS "client=%p condition=%d",
792 client->name, client, condition);
793 rc = G_SOURCE_REMOVE;
795 }
else if (condition & (G_IO_HUP | G_IO_NVAL | G_IO_ERR)) {
796 crm_trace(
"The connection %s[%p] has been closed (I/O condition=%d)",
797 client->name, client, condition);
798 rc = G_SOURCE_REMOVE;
800 }
else if ((condition & G_IO_IN) == 0) {
828 crm_err(
"Strange condition: %d", condition);
838 mainloop_gio_destroy(gpointer c)
841 char *c_name = strdup(client->name);
846 crm_trace(
"Destroying client %s[%p]", c_name, c);
852 if (client->destroy_fn) {
853 void (*destroy_fn) (gpointer userdata) = client->destroy_fn;
855 client->destroy_fn = NULL;
856 destroy_fn(client->userdata);
866 crm_trace(
"Destroyed client %s[%p]", c_name, c);
868 free(client->name); client->name = NULL;
897 CRM_CHECK((ipc != NULL) && (callbacks != NULL),
return EINVAL);
906 if (*source == NULL) {
912 (*source)->ipc = ipc;
913 (*source)->destroy_fn = callbacks->
destroy;
914 (*source)->dispatch_fn_ipc = callbacks->
dispatch;
929 return timer->period_ms;
945 fprintf(stderr,
"Connection to %s failed: %s",
982 if (client == NULL) {
985 client->name = strdup(name);
986 client->userdata = userdata;
989 client->destroy_fn = callbacks->
destroy;
990 client->dispatch_fn_io = callbacks->
dispatch;
994 client->channel = g_io_channel_unix_new(fd);
996 g_io_add_watch_full(client->channel, priority,
997 (G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR), mainloop_gio_callback,
998 client, mainloop_gio_destroy);
1009 g_io_channel_unref(client->channel);
1010 crm_trace(
"Added connection %d for %s[%p].%d", client->source, client->name, client, fd);
1021 if (client != NULL) {
1022 crm_trace(
"Removing client %s[%p]", client->name, client);
1023 if (client->source) {
1027 g_source_remove(client->source);
1032 static GList *child_list = NULL;
1049 return child->timeout;
1055 return child->privatedata;
1061 child->privatedata = NULL;
1068 if (child->timerid != 0) {
1069 crm_trace(
"Removing timer %d", child->timerid);
1070 g_source_remove(child->timerid);
1083 crm_debug(
"Kill pid %d only. leave group intact.", child->pid);
1084 rc = kill(child->pid, SIGKILL);
1086 crm_debug(
"Kill pid %d's group", child->pid);
1087 rc = kill(-child->pid, SIGKILL);
1091 if (errno != ESRCH) {
1092 crm_perror(LOG_ERR,
"kill(%d, KILL) failed", child->pid);
1100 child_timeout_callback(gpointer p)
1106 if (child->timeout) {
1107 crm_crit(
"%s process (PID %d) will not die!", child->desc, (
int)child->pid);
1111 rc = child_kill_helper(child);
1117 child->timeout = TRUE;
1118 crm_warn(
"%s process (PID %d) timed out", child->desc, (
int)child->pid);
1120 child->timerid = g_timeout_add(5000, child_timeout_callback, child);
1132 bool callback_needed =
true;
1134 rc = waitpid(child->pid, &status, flags);
1136 crm_trace(
"Child process %d (%s) still active",
1137 child->pid, child->desc);
1138 callback_needed =
false;
1140 }
else if (rc != child->pid) {
1152 crm_notice(
"Wait for child process %d (%s) interrupted: %s",
1155 }
else if (WIFEXITED(status)) {
1156 exitcode = WEXITSTATUS(status);
1157 crm_trace(
"Child process %d (%s) exited with status %d",
1158 child->pid, child->desc, exitcode);
1160 }
else if (WIFSIGNALED(status)) {
1161 signo = WTERMSIG(status);
1162 crm_trace(
"Child process %d (%s) exited with signal %d (%s)",
1163 child->pid, child->desc, signo, strsignal(signo));
1165 #ifdef WCOREDUMP // AIX, SunOS, maybe others
1166 }
else if (WCOREDUMP(status)) {
1168 crm_err(
"Child process %d (%s) dumped core",
1169 child->pid, child->desc);
1173 crm_trace(
"Child process %d (%s) stopped or continued",
1174 child->pid, child->desc);
1175 callback_needed =
false;
1178 if (callback_needed && child->callback) {
1179 child->callback(child, child->pid, core, signo, exitcode);
1181 return callback_needed;
1185 child_death_dispatch(
int signal)
1187 for (GList *iter = child_list; iter; ) {
1188 GList *saved = iter;
1192 if (child_waitpid(child, WNOHANG)) {
1193 crm_trace(
"Removing completed process %d from child list",
1195 child_list = g_list_remove_link(child_list, saved);
1203 child_signal_init(gpointer p)
1210 child_death_dispatch(SIGCHLD);
1222 int waitflags = 0, rc = 0;
1224 for (iter = child_list; iter != NULL && match == NULL; iter = iter->next) {
1226 if (pid == child->pid) {
1231 if (match == NULL) {
1235 rc = child_kill_helper(match);
1242 crm_trace(
"Waiting for signal that child process %d completed",
1246 }
else if(rc != 0) {
1250 waitflags = WNOHANG;
1253 if (!child_waitpid(match, waitflags)) {
1258 child_list = g_list_remove(child_list, match);
1272 void (*callback) (
mainloop_child_t * p, pid_t pid,
int core,
int signo,
int exitcode))
1274 static bool need_init = TRUE;
1279 child->timeout = FALSE;
1280 child->privatedata = privatedata;
1281 child->callback = callback;
1282 child->flags =
flags;
1285 child->desc = strdup(desc);
1289 child->timerid = g_timeout_add(timeout, child_timeout_callback, child);
1292 child_list = g_list_append(child_list, child);
1300 g_timeout_add(1, child_signal_init, NULL);
1306 void (*callback) (
mainloop_child_t * p, pid_t pid,
int core,
int signo,
int exitcode))
1312 mainloop_timer_cb(gpointer user_data)
1315 bool repeat = FALSE;
1316 struct mainloop_timer_s *t = user_data;
1326 crm_trace(
"Invoking callbacks for timer %s", t->name);
1328 if(t->cb(t->userdata) == FALSE) {
1329 crm_trace(
"Timer %s complete", t->name);
1345 if(t && t->id != 0) {
1355 if(t && t->period_ms > 0) {
1356 crm_trace(
"Starting timer %s", t->name);
1357 t->id = g_timeout_add(t->period_ms, mainloop_timer_cb, t);
1364 if(t && t->id != 0) {
1365 crm_trace(
"Stopping timer %s", t->name);
1366 g_source_remove(t->id);
1377 last = t->period_ms;
1378 t->period_ms = period_ms;
1381 if(t && t->id != 0 && last != t->period_ms) {
1399 t->period_ms = period_ms;
1402 t->userdata = userdata;
1403 crm_trace(
"Created timer %s with %p %p", t->name, userdata, t->userdata);
1412 crm_trace(
"Destroying timer %s", t->name);
1424 drain_timeout_cb(gpointer user_data)
1426 bool *timeout_popped = (
bool*) user_data;
1428 *timeout_popped = TRUE;
1441 if ((mloop != NULL) && g_main_loop_is_running(mloop)) {
1442 GMainContext *ctx = g_main_loop_get_context(mloop);
1447 for (
int i = 0; (i < n) && g_main_context_pending(ctx); ++i) {
1448 g_main_context_dispatch(ctx);
1450 g_main_loop_quit(mloop);
1469 bool timeout_popped = FALSE;
1471 GMainContext *ctx = NULL;
1475 ctx = g_main_loop_get_context(mloop);
1477 time_t start_time = time(NULL);
1479 timer = g_timeout_add(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);
1485 if (!timeout_popped && (timer > 0)) {
1486 g_source_remove(timer);
#define CRM_CHECK(expr, failure_action)
bool crm_ipc_connect(crm_ipc_t *client)
Establish an IPC connection to a Pacemaker component.
guint pcmk__mainloop_timer_get_period(mainloop_timer_t *timer)
Get period for mainloop timer.
#define crm_notice(fmt, args...)
const char * pcmk_strerror(int rc)
struct signal_s crm_signal_t
#define crm_crit(fmt, args...)
gboolean mainloop_add_signal(int sig, void(*dispatch)(int sig))
mainloop_io_t * mainloop_add_fd(const char *name, int priority, int fd, void *userdata, struct mainloop_fd_callbacks *callbacks)
void mainloop_timer_start(mainloop_timer_t *t)
guint mainloop_timer_set_period(mainloop_timer_t *t, guint period_ms)
void mainloop_timer_del(mainloop_timer_t *t)
gboolean crm_signal(int sig, void(*dispatch)(int sig))
gboolean mainloop_child_kill(pid_t pid)
int crm_ipc_get_fd(crm_ipc_t *client)
Deprecated Pacemaker mainloop API.
void(* sighandler_t)(int)
qb_ipcs_service_t * mainloop_add_ipc_server_with_prio(const char *name, enum qb_ipc_type type, struct qb_ipcs_service_handlers *callbacks, enum qb_loop_priority prio)
Start server-side API end-point, hooked into the internal event loop.
void pcmk_drain_main_loop(GMainLoop *mloop, guint timer_ms, bool(*check)(guint))
Process main loop events while a certain condition is met.
struct mainloop_timer_s mainloop_timer_t
struct mainloop_io_s mainloop_io_t
void mainloop_child_add_with_flags(pid_t pid, int timeout, const char *desc, void *userdata, enum mainloop_child_flags, void(*callback)(mainloop_child_t *p, pid_t pid, int core, int signo, int exitcode))
struct mainloop_child_s mainloop_child_t
void mainloop_set_trigger(crm_trigger_t *source)
void mainloop_cleanup(void)
int(* dispatch)(gpointer userdata)
Dispatch function for mainloop file descriptor with data ready.
pid_t mainloop_child_pid(mainloop_child_t *child)
long crm_ipc_read(crm_ipc_t *client)
enum crm_ais_msg_types type
gboolean mainloop_destroy_trigger(crm_trigger_t *source)
const char * pcmk_rc_str(int rc)
Get a user-friendly description of a return code.
struct qb_ipcs_poll_handlers gio_poll_funcs
void mainloop_timer_stop(mainloop_timer_t *t)
Wrappers for and extensions to glib mainloop.
const char * crm_ipc_buffer(crm_ipc_t *client)
struct trigger_s crm_trigger_t
#define crm_warn(fmt, args...)
#define crm_debug(fmt, args...)
void * mainloop_child_userdata(mainloop_child_t *child)
struct crm_ipc_s crm_ipc_t
void(* destroy)(gpointer userdata)
Destroy function for mainloop file descriptor client data.
#define crm_trace(fmt, args...)
char * crm_strdup_printf(char const *format,...) G_GNUC_PRINTF(1
sighandler_t crm_signal_handler(int sig, sighandler_t dispatch)
Wrappers for and extensions to libxml2.
crm_trigger_t * mainloop_add_trigger(int priority, int(*dispatch)(gpointer user_data), gpointer userdata)
Create a trigger to be used as a mainloop source.
void mainloop_del_ipc_client(mainloop_io_t *client)
unsigned int crm_ipc_default_buffer_size(void)
Return pacemaker's default IPC buffer size.
void crm_ipc_destroy(crm_ipc_t *client)
bool mainloop_timer_running(mainloop_timer_t *t)
bool crm_ipc_connected(crm_ipc_t *client)
unsigned int crm_log_level
void mainloop_child_add(pid_t pid, int timeout, const char *desc, void *userdata, void(*callback)(mainloop_child_t *p, pid_t pid, int core, int signo, int exitcode))
const char * crm_ipc_name(crm_ipc_t *client)
#define crm_perror(level, fmt, args...)
Send a system error message to both the log and stderr.
void mainloop_trigger_complete(crm_trigger_t *trig)
crm_ipc_t * mainloop_get_ipc_client(mainloop_io_t *client)
#define crm_err(fmt, args...)
void mainloop_clear_child_userdata(mainloop_child_t *child)
void pcmk_quit_main_loop(GMainLoop *mloop, unsigned int n)
Drain some remaining main loop events then quit it.
crm_ipc_t * crm_ipc_new(const char *name, size_t max_size)
Create a new (legacy) object for using Pacemaker daemon IPC.
void mainloop_del_fd(mainloop_io_t *client)
void mainloop_del_ipc_server(qb_ipcs_service_t *server)
mainloop_timer_t * mainloop_timer_add(const char *name, guint period_ms, bool repeat, GSourceFunc cb, void *userdata)
gboolean mainloop_destroy_signal(int sig)
mainloop_io_t * mainloop_add_ipc_client(const char *name, int priority, size_t max_size, void *userdata, struct ipc_client_callbacks *callbacks)
qb_ipcs_service_t * mainloop_add_ipc_server(const char *name, enum qb_ipc_type type, struct qb_ipcs_service_handlers *callbacks)
int pcmk__add_mainloop_ipc(crm_ipc_t *ipc, int priority, void *userdata, struct ipc_client_callbacks *callbacks, mainloop_io_t **source)
Connect to IPC and add it as a main loop source.
void crm_ipc_close(crm_ipc_t *client)
const char * mainloop_child_name(mainloop_child_t *child)
void(* destroy)(gpointer userdata)
Destroy function for mainloop IPC connection client data.
int(* dispatch)(const char *buffer, ssize_t length, gpointer userdata)
Dispatch function for an IPC connection used as mainloop source.
int mainloop_child_timeout(mainloop_child_t *child)