From ceb1808c9501d04434324565b1b7229034940277 Mon Sep 17 00:00:00 2001 From: Marc Di Luzio Date: Tue, 14 May 2019 21:16:24 +0100 Subject: [PATCH] Initial implementation of a RefreshConfig dbus interface --- daemon/dbus_messaging.c | 12 ++++ daemon/gamemode.c | 129 ++++++++++++++++++++++++++++++---------- daemon/gamemode.h | 5 ++ 3 files changed, 116 insertions(+), 30 deletions(-) diff --git a/daemon/dbus_messaging.c b/daemon/dbus_messaging.c index 0a9fe20..4c03b14 100644 --- a/daemon/dbus_messaging.c +++ b/daemon/dbus_messaging.c @@ -206,6 +206,17 @@ void game_mode_client_count_changed(void) NULL); } +/** + * Handles the Refresh Config request + */ +static int method_refresh_config(sd_bus_message *m, void *userdata, + __attribute__((unused)) sd_bus_error *ret_error) +{ + GameModeContext *context = userdata; + int status = game_mode_refresh_config(context); + return sd_bus_reply_method_return(m, "i", status); +} + /** * D-BUS vtable to dispatch virtual methods */ @@ -222,6 +233,7 @@ static const sd_bus_vtable gamemode_vtable[] = { SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("QueryStatusByPID", "ii", "i", method_query_status_by_pid, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("RefreshConfig", "", "i", method_refresh_config, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END }; diff --git a/daemon/gamemode.c b/daemon/gamemode.c index 6b977f8..4532db2 100644 --- a/daemon/gamemode.c +++ b/daemon/gamemode.c @@ -99,6 +99,17 @@ static void game_mode_context_leave(GameModeContext *self); static char *game_mode_context_find_exe(pid_t pid); static void game_mode_execute_scripts(char scripts[CONFIG_LIST_MAX][CONFIG_VALUE_MAX], int timeout); +static void start_reaper_thread(GameModeContext *self) +{ + pthread_mutex_init(&self->reaper.mutex, NULL); + pthread_cond_init(&self->reaper.condition, NULL); + + self->reaper.running = true; + if (pthread_create(&self->reaper.thread, NULL, game_mode_context_reaper, self) != 0) { + FATAL_ERROR("Couldn't construct a new thread"); + } +} + void game_mode_context_init(GameModeContext *self) { if (had_context_init) { @@ -120,14 +131,25 @@ void game_mode_context_init(GameModeContext *self) game_mode_initialise_gpu(self->config, &self->target_gpu); pthread_rwlock_init(&self->rwlock, NULL); - pthread_mutex_init(&self->reaper.mutex, NULL); - pthread_cond_init(&self->reaper.condition, NULL); /* Get the reaper thread going */ - self->reaper.running = true; - if (pthread_create(&self->reaper.thread, NULL, game_mode_context_reaper, self) != 0) { - FATAL_ERROR("Couldn't construct a new thread"); - } + start_reaper_thread(self); +} + +static void end_reaper_thread(GameModeContext *self) +{ + self->reaper.running = false; + + /* We might be stuck waiting, so wake it up again */ + pthread_mutex_lock(&self->reaper.mutex); + pthread_cond_signal(&self->reaper.condition); + pthread_mutex_unlock(&self->reaper.mutex); + + /* Join the thread as soon as possible */ + pthread_join(self->reaper.thread, NULL); + + pthread_cond_destroy(&self->reaper.condition); + pthread_mutex_destroy(&self->reaper.mutex); } void game_mode_context_destroy(GameModeContext *self) @@ -143,18 +165,8 @@ void game_mode_context_destroy(GameModeContext *self) had_context_init = false; game_mode_client_free(self->client); - self->reaper.running = false; - /* We might be stuck waiting, so wake it up again */ - pthread_mutex_lock(&self->reaper.mutex); - pthread_cond_signal(&self->reaper.condition); - pthread_mutex_unlock(&self->reaper.mutex); - - /* Join the thread as soon as possible */ - pthread_join(self->reaper.thread, NULL); - - pthread_cond_destroy(&self->reaper.condition); - pthread_mutex_destroy(&self->reaper.mutex); + end_reaper_thread(self); /* Destroy the gpu object */ game_mode_free_gpu(&self->stored_gpu); @@ -324,6 +336,20 @@ int game_mode_context_num_clients(GameModeContext *self) return atomic_load(&self->refcount); } +static int game_mode_apply_client_optimisations(GameModeContext *self, pid_t client) +{ + /* Store current renice and apply */ + game_mode_apply_renice(self, client, 0 /* expect zero value to start with */); + + /* Store current ioprio value and apply */ + game_mode_apply_ioprio(self, client, IOPRIO_DEFAULT); + + /* Apply scheduler policies */ + game_mode_apply_scheduling(self, client); + + return 0; +} + int game_mode_context_register(GameModeContext *self, pid_t client, pid_t requester) { errno = 0; @@ -412,14 +438,7 @@ int game_mode_context_register(GameModeContext *self, pid_t client, pid_t reques game_mode_context_enter(self); } - /* Store current renice and apply */ - game_mode_apply_renice(self, client, 0 /* expect zero value to start with */); - - /* Store current ioprio value and apply */ - game_mode_apply_ioprio(self, client, IOPRIO_DEFAULT); - - /* Apply scheduler policies */ - game_mode_apply_scheduling(self, client); + game_mode_apply_client_optimisations(self, client); game_mode_client_count_changed(); @@ -433,6 +452,17 @@ error_cleanup: return -1; } +static int game_mode_remove_client_optimisations(GameModeContext *self, pid_t client) +{ + /* Restore the ioprio value for the process, expecting it to be the config value */ + game_mode_apply_ioprio(self, client, (int)config_get_ioprio_value(self->config)); + + /* Restore the renice value for the process, expecting it to be our config value */ + game_mode_apply_renice(self, client, (int)config_get_renice_value(self->config)); + + return 0; +} + int game_mode_context_unregister(GameModeContext *self, pid_t client, pid_t requester) { GameModeClient *cl = NULL; @@ -508,11 +538,7 @@ int game_mode_context_unregister(GameModeContext *self, pid_t client, pid_t requ game_mode_client_count_changed(); - /* Restore the ioprio value for the process, expecting it to be the config value */ - game_mode_apply_ioprio(self, client, (int)config_get_ioprio_value(self->config)); - - /* Restore the renice value for the process, expecting it to be our config value */ - game_mode_apply_renice(self, client, (int)config_get_renice_value(self->config)); + game_mode_remove_client_optimisations(self, client); return 0; } @@ -734,3 +760,46 @@ static void game_mode_execute_scripts(char scripts[CONFIG_LIST_MAX][CONFIG_VALUE i++; } } + +/* + * Refresh the current configuration + * + * Refreshing the configuration live would be problematic for various optimisation values, to ensure + * we have a fully clean state, we tear down the whole gamemode state and regrow it with a new + * config, remembering the registered games + */ +int game_mode_refresh_config(GameModeContext *self) +{ + LOG_MSG("Refreshing config..."); + + /* Stop the reaper thread first */ + end_reaper_thread(self); + + /* Remove current client optimisations */ + pthread_rwlock_rdlock(&self->rwlock); + for (GameModeClient *cl = self->client; cl; cl = cl->next) + game_mode_remove_client_optimisations(self, cl->pid); + pthread_rwlock_unlock(&self->rwlock); + + /* Shut down the global context */ + game_mode_context_leave(self); + + /* Reload the config */ + config_reload(self->config); + + /* Start the global context back up */ + game_mode_context_enter(self); + + /* Re-apply all current optimisations */ + pthread_rwlock_rdlock(&self->rwlock); + for (GameModeClient *cl = self->client; cl; cl = cl->next) + game_mode_apply_client_optimisations(self, cl->pid); + pthread_rwlock_unlock(&self->rwlock); + + /* Restart the reaper thread back up again */ + start_reaper_thread(self); + + LOG_MSG("Config refreshed..."); + + return 0; +} \ No newline at end of file diff --git a/daemon/gamemode.h b/daemon/gamemode.h index d5d6eb6..b9ddad1 100644 --- a/daemon/gamemode.h +++ b/daemon/gamemode.h @@ -111,6 +111,11 @@ int game_mode_context_query_status(GameModeContext *self, pid_t pid, pid_t reque */ GameModeConfig *game_mode_config_from_context(const GameModeContext *context); +/* + * Refresh the current configuration + */ +int game_mode_refresh_config(GameModeContext *context); + /** gamemode-env.c * Provides internal API functions specific to working environment * variables.