From edf9257de43d9774ae797858f4bdeb3d8db6b5d1 Mon Sep 17 00:00:00 2001 From: Kai Krakow Date: Mon, 8 Oct 2018 21:49:28 +0200 Subject: [PATCH] refactor: Break sched API functions out of the main daemon source Signed-off-by: Kai Krakow --- daemon/gamemode-sched.c | 157 ++++++++++++++++++++++++++++++++++++++++ daemon/gamemode.c | 114 +---------------------------- daemon/gamemode.h | 7 ++ daemon/meson.build | 1 + 4 files changed, 167 insertions(+), 112 deletions(-) create mode 100644 daemon/gamemode-sched.c diff --git a/daemon/gamemode-sched.c b/daemon/gamemode-sched.c new file mode 100644 index 0000000..cd2a2ed --- /dev/null +++ b/daemon/gamemode-sched.c @@ -0,0 +1,157 @@ +/* + +Copyright (c) 2017-2018, Feral Interactive +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Feral Interactive nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + */ + +#define _GNU_SOURCE + +#include "daemon_config.h" +#include "gamemode.h" +#include "logging.h" + +#include +#include +#include +#include +#include + +/** + * Priority to renice the process to. + */ +#define NICE_DEFAULT_PRIORITY -4 + +/** + * Apply scheduling policies + * + * This tries to change the scheduler of the client to soft realtime mode + * available in some kernels as SCHED_ISO. It also tries to adjust the nice + * level. If some of each fail, ignore this and log a warning. + * + * We don't need to store the current values because when the client exits, + * everything will be good: Scheduling is only applied to the client and + * its children. + */ +void game_mode_apply_renice(const GameModeContext *self, const pid_t client) +{ + GameModeConfig *config = game_mode_config_from_context(self); + + /* + * read configuration "renice" (1..20) + */ + long int renice = 0; + config_get_renice_value(config, &renice); + if ((renice < 1) || (renice > 20)) { + LOG_ERROR("Invalid renice value '%ld' reset to default: %d.\n", + renice, + -NICE_DEFAULT_PRIORITY); + renice = NICE_DEFAULT_PRIORITY; + } else { + renice = -renice; + } + + /* + * don't adjust priority if it was already adjusted + */ + if (getpriority(PRIO_PROCESS, (id_t)client) != 0) { + LOG_ERROR("Refused to renice client [%d]: already reniced\n", client); + } else if (setpriority(PRIO_PROCESS, (id_t)client, (int)renice)) { + LOG_ERROR( + "Failed to renice client [%d], ignoring error condition: %s\n" + " -- Your user may not have permission to do this. Please read the docs\n" + " -- to learn how to adjust the pam limits.\n", + client, + strerror(errno)); + } +} + +void game_mode_apply_scheduling(const GameModeContext *self, const pid_t client) +{ + GameModeConfig *config = game_mode_config_from_context(self); + + /* + * read configuration "softrealtime" (on, off, auto) + */ + char softrealtime[CONFIG_VALUE_MAX] = { 0 }; + config_get_soft_realtime(config, softrealtime); + + /* + * Enable unconditionally or auto-detect soft realtime usage, + * auto detection is based on observations where dual-core CPU suffered + * priority inversion problems with the graphics driver thus running + * slower as a result, so enable only with more than 3 cores. + */ + bool enable_softrealtime = (strcmp(softrealtime, "on") == 0) || (get_nprocs() > 3); + + /* + * Actually apply the scheduler policy if not explicitly turned off + */ + if (!(strcmp(softrealtime, "off") == 0) && (enable_softrealtime)) { + const struct sched_param p = { .sched_priority = 0 }; + if (sched_setscheduler(client, SCHED_ISO | SCHED_RESET_ON_FORK, &p)) { + const char *additional_message = ""; + switch (errno) { + case EPERM: { + static int once = 0; + if (once++) + break; + additional_message = + " -- The error indicates that you may be running a resource management\n" + " -- daemon managing your game launcher and it leaks lower scheduling\n" + " -- classes into the games. This is likely a bug in the management daemon\n" + " -- and not a bug in GameMode, it should be reported upstream.\n" + " -- If unsure, please also look here:\n" + " -- https://github.com/FeralInteractive/gamemode/issues/68\n"; + break; + } + case EINVAL: { + static int once = 0; + if (once++) + break; + additional_message = + " -- The error indicates that your kernel may not support this. If you\n" + " -- don't know what SCHED_ISO means, you can safely ignore this. If you\n" + " -- expected it to work, ensure you're running a kernel with MuQSS or\n" + " -- PDS scheduler.\n" + " -- For further technical reading on the topic start here:\n" + " -- https://lwn.net/Articles/720227/\n"; + break; + } + } + LOG_ERROR( + "Failed setting client [%d] into SCHED_ISO mode, ignoring error condition: %s\n%s", + client, + strerror(errno), + additional_message); + } + } else { + LOG_ERROR("Skipped setting client [%d] into SCHED_ISO mode: softrealtime setting is '%s'\n", + client, + softrealtime); + } +} diff --git a/daemon/gamemode.c b/daemon/gamemode.c index 3d4a1e7..79da96c 100644 --- a/daemon/gamemode.c +++ b/daemon/gamemode.c @@ -41,13 +41,9 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include #include -#include #include #include -#include -#include #include /* SCHED_ISO may not be defined as it is a reserved value not yet @@ -57,10 +53,6 @@ POSSIBILITY OF SUCH DAMAGE. #define SCHED_ISO 4 #endif -/* Priority to renice the process to. - */ -#define NICE_DEFAULT_PRIORITY -4 - /** * The GameModeClient encapsulates the remote connection, providing a list * form to contain the pid and credentials. @@ -167,109 +159,6 @@ void game_mode_context_destroy(GameModeContext *self) pthread_rwlock_destroy(&self->rwlock); } -/** - * Apply scheduling policies - * - * This tries to change the scheduler of the client to soft realtime mode - * available in some kernels as SCHED_ISO. It also tries to adjust the nice - * level. If some of each fail, ignore this and log a warning. - * - * We don't need to store the current values because when the client exits, - * everything will be good: Scheduling is only applied to the client and - * its children. - */ -static void game_mode_apply_scheduler(GameModeContext *self, pid_t client) -{ - /* - * read configuration "renice" (1..20) - */ - long int renice = 0; - config_get_renice_value(self->config, &renice); - if ((renice < 1) || (renice > 20)) { - LOG_ERROR("Invalid renice value '%ld' reset to default: %d.\n", - renice, - -NICE_DEFAULT_PRIORITY); - renice = NICE_DEFAULT_PRIORITY; - } else { - renice = -renice; - } - - /* - * don't adjust priority if it was already adjusted - */ - if (getpriority(PRIO_PROCESS, (id_t)client) != 0) { - LOG_ERROR("Refused to renice client [%d]: already reniced\n", client); - } else if (setpriority(PRIO_PROCESS, (id_t)client, (int)renice)) { - LOG_ERROR( - "Failed to renice client [%d], ignoring error condition: %s\n" - " -- Your user may not have permission to do this. Please read the docs\n" - " -- to learn how to adjust the pam limits.\n", - client, - strerror(errno)); - } - - /* - * read configuration "softrealtime" (on, off, auto) - */ - char softrealtime[CONFIG_VALUE_MAX] = { 0 }; - config_get_soft_realtime(self->config, softrealtime); - - /* - * Enable unconditionally or auto-detect soft realtime usage, - * auto detection is based on observations where dual-core CPU suffered - * priority inversion problems with the graphics driver thus running - * slower as a result, so enable only with more than 3 cores. - */ - bool enable_softrealtime = (strcmp(softrealtime, "on") == 0) || (get_nprocs() > 3); - - /* - * Actually apply the scheduler policy if not explicitly turned off - */ - if (!(strcmp(softrealtime, "off") == 0) && (enable_softrealtime)) { - const struct sched_param p = { .sched_priority = 0 }; - if (sched_setscheduler(client, SCHED_ISO | SCHED_RESET_ON_FORK, &p)) { - const char *additional_message = ""; - switch (errno) { - case EPERM: { - static int once = 0; - if (once++) - break; - additional_message = - " -- The error indicates that you may be running a resource management\n" - " -- daemon managing your game launcher and it leaks lower scheduling\n" - " -- classes into the games. This is likely a bug in the management daemon\n" - " -- and not a bug in GameMode, it should be reported upstream.\n" - " -- If unsure, please also look here:\n" - " -- https://github.com/FeralInteractive/gamemode/issues/68\n"; - break; - } - case EINVAL: { - static int once = 0; - if (once++) - break; - additional_message = - " -- The error indicates that your kernel may not support this. If you\n" - " -- don't know what SCHED_ISO means, you can safely ignore this. If you\n" - " -- expected it to work, ensure you're running a kernel with MuQSS or\n" - " -- PDS scheduler.\n" - " -- For further technical reading on the topic start here:\n" - " -- https://lwn.net/Articles/720227/\n"; - break; - } - } - LOG_ERROR( - "Failed setting client [%d] into SCHED_ISO mode, ignoring error condition: %s\n%s", - client, - strerror(errno), - additional_message); - } - } else { - LOG_ERROR("Skipped setting client [%d] into SCHED_ISO mode: softrealtime setting is '%s'\n", - client, - softrealtime); - } -} - /** * Apply io priorities * @@ -539,7 +428,8 @@ bool game_mode_context_register(GameModeContext *self, pid_t client) } /* Apply scheduler policies */ - game_mode_apply_scheduler(self, client); + game_mode_apply_renice(self, client); + game_mode_apply_scheduling(self, client); /* Apply io priorities */ game_mode_apply_ioprio(self, client); diff --git a/daemon/gamemode.h b/daemon/gamemode.h index 201cf85..ab41576 100644 --- a/daemon/gamemode.h +++ b/daemon/gamemode.h @@ -110,3 +110,10 @@ char *game_mode_lookup_user_home(void); */ procfd_t game_mode_open_proc(const pid_t pid); int game_mode_close_proc(const procfd_t procfd); + +/** gamemode-sched.c + * Provides internal API functions specific to adjusting process + * scheduling. + */ +void game_mode_apply_renice(const GameModeContext *self, const pid_t client); +void game_mode_apply_scheduling(const GameModeContext *self, const pid_t client); diff --git a/daemon/meson.build b/daemon/meson.build index 5f4dcc2..ecc8181 100644 --- a/daemon/meson.build +++ b/daemon/meson.build @@ -20,6 +20,7 @@ daemon_sources = [ 'gamemode.c', 'gamemode-env.c', 'gamemode-proc.c', + 'gamemode-sched.c', 'daemonize.c', 'dbus_messaging.c', 'governors.c',