sysdeps-unix: Factor out _dbus_reset_oom_score_adj
authorSimon McVittie <smcv@collabora.com>
Mon, 21 Feb 2022 15:41:41 +0000 (15:41 +0000)
committerSimon McVittie <smcv@collabora.com>
Fri, 25 Feb 2022 14:57:18 +0000 (14:57 +0000)
Signed-off-by: Simon McVittie <smcv@collabora.com>
(cherry picked from commit f3ffe9a873708c679df88b9fc12b6b831539cf8a)

dbus/dbus-spawn.c
dbus/dbus-sysdeps-unix.h
dbus/dbus-sysdeps-util-unix.c

index 61c7e61..b4aff67 100644 (file)
@@ -1397,26 +1397,14 @@ _dbus_spawn_async_with_babysitter (DBusBabysitter          **sitter_p,
        }
       else if (grandchild_pid == 0)
         {
-#ifdef __linux__
-          int fd = -1;
+          const char *error_str = NULL;
 
-#ifdef O_CLOEXEC
-          fd = open ("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
-#endif
-
-          if (fd < 0)
+          if (!_dbus_reset_oom_score_adj (&error_str))
             {
-              fd = open ("/proc/self/oom_score_adj", O_WRONLY);
-              _dbus_fd_set_close_on_exec (fd);
+              /* TODO: Strictly speaking, this is not async-signal-safe. */
+              _dbus_warn ("%s: %s", error_str, strerror (errno));
             }
 
-          if (fd >= 0)
-            {
-              if (write (fd, "0", sizeof (char)) < 0)
-                _dbus_warn ("writing oom_score_adj error: %s", strerror (errno));
-              _dbus_close (fd, NULL);
-            }
-#endif
           /* Go back to ignoring SIGPIPE, since it's evil
            */
           signal (SIGPIPE, SIG_IGN);
index 830d5cd..5de8b73 100644 (file)
@@ -173,6 +173,8 @@ typedef void (* DBusSignalHandler) (int sig);
 void _dbus_set_signal_handler (int               sig,
                                DBusSignalHandler handler);
 
+dbus_bool_t _dbus_reset_oom_score_adj (const char **error_str_p);
+
 /** @} */
 
 DBUS_END_DECLS
index cc7bbe6..dcf6dcf 100644 (file)
@@ -1571,3 +1571,68 @@ _dbus_test_append_different_username (DBusString *username)
 }
 
 #endif
+
+/**
+ * If the current process has been protected from the Linux OOM killer
+ * (the oom_score_adj process parameter is negative), reset it to the
+ * default level of protection from the OOM killer (set oom_score_adj
+ * to zero).
+ *
+ * This function does not use DBusError, to avoid calling malloc(), so
+ * that it can be used in contexts where an async-signal-safe function
+ * is required (for example after fork()). Instead, on failure it sets
+ * errno and returns something like "Failed to open /dev/null" in
+ * *error_str_p. Callers are expected to combine *error_str_p
+ * with _dbus_strerror (errno) to get a full error report.
+ */
+dbus_bool_t
+_dbus_reset_oom_score_adj (const char **error_str_p)
+{
+#ifdef __linux__
+  int fd = -1;
+  dbus_bool_t ret = FALSE;
+  int saved_errno = 0;
+  const char *error_str = NULL;
+
+#ifdef O_CLOEXEC
+  fd = open ("/proc/self/oom_score_adj", O_WRONLY | O_CLOEXEC);
+#endif
+
+  if (fd < 0)
+    {
+      fd = open ("/proc/self/oom_score_adj", O_WRONLY);
+      _dbus_fd_set_close_on_exec (fd);
+    }
+
+  if (fd >= 0)
+    {
+      if (write (fd, "0", sizeof (char)) < 0)
+        {
+          ret = FALSE;
+          error_str = "writing oom_score_adj error";
+          saved_errno = errno;
+        }
+      else
+        {
+          ret = TRUE;
+        }
+
+      _dbus_close (fd, NULL);
+    }
+  else
+    {
+      /* TODO: Historically we ignored this error, although ideally we
+       * would diagnose it */
+      ret = TRUE;
+    }
+
+  if (error_str_p != NULL)
+    *error_str_p = error_str;
+
+  errno = saved_errno;
+  return ret;
+#else
+  /* nothing to do on this platform */
+  return TRUE;
+#endif
+}