]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-event: support callback=NULL in IO/child/inotify/defer event sources, too
authorLennart Poettering <lennart@poettering.net>
Fri, 2 Oct 2020 07:51:36 +0000 (09:51 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 7 Oct 2020 07:40:16 +0000 (09:40 +0200)
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.

man/sd_event_add_child.xml
man/sd_event_add_defer.xml
man/sd_event_add_inotify.xml
man/sd_event_add_io.xml
man/sd_event_add_signal.xml
man/sd_event_add_time.xml
man/sd_event_exit.xml
src/libsystemd/sd-event/sd-event.c

index 1db536ff2ad133a5021626d7c483533c99aa9cfb..74ebe6d2641a5edb9e7ff085c38cb36d8599723c 100644 (file)
     <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
index 92be8353e647d08584f7c6d8de9b62712401dbb2..d1d6d980ee9d04fd3ae70f94229a73e4a9a86e66 100644 (file)
     <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>
index 826f4c4ada0a08361cf6c4c99a099ec121207155..27d43853e65facf73d982c6a0959912689118516 100644 (file)
     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
index 35d02a17000c8dac6f08ccee3f1e80ba77e6c1b2..51238f47555bb90e786af8f784d5ffa03a236831 100644 (file)
     "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
index 43794bd7ceb683cf896aa00a194d282b3bd22111..85de53120f1e57349658040d1aac2b7abda3f9b3 100644 (file)
@@ -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
     "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
index 1fc24c8ab07994a42f295926049cefcd28638811..24a316f9edd7b6317e70dd7ee47d4f4f729458d8 100644 (file)
     "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
index a02897af0b3a7cca679aae34abac9c3640503b06..53aed7001267a89ea5f366d53c8354b856d1c38e 100644 (file)
     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>
 
index e891f62bb7ae5adc278f4e2d7de37677e483b9a1..d3df2e13090c4b5b4eccebd7b9b002a216285a0d 100644 (file)
@@ -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. */