sysdeps-unix: Factor out _dbus_reset_oom_score_adj

Signed-off-by: Simon McVittie <smcv@collabora.com>
This commit is contained in:
Simon McVittie 2022-02-21 15:41:41 +00:00
parent 715a1a920d
commit f3ffe9a873
3 changed files with 71 additions and 16 deletions

View file

@ -1444,26 +1444,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);

View file

@ -174,6 +174,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

View file

@ -1603,3 +1603,68 @@ _dbus_daemon_report_stopping (void)
sd_notify (0, "STOPPING=1");
#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
}