'\" t .TH "SD_EVENT_ADD_CHILD" "3" "" "elogind 252.9" "sd_event_add_child" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" sd_event_add_child, sd_event_add_child_pidfd, sd_event_source_get_child_pid, sd_event_source_get_child_pidfd, sd_event_source_get_child_pidfd_own, sd_event_source_set_child_pidfd_own, sd_event_source_get_child_process_own, sd_event_source_set_child_process_own, sd_event_source_send_child_signal, sd_event_child_handler_t \- Add a child process state change event source to an event loop .SH "SYNOPSIS" .sp .ft B .nf #include .fi .ft .sp .ft B .nf typedef struct sd_event_source sd_event_source; .fi .ft .HP \w'typedef\ int\ (*sd_event_child_handler_t)('u .BI "typedef int (*sd_event_child_handler_t)(sd_event_source\ *" "s" ", const\ siginfo_t\ *" "si" ", void\ *" "userdata" ");" .HP \w'int\ sd_event_add_child('u .BI "int sd_event_add_child(sd_event\ *" "event" ", sd_event_source\ **" "source" ", pid_t\ " "pid" ", int\ " "options" ", sd_event_child_handler_t\ " "handler" ", void\ *" "userdata" ");" .HP \w'int\ sd_event_add_child_pidfd('u .BI "int sd_event_add_child_pidfd(sd_event\ *" "event" ", sd_event_source\ **" "source" ", int\ " "pidfd" ", int\ " "options" ", sd_event_child_handler_t\ " "handler" ", void\ *" "userdata" ");" .HP \w'int\ sd_event_source_get_child_pid('u .BI "int sd_event_source_get_child_pid(sd_event_source\ *" "source" ", pid_t\ *" "pid" ");" .HP \w'int\ sd_event_source_get_child_pidfd('u .BI "int sd_event_source_get_child_pidfd(sd_event_source\ *" "source" ");" .HP \w'int\ sd_event_source_get_child_pidfd_own('u .BI "int sd_event_source_get_child_pidfd_own(sd_event_source\ *" "source" ");" .HP \w'int\ sd_event_source_set_child_pidfd_own('u .BI "int sd_event_source_set_child_pidfd_own(sd_event_source\ *" "source" ", int\ " "own" ");" .HP \w'int\ sd_event_source_get_child_process_own('u .BI "int sd_event_source_get_child_process_own(sd_event_source\ *" "source" ");" .HP \w'int\ sd_event_source_set_child_process_own('u .BI "int sd_event_source_set_child_process_own(sd_event_source\ *" "source" ", int\ " "own" ");" .HP \w'int\ sd_event_source_send_child_signal('u .BI "int sd_event_source_send_child_signal(sd_event_source\ *" "source" ", int\ " "sig" ", const\ siginfo_t\ *" "info" ", unsigned\ " "flags" ");" .SH "DESCRIPTION" .PP \fBsd_event_add_child()\fR adds a new child process state change event source to an event loop\&. The event loop object is specified in the \fIevent\fR parameter, the event source object is returned in the \fIsource\fR parameter\&. The \fIpid\fR parameter specifies the PID of the process to watch, which must be a direct child process of the invoking process\&. The \fIoptions\fR parameter determines which state changes will be watched for\&. It must contain an OR\-ed mask of \fBWEXITED\fR (watch for the child process terminating), \fBWSTOPPED\fR (watch for the child process being stopped by a signal), and \fBWCONTINUED\fR (watch for the child process being resumed by a signal)\&. See \fBwaitid\fR(2) for further information\&. .PP The \fIhandler\fR must be a function to call when the process changes state or \fBNULL\fR\&. The handler function will be passed the \fIuserdata\fR pointer, which may be chosen freely by the caller\&. The handler also receives a pointer to a siginfo_t structure containing information about the child process event\&. The handler may return negative to signal an error (see below), other return values are ignored\&. If \fIhandler\fR is \fBNULL\fR, a default handler that calls \fBsd_event_exit\fR(3) will be used\&. .PP Only a single handler may be installed for a specific child process\&. The handler is enabled for a single event (\fBSD_EVENT_ONESHOT\fR), but this may be changed with \fBsd_event_source_set_enabled\fR(3)\&. If the handler function returns a negative error code, it will either be disabled after the invocation, even if the \fBSD_EVENT_ON\fR mode was requested before, or it will cause the loop to terminate, see \fBsd_event_source_set_exit_on_failure\fR(3)\&. .PP To destroy an event source object use \fBsd_event_source_unref\fR(3), but note that the event source is only removed from the event loop when all references to the event source are dropped\&. To make sure an event source does not fire anymore, even when there\*(Aqs still a reference to it kept, consider setting the event source to \fBSD_EVENT_OFF\fR with \fBsd_event_source_set_enabled\fR(3)\&. .PP The \fBSIGCHLD\fR signal must be blocked in all threads before this function is called (using \fBsigprocmask\fR(2) or \fBpthread_sigmask\fR(3))\&. .PP If the second parameter of \fBsd_event_add_child()\fR is passed as \fBNULL\fR no reference to the event source object is returned\&. In this case the event source is considered "floating", and will be destroyed implicitly when the event loop itself is destroyed\&. .PP Note that the \fIhandler\fR function is invoked at a time where the child process is not reaped yet (and thus still is exposed as a zombie process by the kernel)\&. However, the child will be reaped automatically after the function returns\&. Child processes for which no child process state change event sources are installed will not be reaped by the event loop implementation\&. .PP If the \fIhandler\fR parameter to \fBsd_event_add_child()\fR is \fBNULL\fR, and the event source fires, this will be considered a request to exit the event loop\&. In this case, the \fIuserdata\fR parameter, cast to an integer, is passed as the exit code parameter to \fBsd_event_exit\fR(3)\&. .PP If both a child process state change event source and a \fBSIGCHLD\fR signal event source is installed in the same event loop, the configured event source priorities decide which event source is dispatched first\&. If the signal handler is processed first, it should leave the child processes for which child process state change event sources are installed unreaped\&. .PP \fBsd_event_add_child_pidfd()\fR is similar to \fBsd_event_add_child()\fR but takes a file descriptor referencing the process ("pidfd") instead of the numeric PID\&. A suitable file descriptor may be acquired via \fBpidfd_open\fR(2) and related calls\&. The passed file descriptor is not closed when the event source is freed again, unless \fBsd_event_source_set_child_pidfd_own()\fR is used to turn this behaviour on\&. Note that regardless which of \fBsd_event_add_child()\fR and \fBsd_event_add_child_pidfd()\fR is used for allocating an event source, the watched process has to be a direct child process of the invoking process\&. Also in both cases \fBSIGCHLD\fR has to be blocked in the invoking process\&. .PP \fBsd_event_source_get_child_pid()\fR retrieves the configured PID of a child process state change event source created previously with \fBsd_event_add_child()\fR\&. It takes the event source object as the \fIsource\fR parameter and a pointer to a \fBpid_t\fR variable to return the process ID in\&. .PP \fBsd_event_source_get_child_pidfd()\fR retrieves the file descriptor referencing the watched process ("pidfd") if this functionality is available\&. On kernels that support the concept the event loop will make use of pidfds to watch child processes, regardless if the individual event sources are allocated via \fBsd_event_add_child()\fR or \fBsd_event_add_child_pidfd()\fR\&. If the latter call was used to allocate the event source, this function returns the file descriptor used for allocation\&. On kernels that do not support the pidfd concept this function will fail with \fBEOPNOTSUPP\fR\&. This call takes the event source object as the \fIsource\fR parameter and returns the numeric file descriptor\&. .PP \fBsd_event_source_get_child_pidfd_own()\fR may be used to query whether the pidfd the event source encapsulates shall be closed when the event source is freed\&. This function returns zero if the pidfd shall be left open, and positive if it shall be closed automatically\&. By default this setting defaults to on if the event source was allocated via \fBsd_event_add_child()\fR and off if it was allocated via \fBsd_event_add_child_pidfd()\fR\&. The \fBsd_event_source_set_child_pidfd_own()\fR function may be used to change the setting and takes a boolean parameter with the new setting\&. .PP \fBsd_event_source_get_child_process_own()\fR may be used to query whether the process the event source watches shall be killed (with \fBSIGKILL\fR) and reaped when the event source is freed\&. This function returns zero if the process shell be left running, and positive if it shall be killed and reaped automatically\&. By default this setting defaults to off\&. The \fBsd_event_source_set_child_process_own()\fR function may be used to change the setting and takes a boolean parameter with the new setting\&. Note that currently if the calling process is terminated abnormally the watched process might survive even thought the event source ceases to exist\&. This behaviour might change eventually\&. .PP \fBsd_event_source_send_child_signal()\fR may be used to send a UNIX signal to the watched process\&. If the pidfd concept is supported in the kernel, this is implemented via \fBpidfd_send_signal\fR(2) and otherwise via \fBrt_sigqueueinfo\fR(2) (or via \fBkill\fR(2) in case \fIinfo\fR is \fBNULL\fR)\&. The specified parameters match those of these underlying system calls, except that the \fIinfo\fR is never modified (and is thus declared constant)\&. Like for the underlying system calls, the \fIflags\fR parameter currently must be zero\&. .SH "RETURN VALUE" .PP On success, these functions return 0 or a positive integer\&. On failure, they return a negative errno\-style error code\&. .SS "Errors" .PP Returned errors may indicate the following problems: .PP \fB\-ENOMEM\fR .RS 4 Not enough memory to allocate an object\&. .RE .PP \fB\-EINVAL\fR .RS 4 An invalid argument has been passed\&. This includes specifying an empty mask in \fIoptions\fR or a mask which contains values different than a combination of \fBWEXITED\fR, \fBWSTOPPED\fR, and \fBWCONTINUED\fR\&. .RE .PP \fB\-EBUSY\fR .RS 4 A handler is already installed for this child process, or \fBSIGCHLD\fR is not blocked\&. .RE .PP \fB\-ESTALE\fR .RS 4 The event loop is already terminated\&. .RE .PP \fB\-ECHILD\fR .RS 4 The event loop has been created in a different process\&. .RE .PP \fB\-EDOM\fR .RS 4 The passed event source is not a child process event source\&. .RE .PP \fB\-EOPNOTSUPP\fR .RS 4 A pidfd was requested but the kernel does not support this concept\&. .RE .SH "NOTES" .PP These APIs are implemented as a shared library, which can be compiled and linked to with the \fBlibelogind\fR\ \&\fBpkg-config\fR(1) file\&. .SH "EXAMPLE" .PP \fBExample\ \&1.\ \&Exit loop when the child terminates\fR .sp .if n \{\ .RS 4 .\} .nf /* SPDX\-License\-Identifier: MIT\-0 */ #include #include #include #include int main(int argc, char **argv) { pid_t pid = fork(); assert(pid >= 0); /* SIGCHLD signal must be blocked for sd_event_add_child to work */ sigset_t ss; sigemptyset(&ss); sigaddset(&ss, SIGCHLD); sigprocmask(SIG_BLOCK, &ss, NULL); if (pid == 0) /* child */ sleep(1); else { /* parent */ sd_event *e = NULL; int r; /* Create the default event loop */ sd_event_default(&e); assert(e); /* We create a floating child event source (attached to \*(Aqe\*(Aq)\&. * The default handler will be called with 666 as userdata, which * will become the exit value of the loop\&. */ r = sd_event_add_child(e, NULL, pid, WEXITED, NULL, (void*) 666); assert(r >= 0); r = sd_event_loop(e); assert(r == 666); sd_event_unref(e); } return 0; } .fi .if n \{\ .RE .\} .SH "SEE ALSO" .PP \fBelogind\fR(8), \fBsd-event\fR(3), \fBsd_event_new\fR(3), \fBsd_event_now\fR(3), \fBsd_event_add_io\fR(3), \fBsd_event_add_time\fR(3), \fBsd_event_add_signal\fR(3), \fBsd_event_add_inotify\fR(3), \fBsd_event_add_defer\fR(3), \fBsd_event_source_set_enabled\fR(3), \fBsd_event_source_set_priority\fR(3), \fBsd_event_source_set_userdata\fR(3), \fBsd_event_source_set_description\fR(3), \fBsd_event_source_set_floating\fR(3), \fBwaitid\fR(2), \fBsigprocmask\fR(2), \fBpthread_sigmask\fR(3), \fBpidfd_open\fR(2), \fBpidfd_send_signal\fR(2), \fBrt_sigqueueinfo\fR(2), \fBkill\fR(2)