summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2020-10-02 09:51:36 +0200
committerLennart Poettering <lennart@poettering.net>2020-10-07 09:40:16 +0200
commitb9350e70aa050d97c47ff59994e84fa8c3de4738 (patch)
tree467bb5ba1acd7393c22cab9c002955d560b5a9b3
parentbac0bfc1d0ee1e57055dffb78c77a1ee021ce536 (diff)
downloadsystemd-b9350e70aa050d97c47ff59994e84fa8c3de4738.tar.gz
sd-event: support callback=NULL in IO/child/inotify/defer event sources, too
Also, document this functionality more prominently, including with a reference from sd_event_exit(). This is mostly to make things complete, as previously we supported NULL callbacks only in _add_time() and _add_signal(). However, I think this makes snese for IO event sources too (think: when some fd such as a pipe end sees SIGHUP or so, exit), as well as defer or post event sources (i.e. exit once we got nothing else to do). This also adds support for inotify event sources, simply to complete things (I can't see the immediate use, but maybe someone else comes up with it). The only event source type that doesn't allow callback=NULL now are exit callbacks, but for them they make little sense, as the event loop is exiting then anyway.
-rw-r--r--man/sd_event_add_child.xml15
-rw-r--r--man/sd_event_add_defer.xml16
-rw-r--r--man/sd_event_add_inotify.xml13
-rw-r--r--man/sd_event_add_io.xml6
-rw-r--r--man/sd_event_add_signal.xml10
-rw-r--r--man/sd_event_add_time.xml10
-rw-r--r--man/sd_event_exit.xml17
-rw-r--r--src/libsystemd/sd-event/sd-event.c48
8 files changed, 106 insertions, 29 deletions
diff --git a/man/sd_event_add_child.xml b/man/sd_event_add_child.xml
index 1db536ff2a..74ebe6d264 100644
--- a/man/sd_event_add_child.xml
+++ b/man/sd_event_add_child.xml
@@ -150,11 +150,10 @@
<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
@@ -164,6 +163,12 @@
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
diff --git a/man/sd_event_add_defer.xml b/man/sd_event_add_defer.xml
index 92be8353e6..d1d6d980ee 100644
--- a/man/sd_event_add_defer.xml
+++ b/man/sd_event_add_defer.xml
@@ -116,11 +116,17 @@
<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>
diff --git a/man/sd_event_add_inotify.xml b/man/sd_event_add_inotify.xml
index 826f4c4ada..27d43853e6 100644
--- a/man/sd_event_add_inotify.xml
+++ b/man/sd_event_add_inotify.xml
@@ -95,9 +95,16 @@
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
diff --git a/man/sd_event_add_io.xml b/man/sd_event_add_io.xml
index 35d02a1700..51238f4755 100644
--- a/man/sd_event_add_io.xml
+++ b/man/sd_event_add_io.xml
@@ -161,6 +161,12 @@
"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
diff --git a/man/sd_event_add_signal.xml b/man/sd_event_add_signal.xml
index 43794bd7ce..85de53120f 100644
--- a/man/sd_event_add_signal.xml
+++ b/man/sd_event_add_signal.xml
@@ -79,9 +79,7 @@
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
@@ -107,6 +105,12 @@
"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
diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml
index 1fc24c8ab0..24a316f9ed 100644
--- a/man/sd_event_add_time.xml
+++ b/man/sd_event_add_time.xml
@@ -161,12 +161,10 @@
"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
diff --git a/man/sd_event_exit.xml b/man/sd_event_exit.xml
index a02897af0b..53aed70012 100644
--- a/man/sd_event_exit.xml
+++ b/man/sd_event_exit.xml
@@ -74,6 +74,16 @@
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>
@@ -128,7 +138,12 @@
<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>
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
index e891f62bb7..d3df2e1309 100644
--- a/src/libsystemd/sd-event/sd-event.c
+++ b/src/libsystemd/sd-event/sd-event.c
@@ -972,6 +972,12 @@ static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType t
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,
@@ -987,10 +993,12 @@ _public_ int sd_event_add_io(
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;
@@ -1235,6 +1243,12 @@ _public_ int sd_event_add_signal(
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;
@@ -1256,10 +1270,12 @@ _public_ int sd_event_add_child(
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
@@ -1357,10 +1373,12 @@ _public_ int sd_event_add_child_pidfd(
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)
@@ -1426,6 +1444,12 @@ _public_ int sd_event_add_child_pidfd(
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,
@@ -1437,10 +1461,12 @@ _public_ int sd_event_add_defer(
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;
@@ -1471,10 +1497,12 @@ _public_ int sd_event_add_post(
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;
@@ -1826,6 +1854,12 @@ static int inode_data_realize_watch(sd_event *e, struct inode_data *d) {
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,
@@ -1844,10 +1878,12 @@ _public_ int sd_event_add_inotify(
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. */