[glib: 1/2] gspawn: Use CLOSE_RANGE_CLOEXEC if available




commit b5556a2c6831825fab90c03f8834d298194d8202
Author: Philip Withnall <pwithnall endlessos org>
Date:   Fri Jul 9 12:40:47 2021 +0100

    gspawn: Use CLOSE_RANGE_CLOEXEC if available
    
    It’s a new flag added to `close_range()` in kernel 5.11, which will
    allow us to speed up setting `CLOEXEC` on ranges of file descriptors.
    
    This currently happens in some situations when executing a new binary
    with `GSpawn`.
    
    Signed-off-by: Philip Withnall <pwithnall endlessos org>

 glib/gspawn.c | 24 +++++++++++++++++++++++-
 1 file changed, 23 insertions(+), 1 deletion(-)
---
diff --git a/glib/gspawn.c b/glib/gspawn.c
index 3073a10a4..98986d8a7 100644
--- a/glib/gspawn.c
+++ b/glib/gspawn.c
@@ -1482,6 +1482,28 @@ safe_fdwalk (int (*cb)(void *data, int fd), void *data)
 #endif
 }
 
+/* This function is called between fork() and exec() and hence must be
+ * async-signal-safe (see signal-safety(7)). */
+static void
+safe_fdwalk_set_cloexec (int lowfd)
+{
+#if defined(HAVE_CLOSE_RANGE) && defined(CLOSE_RANGE_CLOEXEC)
+  /* close_range() is available in Linux since kernel 5.9, and on FreeBSD at
+   * around the same time. It was designed for use in async-signal-safe
+   * situations: https://bugs.python.org/issue38061
+   *
+   * The `CLOSE_RANGE_CLOEXEC` flag was added in Linux 5.11, and is not yet
+   * present in FreeBSD.
+   *
+   * Handle ENOSYS in case it’s supported in libc but not the kernel; if so,
+   * fall back to safe_fdwalk(). Handle EINVAL in case `CLOSE_RANGE_CLOEXEC`
+   * is not supported. */
+  if (close_range (lowfd, G_MAXUINT, CLOSE_RANGE_CLOEXEC) != 0 &&
+      (errno == ENOSYS || errno == EINVAL))
+#endif  /* HAVE_CLOSE_RANGE */
+  (void) safe_fdwalk (set_cloexec, GINT_TO_POINTER (lowfd));
+}
+
 /* This function is called between fork() and exec() and hence must be
  * async-signal-safe (see signal-safety(7)). */
 static void
@@ -1689,7 +1711,7 @@ do_exec (gint                  child_err_report_fd,
         }
       else
         {
-          safe_fdwalk (set_cloexec, GINT_TO_POINTER (3));
+          safe_fdwalk_set_cloexec (3);
         }
     }
   else


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]