Browse Source

Initial implementation of a RefreshConfig dbus interface

Marc Di Luzio 5 years ago
parent
commit
ceb1808c95
3 changed files with 116 additions and 30 deletions
  1. 12 0
      daemon/dbus_messaging.c
  2. 99 30
      daemon/gamemode.c
  3. 5 0
      daemon/gamemode.h

+ 12 - 0
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
 };
 

+ 99 - 30
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;
+}

+ 5 - 0
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.