mirror of
https://github.com/FeralInteractive/gamemode.git
synced 2025-06-26 17:31:45 +02:00
Initial implementation of a RefreshConfig dbus interface
This commit is contained in:
@ -206,6 +206,17 @@ void game_mode_client_count_changed(void)
|
|||||||
NULL);
|
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
|
* D-BUS vtable to dispatch virtual methods
|
||||||
*/
|
*/
|
||||||
@ -222,6 +233,7 @@ static const sd_bus_vtable gamemode_vtable[] = {
|
|||||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD("QueryStatusByPID", "ii", "i", method_query_status_by_pid,
|
SD_BUS_METHOD("QueryStatusByPID", "ii", "i", method_query_status_by_pid,
|
||||||
SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
|
SD_BUS_METHOD("RefreshConfig", "", "i", method_refresh_config, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_VTABLE_END
|
SD_BUS_VTABLE_END
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,6 +99,17 @@ static void game_mode_context_leave(GameModeContext *self);
|
|||||||
static char *game_mode_context_find_exe(pid_t pid);
|
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 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)
|
void game_mode_context_init(GameModeContext *self)
|
||||||
{
|
{
|
||||||
if (had_context_init) {
|
if (had_context_init) {
|
||||||
@ -120,14 +131,25 @@ void game_mode_context_init(GameModeContext *self)
|
|||||||
game_mode_initialise_gpu(self->config, &self->target_gpu);
|
game_mode_initialise_gpu(self->config, &self->target_gpu);
|
||||||
|
|
||||||
pthread_rwlock_init(&self->rwlock, NULL);
|
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 */
|
/* Get the reaper thread going */
|
||||||
self->reaper.running = true;
|
start_reaper_thread(self);
|
||||||
if (pthread_create(&self->reaper.thread, NULL, game_mode_context_reaper, self) != 0) {
|
}
|
||||||
FATAL_ERROR("Couldn't construct a new thread");
|
|
||||||
}
|
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)
|
void game_mode_context_destroy(GameModeContext *self)
|
||||||
@ -143,18 +165,8 @@ void game_mode_context_destroy(GameModeContext *self)
|
|||||||
|
|
||||||
had_context_init = false;
|
had_context_init = false;
|
||||||
game_mode_client_free(self->client);
|
game_mode_client_free(self->client);
|
||||||
self->reaper.running = false;
|
|
||||||
|
|
||||||
/* We might be stuck waiting, so wake it up again */
|
end_reaper_thread(self);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Destroy the gpu object */
|
/* Destroy the gpu object */
|
||||||
game_mode_free_gpu(&self->stored_gpu);
|
game_mode_free_gpu(&self->stored_gpu);
|
||||||
@ -324,6 +336,20 @@ int game_mode_context_num_clients(GameModeContext *self)
|
|||||||
return atomic_load(&self->refcount);
|
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)
|
int game_mode_context_register(GameModeContext *self, pid_t client, pid_t requester)
|
||||||
{
|
{
|
||||||
errno = 0;
|
errno = 0;
|
||||||
@ -412,14 +438,7 @@ int game_mode_context_register(GameModeContext *self, pid_t client, pid_t reques
|
|||||||
game_mode_context_enter(self);
|
game_mode_context_enter(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store current renice and apply */
|
game_mode_apply_client_optimisations(self, client);
|
||||||
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_client_count_changed();
|
game_mode_client_count_changed();
|
||||||
|
|
||||||
@ -433,6 +452,17 @@ error_cleanup:
|
|||||||
return -1;
|
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)
|
int game_mode_context_unregister(GameModeContext *self, pid_t client, pid_t requester)
|
||||||
{
|
{
|
||||||
GameModeClient *cl = NULL;
|
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();
|
game_mode_client_count_changed();
|
||||||
|
|
||||||
/* Restore the ioprio value for the process, expecting it to be the config value */
|
game_mode_remove_client_optimisations(self, client);
|
||||||
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -734,3 +760,46 @@ static void game_mode_execute_scripts(char scripts[CONFIG_LIST_MAX][CONFIG_VALUE
|
|||||||
i++;
|
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;
|
||||||
|
}
|
@ -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);
|
GameModeConfig *game_mode_config_from_context(const GameModeContext *context);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Refresh the current configuration
|
||||||
|
*/
|
||||||
|
int game_mode_refresh_config(GameModeContext *context);
|
||||||
|
|
||||||
/** gamemode-env.c
|
/** gamemode-env.c
|
||||||
* Provides internal API functions specific to working environment
|
* Provides internal API functions specific to working environment
|
||||||
* variables.
|
* variables.
|
||||||
|
Reference in New Issue
Block a user