12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040 |
- #define _GNU_SOURCE
- #include "common-external.h"
- #include "common-governors.h"
- #include "common-helpers.h"
- #include "common-logging.h"
- #include "common-power.h"
- #include "gamemode.h"
- #include "gamemode-config.h"
- #include "build-config.h"
- #include <assert.h>
- #include <fcntl.h>
- #include <pthread.h>
- #include <signal.h>
- #include <stdatomic.h>
- #include <stdlib.h>
- #include <sys/time.h>
- #include <systemd/sd-daemon.h> /* TODO: Move usage to gamemode-dbus.c */
- #include <unistd.h>
- struct GameModeClient {
- _Atomic int refcount;
- pid_t pid;
- pid_t requester;
- struct GameModeClient *next;
- char executable[PATH_MAX];
- time_t timestamp;
- };
- enum GameModeGovernor {
- GAME_MODE_GOVERNOR_DEFAULT,
- GAME_MODE_GOVERNOR_DESIRED,
- GAME_MODE_GOVERNOR_IGPU_DESIRED,
- };
- struct GameModeContext {
- pthread_rwlock_t rwlock;
- _Atomic int refcount;
- GameModeClient *client;
- GameModeConfig *config;
- char initial_cpu_mode[64];
- enum GameModeGovernor current_govenor;
- struct GameModeGPUInfo *stored_gpu;
- struct GameModeGPUInfo *target_gpu;
- bool igpu_optimization_enabled;
- uint32_t last_cpu_energy_uj;
- uint32_t last_igpu_energy_uj;
-
- struct {
- pthread_t thread;
- bool running;
- pthread_mutex_t mutex;
- pthread_cond_t condition;
- } reaper;
- };
- static GameModeContext instance = { 0 };
- static volatile bool had_context_init = false;
- static GameModeClient *game_mode_client_new(pid_t pid, char *exe, pid_t req);
- static const GameModeClient *game_mode_context_has_client(GameModeContext *self, pid_t client);
- static void *game_mode_context_reaper(void *userdata);
- static void game_mode_context_enter(GameModeContext *self);
- 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) {
- LOG_ERROR("Context already initialised\n");
- return;
- }
- had_context_init = true;
- self->refcount = ATOMIC_VAR_INIT(0);
-
- memset(self->initial_cpu_mode, 0, sizeof(self->initial_cpu_mode));
-
- self->config = config_create();
- config_init(self->config);
- self->current_govenor = GAME_MODE_GOVERNOR_DEFAULT;
-
- game_mode_initialise_gpu(self->config, &self->stored_gpu);
- game_mode_initialise_gpu(self->config, &self->target_gpu);
- pthread_rwlock_init(&self->rwlock, NULL);
-
- start_reaper_thread(self);
- }
- static void end_reaper_thread(GameModeContext *self)
- {
- self->reaper.running = false;
-
- pthread_mutex_lock(&self->reaper.mutex);
- pthread_cond_signal(&self->reaper.condition);
- pthread_mutex_unlock(&self->reaper.mutex);
-
- 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)
- {
- if (!had_context_init) {
- return;
- }
-
- if (game_mode_context_num_clients(self) > 0) {
- game_mode_context_leave(self);
- }
- had_context_init = false;
- game_mode_client_unref(self->client);
- end_reaper_thread(self);
-
- game_mode_free_gpu(&self->stored_gpu);
- game_mode_free_gpu(&self->target_gpu);
-
- config_destroy(self->config);
- pthread_rwlock_destroy(&self->rwlock);
- }
- static int game_mode_set_governor(GameModeContext *self, enum GameModeGovernor gov)
- {
- if (self->current_govenor == gov) {
- return 0;
- }
- if (self->current_govenor == GAME_MODE_GOVERNOR_DEFAULT) {
-
- const char *initial_state = get_gov_state();
- if (initial_state == NULL) {
- return 0;
- }
-
- strncpy(self->initial_cpu_mode, initial_state, sizeof(self->initial_cpu_mode) - 1);
- self->initial_cpu_mode[sizeof(self->initial_cpu_mode) - 1] = '\0';
- LOG_MSG("governor was initially set to [%s]\n", initial_state);
- }
- char *gov_str = NULL;
- char gov_config_str[CONFIG_VALUE_MAX] = { 0 };
- switch (gov) {
- case GAME_MODE_GOVERNOR_DEFAULT:
- config_get_default_governor(self->config, gov_config_str);
- gov_str = gov_config_str[0] != '\0' ? gov_config_str : self->initial_cpu_mode;
- break;
- case GAME_MODE_GOVERNOR_DESIRED:
- config_get_desired_governor(self->config, gov_config_str);
- gov_str = gov_config_str[0] != '\0' ? gov_config_str : "performance";
- break;
- case GAME_MODE_GOVERNOR_IGPU_DESIRED:
- config_get_igpu_desired_governor(self->config, gov_config_str);
- gov_str = gov_config_str[0] != '\0' ? gov_config_str : "powersave";
- break;
- default:
- assert(!"Invalid governor requested");
- }
- const char *const exec_args[] = {
- "pkexec", LIBEXECDIR "/cpugovctl", "set", gov_str, NULL,
- };
- LOG_MSG("Requesting update of governor policy to %s\n", gov_str);
- int ret = run_external_process(exec_args, NULL, -1);
- if (ret != 0) {
- LOG_ERROR("Failed to update cpu governor policy\n");
- return ret;
- }
-
- self->current_govenor = gov;
- return 0;
- }
- static void game_mode_enable_igpu_optimization(GameModeContext *self)
- {
- float threshold = config_get_igpu_power_threshold(self->config);
-
- if (threshold < 10000 && get_cpu_energy_uj(&self->last_cpu_energy_uj) &&
- get_igpu_energy_uj(&self->last_igpu_energy_uj)) {
- LOG_MSG(
- "Successfully queried power data for the CPU and iGPU. "
- "Enabling the integrated GPU optimization");
- self->igpu_optimization_enabled = true;
- }
- }
- static void game_mode_disable_igpu_optimization(GameModeContext *self)
- {
- self->igpu_optimization_enabled = false;
- }
- static void game_mode_check_igpu_energy(GameModeContext *self)
- {
- pthread_rwlock_wrlock(&self->rwlock);
-
- if (self->current_govenor == GAME_MODE_GOVERNOR_DEFAULT)
- goto unlock;
- if (!self->igpu_optimization_enabled)
- goto unlock;
- uint32_t cpu_energy_uj, igpu_energy_uj;
- if (!get_cpu_energy_uj(&cpu_energy_uj) || !get_igpu_energy_uj(&igpu_energy_uj)) {
-
- self->igpu_optimization_enabled = false;
- LOG_ERROR("Failed to get CPU and iGPU power data\n");
- goto unlock;
- }
-
- uint32_t cpu_energy_delta_uj = cpu_energy_uj - self->last_cpu_energy_uj;
- uint32_t igpu_energy_delta_uj = igpu_energy_uj - self->last_igpu_energy_uj;
- self->last_cpu_energy_uj = cpu_energy_uj;
- self->last_igpu_energy_uj = igpu_energy_uj;
- if (cpu_energy_delta_uj == 0) {
- LOG_ERROR("CPU reported no energy used\n");
- goto unlock;
- }
- float threshold = config_get_igpu_power_threshold(self->config);
- double ratio = (double)igpu_energy_delta_uj / (double)cpu_energy_delta_uj;
- if (ratio > threshold) {
- game_mode_set_governor(self, GAME_MODE_GOVERNOR_IGPU_DESIRED);
- } else {
- game_mode_set_governor(self, GAME_MODE_GOVERNOR_DESIRED);
- }
- unlock:
- pthread_rwlock_unlock(&self->rwlock);
- }
- static void game_mode_context_enter(GameModeContext *self)
- {
- LOG_MSG("Entering Game Mode...\n");
- sd_notifyf(0, "STATUS=%sGameMode is now active.%s\n", "\x1B[1;32m", "\x1B[0m");
- if (game_mode_set_governor(self, GAME_MODE_GOVERNOR_DESIRED) == 0) {
-
- game_mode_enable_igpu_optimization(self);
- }
-
- if (config_get_inhibit_screensaver(self->config))
- game_mode_inhibit_screensaver(true);
-
- game_mode_get_gpu(self->stored_gpu);
- game_mode_apply_gpu(self->target_gpu);
-
- char scripts[CONFIG_LIST_MAX][CONFIG_VALUE_MAX];
- memset(scripts, 0, sizeof(scripts));
- config_get_gamemode_start_scripts(self->config, scripts);
- long timeout = config_get_script_timeout(self->config);
- game_mode_execute_scripts(scripts, (int)timeout);
- }
- static void game_mode_context_leave(GameModeContext *self)
- {
- LOG_MSG("Leaving Game Mode...\n");
- sd_notifyf(0, "STATUS=%sGameMode is currently deactivated.%s\n", "\x1B[1;36m", "\x1B[0m");
-
- game_mode_apply_gpu(self->stored_gpu);
-
- if (config_get_inhibit_screensaver(self->config))
- game_mode_inhibit_screensaver(false);
- game_mode_set_governor(self, GAME_MODE_GOVERNOR_DEFAULT);
- game_mode_disable_igpu_optimization(self);
- char scripts[CONFIG_LIST_MAX][CONFIG_VALUE_MAX];
- memset(scripts, 0, sizeof(scripts));
- config_get_gamemode_end_scripts(self->config, scripts);
- long timeout = config_get_script_timeout(self->config);
- game_mode_execute_scripts(scripts, (int)timeout);
- }
- static void game_mode_context_auto_expire(GameModeContext *self)
- {
- bool removing = true;
- while (removing) {
- pthread_rwlock_rdlock(&self->rwlock);
- removing = false;
-
- for (GameModeClient *client = self->client; client; client = client->next) {
- if (kill(client->pid, 0) != 0) {
- LOG_MSG("Removing expired game [%i]...\n", client->pid);
- pthread_rwlock_unlock(&self->rwlock);
- game_mode_context_unregister(self, client->pid, client->pid);
- removing = true;
- break;
- }
- }
- if (!removing) {
- pthread_rwlock_unlock(&self->rwlock);
- break;
- }
- if (game_mode_context_num_clients(self) == 0)
- LOG_MSG("Properly cleaned up all expired games.\n");
- }
- }
- static const GameModeClient *game_mode_context_has_client(GameModeContext *self, pid_t client)
- {
- const GameModeClient *found = NULL;
- pthread_rwlock_rdlock(&self->rwlock);
-
- for (GameModeClient *cl = self->client; cl; cl = cl->next) {
- if (cl->pid == client) {
- found = cl;
- break;
- }
- }
- pthread_rwlock_unlock(&self->rwlock);
- return found;
- }
- int game_mode_context_num_clients(GameModeContext *self)
- {
- return atomic_load(&self->refcount);
- }
- pid_t *game_mode_context_list_clients(GameModeContext *self, unsigned int *count)
- {
- pid_t *res = NULL;
- unsigned int i = 0;
- unsigned int n;
- pthread_rwlock_rdlock(&self->rwlock);
- n = (unsigned int)atomic_load(&self->refcount);
- if (n > 0)
- res = (pid_t *)malloc(n * sizeof(pid_t));
- for (GameModeClient *cl = self->client; cl; cl = cl->next) {
- assert(n > i);
- res[i] = cl->pid;
- i++;
- }
- *count = i;
- pthread_rwlock_unlock(&self->rwlock);
- return res;
- }
- GameModeClient *game_mode_context_lookup_client(GameModeContext *self, pid_t client)
- {
- GameModeClient *found = NULL;
- pthread_rwlock_rdlock(&self->rwlock);
-
- for (GameModeClient *cl = self->client; cl; cl = cl->next) {
- if (cl->pid == client) {
- found = cl;
- break;
- }
- }
- if (found) {
- game_mode_client_ref(found);
- }
- pthread_rwlock_unlock(&self->rwlock);
- return found;
- }
- static int game_mode_apply_client_optimisations(GameModeContext *self, pid_t client)
- {
-
- game_mode_apply_renice(self, client, 0 );
-
- game_mode_apply_ioprio(self, client, IOPRIO_DEFAULT);
-
- game_mode_apply_scheduling(self, client);
- return 0;
- }
- int game_mode_context_register(GameModeContext *self, pid_t client, pid_t requester)
- {
- errno = 0;
-
- char *executable = NULL;
- int err = -1;
-
- if (requester != client) {
-
- executable = game_mode_context_find_exe(requester);
- if (!executable) {
- goto error_cleanup;
- }
-
- if (!config_get_supervisor_whitelisted(self->config, executable)) {
- LOG_MSG("Supervisor [%s] was rejected (not in whitelist)\n", executable);
- err = -2;
- goto error_cleanup;
- } else if (config_get_supervisor_blacklisted(self->config, executable)) {
- LOG_MSG("Supervisor [%s] was rejected (in blacklist)\n", executable);
- err = -2;
- goto error_cleanup;
- }
-
- free(executable);
- executable = NULL;
- } else if (config_get_require_supervisor(self->config)) {
- LOG_ERROR("Direct request made but require_supervisor was set, rejecting request!\n");
- err = -2;
- goto error_cleanup;
- }
-
- pthread_rwlock_rdlock(&self->rwlock);
- const GameModeClient *existing = game_mode_context_has_client(self, client);
- if (existing) {
- LOG_HINTED(ERROR,
- "Addition requested for already known client %d [%s].\n",
- " -- This may happen due to using exec or shell wrappers. You may want to\n"
- " -- blacklist this client so GameMode can see its final name here.\n",
- existing->pid,
- existing->executable);
- pthread_rwlock_unlock(&self->rwlock);
- goto error_cleanup;
- }
- pthread_rwlock_unlock(&self->rwlock);
-
- executable = game_mode_context_find_exe(client);
- if (!executable)
- goto error_cleanup;
-
- if (!config_get_client_whitelisted(self->config, executable)) {
- LOG_MSG("Client [%s] was rejected (not in whitelist)\n", executable);
- goto error_cleanup;
- } else if (config_get_client_blacklisted(self->config, executable)) {
- LOG_MSG("Client [%s] was rejected (in blacklist)\n", executable);
- goto error_cleanup;
- }
-
- GameModeClient *cl = game_mode_client_new(client, executable, requester);
- if (!cl)
- goto error_cleanup;
- free(executable);
-
- pthread_rwlock_wrlock(&self->rwlock);
- LOG_MSG("Adding game: %d [%s]\n", client, cl->executable);
-
- cl->next = self->client;
- self->client = cl;
-
- if (atomic_fetch_add_explicit(&self->refcount, 1, memory_order_seq_cst) == 0) {
- game_mode_context_enter(self);
- }
- game_mode_apply_client_optimisations(self, client);
-
- pthread_rwlock_unlock(&self->rwlock);
- game_mode_client_registered(client);
- return 0;
- error_cleanup:
- if (errno != 0)
- LOG_ERROR("Failed to register client [%d]: %s\n", client, strerror(errno));
- free(executable);
- return err;
- }
- static int game_mode_remove_client_optimisations(GameModeContext *self, pid_t client)
- {
-
- game_mode_apply_ioprio(self, client, (int)config_get_ioprio_value(self->config));
-
- 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;
- GameModeClient *prev = NULL;
- bool found = false;
-
- if (requester != client) {
-
- char *executable = game_mode_context_find_exe(requester);
- if (!executable) {
- return -1;
- }
-
- if (!config_get_supervisor_whitelisted(self->config, executable)) {
- LOG_MSG("Supervisor [%s] was rejected (not in whitelist)\n", executable);
- free(executable);
- return -2;
- } else if (config_get_supervisor_blacklisted(self->config, executable)) {
- LOG_MSG("Supervisor [%s] was rejected (in blacklist)\n", executable);
- free(executable);
- return -2;
- }
- free(executable);
- } else if (config_get_require_supervisor(self->config)) {
- LOG_ERROR("Direct request made but require_supervisor was set, rejecting request!\n");
- return -2;
- }
-
- pthread_rwlock_wrlock(&self->rwlock);
- for (prev = cl = self->client; cl; cl = cl->next) {
- if (cl->pid != client) {
- prev = cl;
- continue;
- }
- LOG_MSG("Removing game: %d [%s]\n", client, cl->executable);
-
- found = true;
- prev->next = cl->next;
- if (cl == self->client) {
- self->client = cl->next;
- }
- cl->next = NULL;
- game_mode_client_unref(cl);
- break;
- }
- if (!found) {
- LOG_HINTED(
- ERROR,
- "Removal requested for unknown process [%d].\n",
- " -- The parent process probably forked and tries to unregister from the wrong\n"
- " -- process now. We cannot work around this. This message will likely be paired\n"
- " -- with a nearby 'Removing expired game' which means we cleaned up properly\n"
- " -- (we will log this event). This hint will be displayed only once.\n",
- client);
- pthread_rwlock_unlock(&self->rwlock);
- return -1;
- }
-
- if (atomic_fetch_sub_explicit(&self->refcount, 1, memory_order_seq_cst) == 1) {
- game_mode_context_leave(self);
- }
- game_mode_remove_client_optimisations(self, client);
-
- pthread_rwlock_unlock(&self->rwlock);
- game_mode_client_unregistered(client);
- return 0;
- }
- int game_mode_context_query_status(GameModeContext *self, pid_t client, pid_t requester)
- {
- GameModeClient *cl = NULL;
- int ret = 0;
-
- if (client != requester) {
- char *executable = game_mode_context_find_exe(requester);
- if (!executable) {
- return -1;
- }
-
- if (!config_get_supervisor_whitelisted(self->config, executable)) {
- LOG_MSG("Supervisor [%s] was rejected (not in whitelist)\n", executable);
- free(executable);
- return -2;
- } else if (config_get_supervisor_blacklisted(self->config, executable)) {
- LOG_MSG("Supervisor [%s] was rejected (in blacklist)\n", executable);
- free(executable);
- return -2;
- }
- free(executable);
- }
-
- if (atomic_load_explicit(&self->refcount, memory_order_seq_cst)) {
- ret++;
-
-
- pthread_rwlock_rdlock(&self->rwlock);
- for (cl = self->client; cl; cl = cl->next) {
- if (cl->pid != client) {
- continue;
- }
-
- ret++;
- break;
- }
-
- pthread_rwlock_unlock(&self->rwlock);
- }
- return ret;
- }
- static GameModeClient *game_mode_client_new(pid_t pid, char *executable, pid_t requester)
- {
-
-
- GameModeClient c = {
- .next = NULL,
- .pid = pid,
- .requester = requester,
- .timestamp = 0,
- };
-
- GameModeClient *ret = NULL;
- struct timeval now = {
- 0,
- };
- int r;
- r = gettimeofday(&now, NULL);
- if (r == 0)
- c.timestamp = now.tv_sec;
- ret = calloc(1, sizeof(struct GameModeClient));
- if (!ret) {
- return NULL;
- }
- *ret = c;
- ret->refcount = ATOMIC_VAR_INIT(1);
- strncpy(ret->executable, executable, PATH_MAX - 1);
- return ret;
- }
- void game_mode_client_unref(GameModeClient *client)
- {
- if (!client) {
- return;
- }
- if (atomic_fetch_sub_explicit(&client->refcount, 1, memory_order_seq_cst) > 1) {
- return;
- }
- if (client->next) {
- game_mode_client_unref(client->next);
- }
- free(client);
- }
- void game_mode_client_ref(GameModeClient *client)
- {
- if (!client) {
- return;
- }
- atomic_fetch_add_explicit(&client->refcount, 1, memory_order_seq_cst);
- }
- pid_t game_mode_client_get_pid(GameModeClient *client)
- {
- assert(client != NULL);
- return client->pid;
- }
- const char *game_mode_client_get_executable(GameModeClient *client)
- {
- assert(client != NULL);
- return client->executable;
- }
- pid_t game_mode_client_get_requester(GameModeClient *client)
- {
- assert(client != NULL);
- return client->requester;
- }
- uint64_t game_mode_client_get_timestamp(GameModeClient *client)
- {
- assert(client != NULL);
- return (uint64_t)client->timestamp;
- }
- static void game_mode_reload_config_internal(GameModeContext *self)
- {
- LOG_MSG("Reloading config...\n");
-
- pthread_rwlock_wrlock(&self->rwlock);
-
- if (game_mode_context_num_clients(self)) {
- for (GameModeClient *cl = self->client; cl; cl = cl->next)
- game_mode_remove_client_optimisations(self, cl->pid);
- game_mode_context_leave(self);
- }
-
- config_reload(self->config);
-
- if (game_mode_context_num_clients(self)) {
-
- game_mode_context_enter(self);
- for (GameModeClient *cl = self->client; cl; cl = cl->next)
- game_mode_apply_client_optimisations(self, cl->pid);
- }
- pthread_rwlock_unlock(&self->rwlock);
- LOG_MSG("Config reload complete\n");
- }
- static void *game_mode_context_reaper(void *userdata)
- {
-
- GameModeContext *self = userdata;
- long reaper_interval = config_get_reaper_frequency(self->config);
- struct timespec ts = { 0, 0 };
- ts.tv_sec = time(NULL) + reaper_interval;
- while (self->reaper.running) {
-
- pthread_mutex_lock(&self->reaper.mutex);
- pthread_cond_timedwait(&self->reaper.condition, &self->reaper.mutex, &ts);
- pthread_mutex_unlock(&self->reaper.mutex);
-
- if (!self->reaper.running) {
- return NULL;
- }
-
- game_mode_check_igpu_energy(self);
-
- game_mode_context_auto_expire(self);
-
- if (config_needs_reload(self->config)) {
- LOG_MSG("Detected config file changes\n");
- game_mode_reload_config_internal(self);
- }
- ts.tv_sec = time(NULL) + reaper_interval;
- }
- return NULL;
- }
- GameModeContext *game_mode_context_instance(void)
- {
- return &instance;
- }
- GameModeConfig *game_mode_config_from_context(const GameModeContext *context)
- {
- return context ? context->config : NULL;
- }
- static char *game_mode_context_find_exe(pid_t pid)
- {
- char buffer[PATH_MAX];
- char *proc_path = NULL, *wine_exe = NULL;
- autoclose_fd int pidfd = -1;
- ssize_t r;
- if (!(proc_path = buffered_snprintf(buffer, "/proc/%d", pid)))
- goto fail;
-
- pidfd = openat(AT_FDCWD, proc_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY);
- if (pidfd == -1)
- goto fail;
- r = readlinkat(pidfd, "exe", buffer, sizeof(buffer));
- if (r == sizeof(buffer)) {
- errno = ENAMETOOLONG;
- r = -1;
- }
- if (r == -1)
- goto fail;
- buffer[r] = '\0';
- char *exe = strdup(buffer);
-
- if ((wine_exe = game_mode_resolve_wine_preloader(exe, pid))) {
- free(exe);
- exe = wine_exe;
- }
- return exe;
- fail:
- if (errno != 0)
- LOG_ERROR("Unable to find executable for PID %d: %s\n", pid, strerror(errno));
- return NULL;
- }
- static void game_mode_execute_scripts(char scripts[CONFIG_LIST_MAX][CONFIG_VALUE_MAX], int timeout)
- {
- unsigned int i = 0;
- while (i < CONFIG_LIST_MAX && *scripts[i] != '\0') {
- LOG_MSG("Executing script [%s]\n", scripts[i]);
- int err;
- const char *args[] = { "/bin/sh", "-c", scripts[i], NULL };
- if ((err = run_external_process(args, NULL, timeout)) != 0) {
-
- LOG_ERROR("Script [%s] failed with error %d\n", scripts[i], err);
- }
- i++;
- }
- }
- int game_mode_reload_config(GameModeContext *self)
- {
-
- end_reaper_thread(self);
- game_mode_reload_config_internal(self);
-
- start_reaper_thread(self);
- return 0;
- }
|