Skip to content

Commit ce6fe12

Browse files
MithicSpiritafayaz-feral
authored andcommitted
add RestartGamemode command
This allows gamemode to leave the context and then enter it again, which re-applies all system optimizations. It is useful in cases where another program (like TLP) may override gamemode's optimizations. This is exposed to users by the -R or --restart flags to gamemoded.
1 parent af07e16 commit ce6fe12

6 files changed

Lines changed: 128 additions & 5 deletions

File tree

daemon/gamemode-context.c

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,49 @@ int game_mode_context_query_status(GameModeContext *self, pid_t client, pid_t re
934934
return ret;
935935
}
936936

937+
int game_mode_context_restart(GameModeContext *self, pid_t client, pid_t requester)
938+
{
939+
/* First check the requester settings */
940+
{
941+
char *executable = game_mode_context_find_exe(requester);
942+
if (!executable) {
943+
return -1;
944+
}
945+
946+
/* Check our blacklist and whitelist */
947+
if (!config_get_supervisor_whitelisted(self->config, executable)) {
948+
LOG_MSG("Supervisor [%s] was rejected (not in whitelist)\n", executable);
949+
free(executable);
950+
return -2;
951+
} else if (config_get_supervisor_blacklisted(self->config, executable)) {
952+
LOG_MSG("Supervisor [%s] was rejected (in blacklist)\n", executable);
953+
free(executable);
954+
return -2;
955+
}
956+
957+
free(executable);
958+
}
959+
960+
/*
961+
* Check the current refcount on gamemode, this equates to whether gamemode is active or not,
962+
* see game_mode_context_register and game_mode_context_unregister
963+
*/
964+
if (!atomic_load_explicit(&self->refcount, memory_order_seq_cst)) {
965+
return 1;
966+
}
967+
968+
/* Requires locking. */
969+
pthread_rwlock_rdlock(&self->rwlock);
970+
971+
game_mode_context_leave(self);
972+
game_mode_context_enter(self);
973+
974+
/* Unlock here, potentially yielding */
975+
pthread_rwlock_unlock(&self->rwlock);
976+
977+
return 0;
978+
}
979+
937980
/**
938981
* Construct a new GameModeClient for the given process ID
939982
*

daemon/gamemode-dbus.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,26 @@ static int method_query_status(sd_bus_message *m, void *userdata,
133133
return sd_bus_reply_method_return(m, "i", status);
134134
}
135135

136+
/**
137+
* Handles the RestartGamemode D-BUS Method
138+
*/
139+
static int method_restart_gamemode(sd_bus_message *m, void *userdata,
140+
__attribute__((unused)) sd_bus_error *ret_error)
141+
{
142+
int pid = 0;
143+
GameModeContext *context = userdata;
144+
145+
int ret = sd_bus_message_read(m, "i", &pid);
146+
if (ret < 0) {
147+
LOG_ERROR("Failed to parse input parameters: %s\n", strerror(-ret));
148+
return ret;
149+
}
150+
151+
int status = game_mode_context_restart(context, (pid_t)pid, (pid_t)pid);
152+
153+
return sd_bus_reply_method_return(m, "i", status);
154+
}
155+
136156
/**
137157
* Handles the RegisterGameByPID D-BUS Method
138158
*/
@@ -402,6 +422,7 @@ static const sd_bus_vtable gamemode_vtable[] = {
402422
SD_BUS_METHOD("RegisterGame", "i", "i", method_register_game, SD_BUS_VTABLE_UNPRIVILEGED),
403423
SD_BUS_METHOD("UnregisterGame", "i", "i", method_unregister_game, SD_BUS_VTABLE_UNPRIVILEGED),
404424
SD_BUS_METHOD("QueryStatus", "i", "i", method_query_status, SD_BUS_VTABLE_UNPRIVILEGED),
425+
SD_BUS_METHOD("RestartGamemode", "i", "i", method_restart_gamemode, SD_BUS_VTABLE_UNPRIVILEGED),
405426
SD_BUS_METHOD("RegisterGameByPID", "ii", "i", method_register_game_by_pid,
406427
SD_BUS_VTABLE_UNPRIVILEGED),
407428
SD_BUS_METHOD("UnregisterGameByPID", "ii", "i", method_unregister_game_by_pid,

daemon/gamemode.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,16 @@ int game_mode_context_unregister(GameModeContext *self, pid_t pid, pid_t request
155155
*/
156156
int game_mode_context_query_status(GameModeContext *self, pid_t pid, pid_t requester);
157157

158+
/**
159+
* Restart gamemode if it is running
160+
*
161+
* @param pid Process ID for the remote client
162+
* @returns 0 if gamemode was restarted
163+
* 1 if gamemode was already deactivated
164+
* -2 if this request was rejected
165+
*/
166+
int game_mode_context_restart(GameModeContext *self, pid_t pid, pid_t requester);
167+
158168
/**
159169
* Query the config of a gamemode context
160170
*

daemon/gamemoded.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ POSSIBILITY OF SUCH DAMAGE.
7070
" When no PID given, requests gamemode and pauses\n" \
7171
" -s[PID], --status=[PID] Query the status of gamemode for process\n" \
7272
" When no PID given, queries the status globally\n" \
73+
" -R, --reset If gamemode is currently running, stop it, then restart\n" \
7374
" -d, --daemonize Daemonize self after launch\n" \
7475
" -l, --log-to-syslog Log to syslog\n" \
7576
" -t, --test Run tests\n" \
@@ -158,12 +159,17 @@ int main(int argc, char *argv[])
158159

159160
/* Options struct for getopt_long */
160161
static struct option long_options[] = {
161-
{ "daemonize", no_argument, 0, 'd' }, { "log-to-syslog", no_argument, 0, 'l' },
162-
{ "request", optional_argument, 0, 'r' }, { "test", no_argument, 0, 't' },
163-
{ "status", optional_argument, 0, 's' }, { "help", no_argument, 0, 'h' },
164-
{ "version", no_argument, 0, 'v' }, { NULL, 0, NULL, 0 },
162+
{ "daemonize", no_argument, 0, 'd' },
163+
{ "log-to-syslog", no_argument, 0, 'l' },
164+
{ "request", optional_argument, 0, 'r' },
165+
{ "test", no_argument, 0, 't' },
166+
{ "status", optional_argument, 0, 's' },
167+
{ "reset", no_argument, 0, 'R' },
168+
{ "help", no_argument, 0, 'h' },
169+
{ "version", no_argument, 0, 'v' },
170+
{ NULL, 0, NULL, 0 },
165171
};
166-
static const char *short_options = "dls::r::tvh";
172+
static const char *short_options = "dls::r::tvhR";
167173

168174
while ((opt = getopt_long(argc, argv, short_options, long_options, 0)) != -1) {
169175
switch (opt) {
@@ -289,6 +295,20 @@ int main(int argc, char *argv[])
289295

290296
exit(EXIT_SUCCESS);
291297

298+
case 'R':
299+
switch (gamemode_request_restart()) {
300+
case 0: /* success */
301+
LOG_MSG("gamemode restart succeeded\n");
302+
exit(EXIT_SUCCESS);
303+
case 1: /* already off */
304+
LOG_ERROR("gamemode was already deactivated\n");
305+
break;
306+
case -1: /* error */
307+
LOG_ERROR("gamemode_request_restart failed: %s\n", gamemode_error_string());
308+
break;
309+
}
310+
exit(EXIT_FAILURE);
311+
292312
case 't': {
293313
int status = game_mode_run_client_tests();
294314
exit(status);

lib/client_impl.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,12 @@ extern int real_gamemode_query_status(void)
379379
{
380380
return gamemode_request("QueryStatus", 0);
381381
}
382+
//
383+
// Wrapper to call RestartGamemode
384+
extern int real_gamemode_request_restart(void)
385+
{
386+
return gamemode_request("RestartGamemode", 0);
387+
}
382388

383389
// Wrapper to call RegisterGameByPID
384390
extern int real_gamemode_request_start_for(pid_t pid)

lib/gamemode_client.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ typedef int (*api_call_pid_return_int)(pid_t);
103103
static api_call_return_int REAL_internal_gamemode_request_start = NULL;
104104
static api_call_return_int REAL_internal_gamemode_request_end = NULL;
105105
static api_call_return_int REAL_internal_gamemode_query_status = NULL;
106+
static api_call_return_int REAL_internal_gamemode_request_restart = NULL;
106107
static api_call_return_cstring REAL_internal_gamemode_error_string = NULL;
107108
static api_call_pid_return_int REAL_internal_gamemode_request_start_for = NULL;
108109
static api_call_pid_return_int REAL_internal_gamemode_request_end_for = NULL;
@@ -166,6 +167,10 @@ __attribute__((always_inline)) static inline int internal_load_libgamemode(void)
166167
(void **)&REAL_internal_gamemode_query_status,
167168
sizeof(REAL_internal_gamemode_query_status),
168169
false },
170+
{ "real_gamemode_request_restart",
171+
(void **)&REAL_internal_gamemode_request_restart,
172+
sizeof(REAL_internal_gamemode_request_restart),
173+
false },
169174
{ "real_gamemode_error_string",
170175
(void **)&REAL_internal_gamemode_error_string,
171176
sizeof(REAL_internal_gamemode_error_string),
@@ -319,6 +324,24 @@ __attribute__((always_inline)) static inline int gamemode_query_status(void)
319324
return REAL_internal_gamemode_query_status();
320325
}
321326

327+
/* Redirect to the real libgamemode */
328+
__attribute__((always_inline)) static inline int gamemode_request_restart(void)
329+
{
330+
/* Need to load gamemode */
331+
if (internal_load_libgamemode() < 0) {
332+
return -1;
333+
}
334+
335+
if (REAL_internal_gamemode_request_restart == NULL) {
336+
snprintf(internal_gamemode_client_error_string,
337+
sizeof(internal_gamemode_client_error_string),
338+
"gamemode_request_restart missing (older host?)");
339+
return -1;
340+
}
341+
342+
return REAL_internal_gamemode_request_restart();
343+
}
344+
322345
/* Redirect to the real libgamemode */
323346
__attribute__((always_inline)) static inline int gamemode_request_start_for(pid_t pid)
324347
{

0 commit comments

Comments
 (0)