<citerefentry
project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>).</para>
- <para>If the second parameter of
- <function>sd_event_add_child()</function> 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.</para>
+ <para>If the second parameter of <function>sd_event_add_child()</function> is passed as
+ <constant>NULL</constant> 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.</para>
<para>Note that the <parameter>handler</parameter> function is
invoked at a time where the child process is not reaped yet (and
event sources are installed will not be reaped by the event loop
implementation.</para>
+ <para>If the <parameter>handler</parameter> parameter to <function>sd_event_add_child()</function> is
+ <constant>NULL</constant>, and the event source fires, this will be considered a request to exit the
+ event loop. In this case, the <parameter>userdata</parameter> parameter, cast to an integer, is passed as
+ the exit code parameter to
+ <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+
<para>If both a child process state change event source and a
<constant>SIGCHLD</constant> signal event source is installed in
the same event loop, the configured event source priorities decide
<constant>SD_EVENT_OFF</constant> with
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
- <para>If the second parameter of these functions 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.</para>
+ <para>If the second parameter of these functions is passed as <constant>NULL</constant> 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.</para>
+
+ <para>If the <parameter>handler</parameter> parameter to <function>sd_event_add_defer()</function> or
+ <function>sd_event_add_post()</function> is <constant>NULL</constant>, and the event source fires, this
+ will be considered a request to exit the event loop. In this case, the <parameter>userdata</parameter>
+ parameter, cast to an integer, is passed as the exit code parameter to
+ <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>. Similar
+ functionality is not available for <function>sd_event_add_exit()</function>, as these types of event
+ sources are only dispatched when exiting anyway.</para>
</refsect1>
<refsect1>
it with
<citerefentry><refentrytitle>sd_event_source_set_enabled</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
- <para>If the second parameter of <function>sd_event_add_inotify()</function> 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.</para>
+ <para>If the second parameter of <function>sd_event_add_inotify()</function> is passed as
+ <constant>NULL</constant> 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.</para>
+
+ <para>If the <parameter>handler</parameter> parameter to <function>sd_event_add_inotify()</function> is
+ <constant>NULL</constant>, and the event source fires, this will be considered a request to exit the
+ event loop. In this case, the <parameter>userdata</parameter> parameter, cast to an integer, is passed as
+ the exit code parameter to
+ <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
<para><function>sd_event_source_get_inotify_mask()</function> retrieves the configured inotify watch mask of an
event source created previously with <function>sd_event_add_inotify()</function>. It takes the event source object
"floating", and will be destroyed implicitly when the event loop
itself is destroyed.</para>
+ <para>If the <parameter>handler</parameter> to <function>sd_event_add_io()</function> is
+ <constant>NULL</constant>, and the event source fires, this will be considered a request to exit the
+ event loop. In this case, the <parameter>userdata</parameter> parameter, cast to an integer, is passed as
+ the exit code parameter to
+ <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+
<para>Note that this call does not take possession of the file descriptor passed in, ownership (and thus
the duty to close it when it is no longer needed) remains with the caller. However, with the
<function>sd_event_source_set_io_fd_own()</function> call (see below) the event source may optionally
threads before this function is called (using <citerefentry
project='man-pages'><refentrytitle>sigprocmask</refentrytitle><manvolnum>2</manvolnum></citerefentry> or
<citerefentry
- project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>). If
- the handler is not specified (<parameter>handler</parameter> is <constant>NULL</constant>), a default
- handler which causes the program to exit cleanly will be used.</para>
+ project='man-pages'><refentrytitle>pthread_sigmask</refentrytitle><manvolnum>3</manvolnum></citerefentry>).</para>
<para>By default, the event source is enabled permanently
(<constant>SD_EVENT_ON</constant>), but this may be changed with
"floating", and will be destroyed implicitly when the event loop
itself is destroyed.</para>
+ <para>If the <parameter>handler</parameter> parameter to <function>sd_event_add_signal()</function> is
+ <constant>NULL</constant>, and the event source fires, this will be considered a request to exit the
+ event loop. In this case, the <parameter>userdata</parameter> parameter, cast to an integer, is passed as
+ the exit code parameter to
+ <citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+
<para><function>sd_event_source_get_signal()</function> returns
the configured signal number of an event source created previously
with <function>sd_event_add_signal()</function>. It takes the
"floating", and will be destroyed implicitly when the event loop
itself is destroyed.</para>
- <para>If the <parameter>handler</parameter> to
- <function>sd_event_add_time()</function> is
- <constant>NULL</constant>, and the event source fires, this will
- be considered a request to exit the event loop. In this case, the
- <parameter>userdata</parameter> parameter, cast to an integer, is
- used for the exit code passed to
+ <para>If the <parameter>handler</parameter> parameter to <function>sd_event_add_time()</function> is
+ <constant>NULL</constant>, and the event source fires, this will be considered a request to exit the
+ event loop. In this case, the <parameter>userdata</parameter> parameter, cast to an integer, is passed as
+ the exit code parameter to
<citerefentry><refentrytitle>sd_event_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
<para>Use <constant>CLOCK_BOOTTIME_ALARM</constant> and
conflict with regular exit codes returned by
<function>sd_event_loop()</function>, if these exit codes shall be
distinguishable.</para>
+
+ <para>Note that for most event source types passing the callback pointer as <constant>NULL</constant> in
+ the respective constructor call (i.e. in
+ <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ …) has the effect of <function>sd_event_exit()</function> being invoked once the event source triggers,
+ with the specified userdata pointer cast to an integer as the exit code parameter. This is useful to
+ automatically terminate an event loop after some condition, such as a time-out or reception of
+ <constant>SIGTERM</constant> or similar. See the documentation for the respective constructor call for
+ details.</para>
</refsect1>
<refsect1>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-event</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_event_new</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_time</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_signal</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_io</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_defer</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>sd_event_add_inotify</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
return s;
}
+static int io_exit_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+ assert(s);
+
+ return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
+}
+
_public_ int sd_event_add_io(
sd_event *e,
sd_event_source **ret,
assert_return(e = event_resolve(e), -ENOPKG);
assert_return(fd >= 0, -EBADF);
assert_return(!(events & ~(EPOLLIN|EPOLLOUT|EPOLLRDHUP|EPOLLPRI|EPOLLERR|EPOLLHUP|EPOLLET)), -EINVAL);
- assert_return(callback, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
+ if (!callback)
+ callback = io_exit_callback;
+
s = source_new(e, !ret, SOURCE_IO);
if (!s)
return -ENOMEM;
return 0;
}
+static int child_exit_callback(sd_event_source *s, const siginfo_t *si, void *userdata) {
+ assert(s);
+
+ return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
+}
+
static bool shall_use_pidfd(void) {
/* Mostly relevant for debugging, i.e. this is used in test-event.c to test the event loop once with and once without pidfd */
return getenv_bool_secure("SYSTEMD_PIDFD") != 0;
assert_return(pid > 1, -EINVAL);
assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL);
assert_return(options != 0, -EINVAL);
- assert_return(callback, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
+ if (!callback)
+ callback = child_exit_callback;
+
if (e->n_enabled_child_sources == 0) {
/* Caller must block SIGCHLD before using us to watch children, even if pidfd is available,
* for compatibility with pre-pidfd and because we don't want the reap the child processes
assert_return(pidfd >= 0, -EBADF);
assert_return(!(options & ~(WEXITED|WSTOPPED|WCONTINUED)), -EINVAL);
assert_return(options != 0, -EINVAL);
- assert_return(callback, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
+ if (!callback)
+ callback = child_exit_callback;
+
if (e->n_enabled_child_sources == 0) {
r = signal_is_blocked(SIGCHLD);
if (r < 0)
return 0;
}
+static int generic_exit_callback(sd_event_source *s, void *userdata) {
+ assert(s);
+
+ return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
+}
+
_public_ int sd_event_add_defer(
sd_event *e,
sd_event_source **ret,
assert_return(e, -EINVAL);
assert_return(e = event_resolve(e), -ENOPKG);
- assert_return(callback, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
+ if (!callback)
+ callback = generic_exit_callback;
+
s = source_new(e, !ret, SOURCE_DEFER);
if (!s)
return -ENOMEM;
assert_return(e, -EINVAL);
assert_return(e = event_resolve(e), -ENOPKG);
- assert_return(callback, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
+ if (!callback)
+ callback = generic_exit_callback;
+
s = source_new(e, !ret, SOURCE_POST);
if (!s)
return -ENOMEM;
return 1;
}
+static int inotify_exit_callback(sd_event_source *s, const struct inotify_event *event, void *userdata) {
+ assert(s);
+
+ return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata));
+}
+
_public_ int sd_event_add_inotify(
sd_event *e,
sd_event_source **ret,
assert_return(e, -EINVAL);
assert_return(e = event_resolve(e), -ENOPKG);
assert_return(path, -EINVAL);
- assert_return(callback, -EINVAL);
assert_return(e->state != SD_EVENT_FINISHED, -ESTALE);
assert_return(!event_pid_changed(e), -ECHILD);
+ if (!callback)
+ callback = inotify_exit_callback;
+
/* Refuse IN_MASK_ADD since we coalesce watches on the same inode, and hence really don't want to merge
* masks. Or in other words, this whole code exists only to manage IN_MASK_ADD type operations for you, hence
* the user can't use them for us. */