Skip to content

Commit 3c5c885

Browse files
committed
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 1d9c1e6 commit 3c5c885

File tree

6 files changed

+121
-2
lines changed

6 files changed

+121
-2
lines changed

daemon/gamemode-context.c

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

860+
int game_mode_context_restart(GameModeContext *self, pid_t client, pid_t requester)
861+
{
862+
/* First check the requester settings */
863+
{
864+
char *executable = game_mode_context_find_exe(requester);
865+
if (!executable) {
866+
return -1;
867+
}
868+
869+
/* Check our blacklist and whitelist */
870+
if (!config_get_supervisor_whitelisted(self->config, executable)) {
871+
LOG_MSG("Supervisor [%s] was rejected (not in whitelist)\n", executable);
872+
free(executable);
873+
return -2;
874+
} else if (config_get_supervisor_blacklisted(self->config, executable)) {
875+
LOG_MSG("Supervisor [%s] was rejected (in blacklist)\n", executable);
876+
free(executable);
877+
return -2;
878+
}
879+
880+
free(executable);
881+
}
882+
883+
/*
884+
* Check the current refcount on gamemode, this equates to whether gamemode is active or not,
885+
* see game_mode_context_register and game_mode_context_unregister
886+
*/
887+
if (!atomic_load_explicit(&self->refcount, memory_order_seq_cst)) {
888+
return 1;
889+
}
890+
891+
/* Requires locking. */
892+
pthread_rwlock_rdlock(&self->rwlock);
893+
894+
game_mode_context_leave(self);
895+
game_mode_context_enter(self);
896+
897+
/* Unlock here, potentially yielding */
898+
pthread_rwlock_unlock(&self->rwlock);
899+
900+
return 0;
901+
}
902+
860903
/**
861904
* Construct a new GameModeClient for the given process ID
862905
*

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: 18 additions & 2 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" \
@@ -161,9 +162,10 @@ int main(int argc, char *argv[])
161162
{ "daemonize", no_argument, 0, 'd' }, { "log-to-syslog", no_argument, 0, 'l' },
162163
{ "request", optional_argument, 0, 'r' }, { "test", no_argument, 0, 't' },
163164
{ "status", optional_argument, 0, 's' }, { "help", no_argument, 0, 'h' },
164-
{ "version", no_argument, 0, 'v' }, { NULL, 0, NULL, 0 },
165+
{ "version", no_argument, 0, 'v' }, { "reset", no_argument, 0, 'R' },
166+
{ NULL, 0, NULL, 0 },
165167
};
166-
static const char *short_options = "dls::r::tvh";
168+
static const char *short_options = "dls::r::tvhR";
167169

168170
while ((opt = getopt_long(argc, argv, short_options, long_options, 0)) != -1) {
169171
switch (opt) {
@@ -289,6 +291,20 @@ int main(int argc, char *argv[])
289291

290292
exit(EXIT_SUCCESS);
291293

294+
case 'R':
295+
switch (gamemode_request_restart()) {
296+
case 0: /* success */
297+
LOG_MSG("gamemode restart succeeded\n");
298+
exit(EXIT_SUCCESS);
299+
case 1: /* already off */
300+
LOG_ERROR("gamemode was already deactivated\n");
301+
break;
302+
case -1: /* error */
303+
LOG_ERROR("gamemode_request_restart failed: %s\n", gamemode_error_string());
304+
break;
305+
}
306+
exit(EXIT_FAILURE);
307+
292308
case 't': {
293309
int status = game_mode_run_client_tests();
294310
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)