sd_event_add_child - Man Page

Add a child process state change event source to an event loop

Synopsis

#include <systemd/sd-event​.h>
typedef struct sd_event_source sd_event_source;

typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata);

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);

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);

int sd_event_source_get_child_pid(sd_event_source *source, pid_t *ret);

int sd_event_source_get_child_pidfd(sd_event_source *source);

int sd_event_source_get_child_pidfd_own(sd_event_source *source);

int sd_event_source_set_child_pidfd_own(sd_event_source *source, int own);

int sd_event_source_get_child_process_own(sd_event_source *source);

int sd_event_source_set_child_process_own(sd_event_source *source, int own);

int sd_event_source_send_child_signal(sd_event_source *source, int sig, const siginfo_t *info, unsigned flags);

Description

sd_event_add_child() adds a new child process state change event source to an event loop​. The event loop object is specified in the event parameter, the event source object is returned in the source parameter​. The pid parameter specifies the PID of the process to watch, which must be a direct child process of the invoking process​. The options parameter determines which state changes will be watched for​. It must contain an OR-ed mask of WEXITED (watch for the child process terminating), WSTOPPED (watch for the child process being stopped by a signal), WCONTINUED (watch for the child process being resumed by a signal) and WNOWAIT (Do not reap the child process after it exits)​. See waitid(2) for further information​.

The handler must be a function to call when the process changes state or NULL​. The handler function will be passed the userdata 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 handler is NULL, a default handler that calls sd_event_exit(3) will be used​.

Only a single handler may be installed for a specific child process​. The handler is enabled for a single event (SD_EVENT_ONESHOT), but this may be changed with sd_event_source_set_enabled(3)​. If the handler function returns a negative error code, it will either be disabled after the invocation, even if the SD_EVENT_ON mode was requested before, or it will cause the loop to terminate, see sd_event_source_set_exit_on_failure(3)​.

To destroy an event source object use sd_event_source_unref(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's still a reference to it kept, consider setting the event source to SD_EVENT_OFF with sd_event_source_set_enabled(3)​.

The kernel autoreaping logic must be disabled for this function to work as expected (see signal(7))​.

When watching for WSTOPPED or WCONTINUED, the SIGCHLD signal must be blocked in all threads before this function is called (using sigprocmask(2) or pthread_sigmask(3))​.

If the second parameter of sd_event_add_child() is passed as NULL 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​.

Note that the handler 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​.

If the handler parameter to sd_event_add_child() is NULL, and the event source fires, this will be considered a request to exit the event loop​. In this case, the userdata parameter, cast to an integer, is passed as the exit code parameter to sd_event_exit(3)​.

If both a child process state change event source and a SIGCHLD 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​.

sd_event_add_child_pidfd() is similar to sd_event_add_child() but takes a file descriptor referencing the process ("pidfd") instead of the numeric PID​. A suitable file descriptor may be acquired via pidfd_open(2) and related calls​. The passed file descriptor is not closed when the event source is freed again, unless sd_event_source_set_child_pidfd_own() is used to turn this behaviour on​. Note that regardless which of sd_event_add_child() and sd_event_add_child_pidfd() 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 SIGCHLD has to be blocked in the invoking process when watching for WSTOPPED or WCONTINUED and the kernel autoreaping logic has to be disabled​.

sd_event_source_get_child_pid() retrieves the configured PID of a child process state change event source created previously with sd_event_add_child()​. It takes the event source object as the source parameter and a pointer to a pid_t variable to return the process ID in​.

sd_event_source_get_child_pidfd() retrieves the file descriptor referencing the watched process ("pidfd")​. The event loop internally makes use of pidfds to watch child processes, regardless of whether the individual event sources are allocated via sd_event_add_child() or sd_event_add_child_pidfd()​. If the latter call was used to allocate the event source, this function returns the original file descriptor used for allocation​. This call takes the event source object as the source parameter and returns the numeric file descriptor​.

sd_event_source_get_child_pidfd_own() 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 sd_event_add_child() and off if it was allocated via sd_event_add_child_pidfd()​. The sd_event_source_set_child_pidfd_own() function may be used to change the setting and takes a boolean parameter with the new setting​.

sd_event_source_get_child_process_own() may be used to query whether the process the event source watches shall be killed (with SIGKILL) 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 sd_event_source_set_child_process_own() 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​.

sd_event_source_send_child_signal() may be used to send a UNIX signal to the watched process via pidfd_send_signal(2)​. The specified parameters match those of the underlying system call, except that the info is never modified (and is thus declared constant)​. Like for the underlying system call, the flags parameter currently must be zero​.

Return Value

On success, these functions return 0 or a positive integer​. On failure, they return a negative errno-style error code​.

Errors

Returned errors may indicate the following problems:

-ENOMEM

Not enough memory to allocate an object​.

-EINVAL

An invalid argument has been passed​. This includes specifying an empty mask in options or a mask which contains values different than a combination of WEXITED, WSTOPPED, and WCONTINUED​.

-EBUSY

A handler is already installed for this child process, or SIGCHLD is not blocked​.

-ESTALE

The event loop is already terminated​.

-ECHILD

The event loop has been created in a different process, library or module instance​.

-EDOM

The passed event source is not a child process event source​.

Notes

Functions described here are available as a shared library, which can be compiled against and linked to with the libsystemd ​pkg-config(1) file​.

All functions listed here are thread-agnostic and only a single thread may operate on a given object at any given time​. Different threads may access the same object at different times​. Multiple independent objects may be used from different threads in parallel​.

The code described here uses getenv(3), which is declared to be not multi-thread-safe​. This means that the code calling the functions described here must not call setenv(3) from a parallel thread​. It is recommended to only do calls to setenv() from an early phase of the program when no other threads have been started​.

Example

Example ​1. ​Exit loop when the child terminates

/* SPDX-License-Identifier: MIT-0 */

#define _GNU_SOURCE 1
#include <assert​.h>
#include <stdio​.h>
#include <unistd​.h>
#include <systemd/sd-event​.h>

int main(int argc, char **argv) {
  pid_t pid = fork();
  assert(pid >= 0);

  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 'e')​.
     * 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;
}

History

sd_event_add_child(), sd_event_child_handler_t(), and sd_event_source_get_child_pid() were added in version 217​.

sd_event_add_child_pidfd(), 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(), and sd_event_source_send_child_signal() were added in version 245​.

See Also

systemd(1), sd-event(3), sd_event_new(3), sd_event_now(3), sd_event_add_io(3), sd_event_add_time(3), sd_event_add_signal(3), sd_event_add_inotify(3), sd_event_add_defer(3), sd_event_source_set_enabled(3), sd_event_source_set_priority(3), sd_event_source_set_userdata(3), sd_event_source_set_description(3), sd_event_source_set_floating(3), waitid(2), sigprocmask(2), pthread_sigmask(3), pidfd_open(2), pidfd_send_signal(2), rt_sigqueueinfo(2), kill(2)

Info

systemd 262