Explorar o código

Merge pull request #99 from mdiluz/minor-improvements

Assorted Improvements
Alex Smith %!s(int64=6) %!d(string=hai) anos
pai
achega
92f8d3225d

+ 66 - 60
README.md

@@ -1,26 +1,23 @@
 # GameMode
 **GameMode** is a daemon/lib combo for Linux that allows games to request a set of optimisations be temporarily applied to the host OS.
 
-The design has a clear-cut abstraction between the host daemon and library (`gamemoded` and `libgamemode`), and the client loaders (`libgamemodeauto` and `gamemode_client.h`) that allows for safe use without worrying about whether the daemon is installed or running. This design also means that while the host library currently relies on `systemd` for exchanging messages with the daemon, it's entirely possible to implement other internals that still work with the same clients.
+GameMode was designed primarily as a stop-gap solution to problems with the Intel and AMD CPU powersave or ondemand governors, but is now host to a range of optimisation features and configurations.
 
-GameMode was designed primarily as a stop-gap solution to problems with the Intel and AMD CPU powersave or ondemand governors, but is now able to launch custom user defined plugins, and is intended to be expanded further, as there are a wealth of automation tasks one might want to apply.
-
-GameMode can leverage support for soft real time mode if the running kernel supports `SCHED_ISO`. This adjusts the scheduling of the game to real time without sacrificing system stability by starving other processes.
-
-GameMode adjusts the nice priority of games to -4 by default to give it a slight IO and CPU priority over other background processes. This only works if your user is permitted to adjust priorities within the limits configured by PAM. GameMode can be configured to take care of it by passing `with-pam-group=group` to the build options where `group` is a group your user needs to be part of.
-For more information, see `/etc/security/limits.conf`.
-
-Please take note that some games may actually run seemingly slower with `SCHED_ISO` if the game makes use of busy looping while interacting with the graphic driver. The same may happen if you apply too strong nice values. This effect is called priority inversion: Due to the high priority given to busy loops, there may be too few resources left for the graphics driver. Thus, sane defaults were chosen to not expose this effect on most systems. Part of this default is a heuristic which automatically turns off `SCHED_ISO` if GameMode detects three or less CPU cores. Your experience may change based on using GL threaded optimizations, CPU core binding (taskset), the graphic driver, or different CPU architectures. If you experience bad input latency or inconsistent FPS, try switching these configurations on or off first and report back. `SCHED_ISO` comes with a protection against this effect by falling back to normal scheduling as soon as the `SCHED_ISO` process uses more than 70% avarage across all CPU cores. This default value can be adjusted outside of the scope of GameMode (it's in `/proc/sys/kernel/iso_cpu`). This value also protects against compromising system stability, do not set it to 100% as this would turn the game into a full real time process, thus potentially starving all other OS components from CPU resources.
-
-GameMode can adjust the io priority of games to benefit from reduced lag and latency when a game has to load assets on demand.
+Currently GameMode includes support for optimisations including:
+* CPU Governor
+* I/O Priority
+* Kernel Scheduler (`SCHED_ISO`)
+* Screensaver inhibiting
+* Custom scripts
 
 Issues with GameMode should be reported here in the issues section, and not reported to Feral directly.
 
 ---
-## Building and installing
+## Building and installing [![Build Status](https://travis-ci.org/FeralInteractive/gamemode.svg?branch=master)](https://travis-ci.org/FeralInteractive/gamemode)
 
-If your distribution already has GameMode packaged, it is preferable to install it directly from there. There are Solus, AUR, Gentoo and Fedora packages already available.
+*It is preferable to install GameMode with your package manager of choice, if available*. There are Ubuntu (Cosmic), Solus, AUR, Gentoo and Fedora packages available at the time of writing.
 
+### Install Dependencies
 GameMode depends on `meson` for building and `systemd` for internal communication. This repo contains a `bootstrap.sh` script to allow for quick install to the user bus, but check `meson_options.txt` for custom settings.
 
 #### Ubuntu/Debian (you may also need `dbus-user-session`)
@@ -41,26 +38,16 @@ Gentoo has a bleeding-edge ebuild which builds from sources. It will also pull i
 ACCEPT_KEYWORDS="**" emerge --ask ~games-util/gamemode-9999
 ```
 
+### Build and Install GameMode
 Then clone, build and install a release version of GameMode at 1.2:
 
 ```bash
 git clone https://github.com/FeralInteractive/gamemode.git
 cd gamemode
-git checkout 1.2
-./bootstrap.sh
-```
-
-To build the master branch:
-
-```bash
-git clone https://github.com/FeralInteractive/gamemode.git
-cd gamemode
-git submodule update --init --recursive
+git checkout 1.2 # omit to build the master branch
 ./bootstrap.sh
 ```
 
-This will also satisfy the build requirement `inih` by pulling it in as a git submodule.
-
 To uninstall:
 ```bash
 systemctl --user stop gamemoded.service
@@ -71,44 +58,60 @@ ninja uninstall
 ---
 ## Requesting GameMode
 
-### Users
 After installing `libgamemodeauto.so.0` simply preload it into the game:
 ```bash
-LD_PRELOAD=/usr/\$LIB/libgamemodeauto.so.0 ./game
+gamemoderun ./game
 ```
 Or edit the steam launch options:
 ```bash
-LD_PRELOAD=$LD_PRELOAD:/usr/\$LIB/libgamemodeauto.so.0 %command%
+gamemoderun %command%
 ```
 Please note the backslash here in `\$LIB` is required.
 
-### Developers
-Developers can build the request directly into an app. Note that none of these client methods force your users to have the daemon installed or running - they will safely no-op if the host is missing.
+Note: for older versions of GameMode (1.2) use this string in place of `gamemoderun`:
+```
+LD_PRELOAD="$LD_PRELOAD:/usr/\$LIB/libgamemodeauto.so.0"
+```
+---
+## Configuration
 
-```C
-// Manually with error checking
-#include "gamemode_client.h"
+The daemon can currently be configured using a `gamemode.ini` file. [gamemode.ini](https://github.com/FeralInteractive/gamemode/blob/master/example/gamemode.ini) is an example of what this file would look like, with explanations for all the variables.
 
-	if( gamemode_request_start() < 0 ) {
-		fprintf( stderr, "gamemode request failed: %s\n", gamemode_error_string() );
-	}
+Config files are loaded and merged from the following directories, in order:
+1. `/usr/share/gamemode/`
+2. `/etc/`
+3. `$XDG_CONFIG_HOME` or `$HOME/.config/`
+4. `$PWD`
 
-	/* run game... */
+The file parsing uses [inih](https://github.com/benhoyt/inih).
 
-	gamemode_request_end(); // Not required, gamemoded can clean up after game exits
-```
+---
+## Features
 
-```C
-// Automatically on program start and finish
-#define GAMEMODE_AUTO
-#include "gamemode_client.h"
-```
+### Scheduling
+GameMode can leverage support for soft real time mode if the running kernel supports `SCHED_ISO`. This adjusts the scheduling of the game to real time without sacrificing system stability by starving other processes.
 
-Or, distribute `libgamemodeauto.so` and either add `-lgamemodeauto` to your linker arguments, or add it to an LD\_PRELOAD in a launch script.
+GameMode adjusts the nice priority of games to -4 by default to give it a slight IO and CPU priority over other background processes. This only works if your user is permitted to adjust priorities within the limits configured by PAM. GameMode can be configured to take care of it by passing `with-pam-group=group` to the build options where `group` is a group your user needs to be part of.
+For more information, see `/etc/security/limits.conf`.
+
+Please take note that some games may actually run seemingly slower with `SCHED_ISO` if the game makes use of busy looping while interacting with the graphic driver. The same may happen if you apply too strong nice values. This effect is called priority inversion: Due to the high priority given to busy loops, there may be too few resources left for the graphics driver. Thus, sane defaults were chosen to not expose this effect on most systems. Part of this default is a heuristic which automatically turns off `SCHED_ISO` if GameMode detects three or less CPU cores. Your experience may change based on using GL threaded optimizations, CPU core binding (taskset), the graphic driver, or different CPU architectures. If you experience bad input latency or inconsistent FPS, try switching these configurations on or off first and report back. `SCHED_ISO` comes with a protection against this effect by falling back to normal scheduling as soon as the `SCHED_ISO` process uses more than 70% avarage across all CPU cores. This default value can be adjusted outside of the scope of GameMode (it's in `/proc/sys/kernel/iso_cpu`). This value also protects against compromising system stability, do not set it to 100% as this would turn the game into a full real time process, thus potentially starving all other OS components from CPU resources.
+
+### IO priority
+GameMode can adjust the io priority of games to benefit from reduced lag and latency when a game has to load assets on demand.
+
+### For those with overclocked CPUs
+If you have an AMD CPU and have disabled Cool'n'Quiet, or you have an Intel CPU and have disabled SpeedStep, then GameMode's governor settings will not work, as your CPU is not running with a governor. You are already getting maximum performance.
+
+If you are unsure, `bootstrap.sh` will warn you if your system lacks CPU governor control.
+
+Scripts and other features will still work.
 
 ---
-## Components
+## Developers
 
+The design of GameMode has a clear-cut abstraction between the host daemon and library (`gamemoded` and `libgamemode`), and the client loaders (`libgamemodeauto` and `gamemode_client.h`) that allows for safe use without worrying about whether the daemon is installed or running. This design also means that while the host library currently relies on `systemd` for exchanging messages with the daemon, it's entirely possible to implement other internals that still work with the same clients.
+
+### Components
 **gamemoded** runs in the background, activates game mode on request, refcounts and also checks caller PID lifetime. Run `man gamemoded` for command line options.
 
 **libgamemode** is an internal library used to dispatch requests to the daemon. Note: `libgamemode` should never be linked with directly.
@@ -117,26 +120,29 @@ Or, distribute `libgamemodeauto.so` and either add `-lgamemodeauto` to your link
 
 **gamemode\_client.h** is as single header lib that lets a game request game mode and handle errors.
 
----
-## Configuration
+### Integration
+Developers can integrate the request directly into an app. Note that none of these client methods force your users to have the daemon installed or running - they will safely no-op if the host is missing.
 
-The daemon can currently be configured using a `gamemode.ini` file. [gamemode.ini](https://github.com/FeralInteractive/gamemode/blob/master/example/gamemode.ini) is an example of what this file would look like, with explanations for all the variables.
+```C
+// Manually with error checking
+#include "gamemode_client.h"
 
-Config files are loaded and merged from the following directories, in order:
-1. `/usr/share/gamemode/`
-2. `/etc/`
-3. `$XDG_CONFIG_HOME` or `$HOME/.config/`
-4. `$PWD`
+	if( gamemode_request_start() < 0 ) {
+		fprintf( stderr, "gamemode request failed: %s\n", gamemode_error_string() );
+	}
 
-The file parsing uses [inih](https://github.com/benhoyt/inih).
+	/* run game... */
 
----
-## For those with overclocked CPUs
-If you have an AMD CPU and have disabled Cool'n'Quiet, or you have an Intel CPU and have disabled SpeedStep, then GameMode's governor settings will not work, as your CPU is not running with a governor. You are already getting maximum performance.
+	gamemode_request_end(); // Not required, gamemoded can clean up after game exits
+```
 
-If you are unsure, `bootstrap.sh` will warn you if your system lacks CPU governor control.
+```C
+// Automatically on program start and finish
+#define GAMEMODE_AUTO
+#include "gamemode_client.h"
+```
 
-Scripts and other features will still work.
+Or, distribute `libgamemodeauto.so` and either add `-lgamemodeauto` to your linker arguments, or add it to an LD\_PRELOAD in a launch script.
 
 ---
 ## Contributions

+ 1 - 2
daemon/cpugovctl.c

@@ -48,7 +48,6 @@ static int set_gov_state(const char *value)
 	int retval = EXIT_SUCCESS;
 	int res = 0;
 
-	LOG_MSG("Setting governors to %s\n", value);
 	for (int i = 0; i < num; i++) {
 		const char *gov = governors[i];
 		FILE *f = fopen(gov, "w");
@@ -80,7 +79,7 @@ int main(int argc, char *argv[])
 
 		/* Must be root to set the state */
 		if (geteuid() != 0) {
-			fprintf(stderr, "This program must be run as root\n");
+			LOG_ERROR("This program must be run as root\n");
 			return EXIT_FAILURE;
 		}
 

+ 16 - 1
daemon/daemon_config.c

@@ -72,6 +72,8 @@ struct GameModeConfig {
 
 	char ioprio[CONFIG_VALUE_MAX];
 
+	long inhibit_screensaver;
+
 	long reaper_frequency;
 };
 
@@ -168,6 +170,8 @@ static int inih_handler(void *user, const char *section, const char *name, const
 			valid = get_long_value(name, value, &self->renice);
 		} else if (strcmp(name, "ioprio") == 0) {
 			valid = get_string_value(value, self->ioprio);
+		} else if (strcmp(name, "inhibit_screensaver") == 0) {
+			valid = get_long_value(name, value, &self->inhibit_screensaver);
 		}
 	} else if (strcmp(section, "custom") == 0) {
 		/* Custom subsection */
@@ -227,8 +231,9 @@ static void load_config_files(GameModeConfig *self)
 	memset(self->defaultgov, 0, sizeof(self->defaultgov));
 	memset(self->desiredgov, 0, sizeof(self->desiredgov));
 	memset(self->softrealtime, 0, sizeof(self->softrealtime));
-	self->renice = 0; /* 0 = use default */
+	self->renice = 4; /* default value of 4 */
 	self->reaper_frequency = DEFAULT_REAPER_FREQ;
+	self->inhibit_screensaver = 1; /* Defaults to on */
 
 	/*
 	 * Locations to load, in order
@@ -382,6 +387,16 @@ void config_get_reaper_thread_frequency(GameModeConfig *self, long *value)
 	memcpy_locked_config(self, value, &self->reaper_frequency, sizeof(long));
 }
 
+/*
+ * Gets the screensaver inhibit setting
+ */
+bool config_get_inhibit_screensaver(GameModeConfig *self)
+{
+	long val;
+	memcpy_locked_config(self, &val, &self->inhibit_screensaver, sizeof(long));
+	return val == 1;
+}
+
 /*
  * Get a set of scripts to call when gamemode starts
  */

+ 5 - 0
daemon/daemon_config.h

@@ -89,6 +89,11 @@ bool config_get_client_blacklisted(GameModeConfig *self, const char *client);
  */
 void config_get_reaper_thread_frequency(GameModeConfig *self, long *value);
 
+/*
+ * Get whether we want to inhibit the screensaver (defaults to true)
+ */
+bool config_get_inhibit_screensaver(GameModeConfig *self);
+
 /*
  * Get a set of scripts to call when gamemode starts
  */

+ 2 - 10
daemon/gamemode-sched.c

@@ -48,11 +48,6 @@ POSSIBILITY OF SUCH DAMAGE.
 #define SCHED_ISO 4
 #endif
 
-/**
- * Priority to renice the process to.
- */
-#define NICE_DEFAULT_PRIORITY -4
-
 /**
  * Apply scheduling policies
  *
@@ -74,11 +69,8 @@ void game_mode_apply_renice(const GameModeContext *self, const pid_t client)
 	long int renice = 0;
 	config_get_renice_value(config, &renice);
 	if ((renice < 1) || (renice > 20)) {
-		LOG_ONCE(ERROR,
-		         "Invalid renice value '%ld' reset to default: %d.\n",
-		         renice,
-		         -NICE_DEFAULT_PRIORITY);
-		renice = NICE_DEFAULT_PRIORITY;
+		LOG_ONCE(ERROR, "Configured renice value '%ld' is invalid, will not renice.\n", renice);
+		return;
 	} else {
 		renice = -renice;
 	}

+ 25 - 32
daemon/gamemode-tests.c

@@ -48,13 +48,11 @@ static int verify_gamemode_initial(void)
 	int status = 0;
 
 	if ((status = gamemode_query_status()) != 0 && status != -1) {
-		fprintf(
-		    stderr,
-		    "ERROR: gamemode is currently active, tests require gamemode to start deactivated!\n");
+		LOG_ERROR("gamemode is currently active, tests require gamemode to start deactivated!\n");
 		status = -1;
 	} else if (status == -1) {
-		fprintf(stderr, "ERROR: gamemode_query_status failed: %s!\n", gamemode_error_string());
-		fprintf(stderr, "ERROR: is gamemode installed correctly?\n");
+		LOG_ERROR("gamemode_query_status failed: %s!\n", gamemode_error_string());
+		LOG_ERROR("is gamemode installed correctly?\n");
 		status = -1;
 	} else {
 		status = 0;
@@ -70,13 +68,11 @@ static int verify_active_and_registered(void)
 
 	if (status != 2) {
 		if (status == -1) {
-			fprintf(stderr, "ERROR: gamemode_query_status failed: %s\n", gamemode_error_string());
+			LOG_ERROR("gamemode_query_status failed: %s\n", gamemode_error_string());
 		} else if (status == 1) {
-			fprintf(stderr,
-			        "ERROR: gamemode was active but did not have this process registered\n");
+			LOG_ERROR("gamemode was active but did not have this process registered\n");
 		}
-		fprintf(stderr,
-		        "ERROR: gamemode failed to activate correctly when requested (expected 2)!\n");
+		LOG_ERROR("gamemode failed to activate correctly when requested (expected 2)!\n");
 		status = -1;
 	} else {
 		status = 0;
@@ -92,9 +88,9 @@ static int verify_deactivated(void)
 
 	if (status != 0) {
 		if (status == -1) {
-			fprintf(stderr, "ERROR: gamemode_query_status failed: %s\n", gamemode_error_string());
+			LOG_ERROR("gamemode_query_status failed: %s\n", gamemode_error_string());
 		}
-		fprintf(stderr, "ERROR: gamemode failed to deactivate when requested (expected 0)!\n");
+		LOG_ERROR("gamemode failed to deactivate when requested (expected 0)!\n");
 		status = -1;
 	} else {
 		status = 0;
@@ -110,11 +106,9 @@ static int verify_other_client_connected(void)
 
 	if (status != 1) {
 		if (status == -1) {
-			fprintf(stderr, "ERROR: gamemode_query_status failed: %s\n", gamemode_error_string());
+			LOG_ERROR("gamemode_query_status failed: %s\n", gamemode_error_string());
 		}
-		fprintf(
-		    stderr,
-		    "ERROR: gamemode_query_status failed to return other client connected (expected 1)!\n");
+		LOG_ERROR("gamemode_query_status failed to return other client connected (expected 1)!\n");
 		status = -1;
 	} else {
 		status = 0;
@@ -128,7 +122,7 @@ static int verify_other_client_connected(void)
  */
 static int run_basic_client_tests(void)
 {
-	fprintf(stdout, "   *basic client tests*\n");
+	LOG_MSG("   *basic client tests*\n");
 
 	/* First verify that gamemode is not currently active on the system
 	 * As well as it being currently installed and queryable
@@ -138,7 +132,7 @@ static int run_basic_client_tests(void)
 
 	/* Verify that gamemode_request_start correctly start gamemode */
 	if (gamemode_request_start() != 0) {
-		fprintf(stderr, "ERROR: gamemode_request_start failed: %s\n", gamemode_error_string());
+		LOG_ERROR("gamemode_request_start failed: %s\n", gamemode_error_string());
 		return -1;
 	}
 
@@ -148,7 +142,7 @@ static int run_basic_client_tests(void)
 
 	/* Verify that gamemode_request_end corrently de-registers gamemode */
 	if (gamemode_request_end() != 0) {
-		fprintf(stderr, "ERROR: gamemode_request_end failed: %s!\n", gamemode_error_string());
+		LOG_ERROR("gamemode_request_end failed: %s!\n", gamemode_error_string());
 		return -1;
 	}
 
@@ -156,7 +150,7 @@ static int run_basic_client_tests(void)
 	if (verify_deactivated() != 0)
 		return -1;
 
-	fprintf(stdout, "       *passed*\n");
+	LOG_MSG("       *passed*\n");
 
 	return 0;
 }
@@ -169,12 +163,13 @@ static int run_dual_client_tests(void)
 	int status = 0;
 
 	/* Try running some process interop tests */
-	fprintf(stdout, "   *dual clients tests*\n");
+	LOG_MSG("   *dual clients tests*\n");
 
 	/* Get the current path to this binary */
 	char mypath[PATH_MAX];
+	memset(mypath, 0, sizeof(mypath));
 	if (readlink("/proc/self/exe", mypath, PATH_MAX) == -1) {
-		fprintf(stderr, "ERROR: could not read current exe path: %s\n", strerror(errno));
+		LOG_ERROR("could not read current exe path: %s\n", strerror(errno));
 		return -1;
 	}
 
@@ -182,8 +177,8 @@ static int run_dual_client_tests(void)
 	int child = fork();
 	if (child == 0) {
 		/* Relaunch self with -r (request and wait for signal) */
-		if (execl(mypath, mypath, "-r") == -1) {
-			fprintf(stderr, "ERROR: failed to re-launch self with execv: %s\n", strerror(errno));
+		if (execl(mypath, mypath, "-r", (char *)NULL) == -1) {
+			LOG_ERROR("failed to re-launch self (%s) with execl: %s\n", mypath, strerror(errno));
 			return -1;
 		}
 	}
@@ -200,7 +195,7 @@ static int run_dual_client_tests(void)
 
 	/* Verify that gamemode_request_start correctly start gamemode */
 	if (gamemode_request_start() != 0) {
-		fprintf(stderr, "ERROR: gamemode_request_start failed: %s\n", gamemode_error_string());
+		LOG_ERROR("gamemode_request_start failed: %s\n", gamemode_error_string());
 		status = -1;
 	}
 
@@ -210,7 +205,7 @@ static int run_dual_client_tests(void)
 
 	/* Request end of gamemode (de-register ourselves) */
 	if (gamemode_request_end() != 0) {
-		fprintf(stderr, "ERROR: gamemode_request_end failed: %s!\n", gamemode_error_string());
+		LOG_ERROR("gamemode_request_end failed: %s!\n", gamemode_error_string());
 		status = -1;
 	}
 
@@ -220,9 +215,7 @@ static int run_dual_client_tests(void)
 
 	/* Send SIGINT to child to wake it up*/
 	if (kill(child, SIGINT) == -1) {
-		fprintf(stderr,
-		        "ERROR: failed to send continue signal to other client: %s\n",
-		        strerror(errno));
+		LOG_ERROR("failed to send continue signal to other client: %s\n", strerror(errno));
 		status = -1;
 	}
 
@@ -232,7 +225,7 @@ static int run_dual_client_tests(void)
 	// Wait for the child to finish up
 	int wstatus;
 	while (waitpid(child, &wstatus, WNOHANG) == 0) {
-		fprintf(stdout, "   Waiting for child to quit...\n");
+		LOG_MSG("   Waiting for child to quit...\n");
 		usleep(10000);
 	}
 
@@ -241,7 +234,7 @@ static int run_dual_client_tests(void)
 		return -1;
 
 	if (status == 0)
-		fprintf(stdout, "       *passed*\n");
+		LOG_MSG("       *passed*\n");
 
 	return status;
 }
@@ -255,7 +248,7 @@ static int run_dual_client_tests(void)
 int game_mode_run_client_tests()
 {
 	int status = 0;
-	fprintf(stdout, "Running tests...\n");
+	LOG_MSG("Running tests...\n");
 
 	/* Run the basic tests */
 	if (run_basic_client_tests() != 0)

+ 4 - 2
daemon/gamemode.c

@@ -198,7 +198,8 @@ static void game_mode_context_enter(GameModeContext *self)
 	}
 
 	/* Inhibit the screensaver */
-	game_mode_inhibit_screensaver(true);
+	if (config_get_inhibit_screensaver(self->config))
+		game_mode_inhibit_screensaver(true);
 }
 
 /**
@@ -213,7 +214,8 @@ static void game_mode_context_leave(GameModeContext *self)
 	sd_notifyf(0, "STATUS=%sGameMode is currently deactivated.%s\n", "\x1B[1;36m", "\x1B[0m");
 
 	/* UnInhibit the screensaver */
-	game_mode_inhibit_screensaver(false);
+	if (config_get_inhibit_screensaver(self->config))
+		game_mode_inhibit_screensaver(false);
 
 	/* Reset the governer state back to initial */
 	if (self->initial_cpu_mode[0] != '\0') {

+ 3 - 3
daemon/logging.h

@@ -51,14 +51,14 @@ POSSIBILITY OF SUCH DAMAGE.
 		}                                                                                          \
 	} while (0)
 
-#define PLOG_ERROR(...) fprintf(stderr, __VA_ARGS__)
+#define PLOG_ERROR(...) fprintf(stderr, "ERROR: " __VA_ARGS__)
 #define SYSLOG_ERROR(...) syslog(LOG_ERR, __VA_ARGS__)
 #define LOG_ERROR(...)                                                                             \
 	do {                                                                                           \
 		if (get_use_syslog()) {                                                                    \
-			SYSLOG_MSG(__VA_ARGS__);                                                               \
+			SYSLOG_ERROR(__VA_ARGS__);                                                             \
 		} else {                                                                                   \
-			PLOG_MSG(__VA_ARGS__);                                                                 \
+			PLOG_ERROR(__VA_ARGS__);                                                               \
 		}                                                                                          \
 	} while (0)
 

+ 14 - 15
daemon/main.c

@@ -63,7 +63,7 @@ POSSIBILITY OF SUCH DAMAGE.
 #include <unistd.h>
 
 #define USAGE_TEXT                                                                                 \
-	"Usage: %s [-d] [-l] [-h] [-v]\n\n"                                                            \
+	"Usage: %s [-d] [-l] [-r] [-t] [-h] [-v]\n\n"                                                  \
 	"  -d  daemonize self after launch\n"                                                          \
 	"  -l  log to syslog\n"                                                                        \
 	"  -r  request gamemode and pause\n"                                                           \
@@ -113,12 +113,12 @@ int main(int argc, char *argv[])
 			break;
 		case 's': {
 			if ((status = gamemode_query_status()) < 0) {
-				fprintf(stderr, "gamemode status request failed: %s\n", gamemode_error_string());
+				LOG_ERROR("gamemode status request failed: %s\n", gamemode_error_string());
 				exit(EXIT_FAILURE);
 			} else if (status > 0) {
-				fprintf(stdout, "gamemode is active\n");
+				LOG_MSG("gamemode is active\n");
 			} else {
-				fprintf(stdout, "gamemode is inactive\n");
+				LOG_MSG("gamemode is inactive\n");
 			}
 
 			exit(EXIT_SUCCESS);
@@ -126,18 +126,17 @@ int main(int argc, char *argv[])
 		}
 		case 'r':
 			if (gamemode_request_start() < 0) {
-				fprintf(stderr, "gamemode request failed: %s\n", gamemode_error_string());
+				LOG_ERROR("gamemode request failed: %s\n", gamemode_error_string());
 				exit(EXIT_FAILURE);
 			}
 
 			if ((status = gamemode_query_status()) == 2) {
-				fprintf(stdout, "gamemode request succeeded and is active\n");
+				LOG_MSG("gamemode request succeeded and is active\n");
 			} else if (status == 1) {
-				fprintf(stderr,
-				        "gamemode request succeeded and is active but registration failed\n");
+				LOG_ERROR("gamemode request succeeded and is active but registration failed\n");
 				exit(EXIT_FAILURE);
 			} else {
-				fprintf(stderr, "gamemode request succeeded but is not active\n");
+				LOG_ERROR("gamemode request succeeded but is not active\n");
 				exit(EXIT_FAILURE);
 			}
 
@@ -149,7 +148,7 @@ int main(int argc, char *argv[])
 
 			// Explicitly clean up
 			if (gamemode_request_end() < 0) {
-				fprintf(stderr, "gamemode request failed: %s\n", gamemode_error_string());
+				LOG_ERROR("gamemode request failed: %s\n", gamemode_error_string());
 				exit(EXIT_FAILURE);
 			}
 
@@ -157,22 +156,22 @@ int main(int argc, char *argv[])
 			break;
 		case 't':
 			if ((status = game_mode_run_client_tests()) == 0) {
-				fprintf(stdout, "gamemode tests succeeded\n");
+				LOG_MSG("gamemode tests succeeded\n");
 				exit(EXIT_SUCCESS);
 			} else if (status == -1) {
-				fprintf(stderr, "gamemode tests failed\n");
+				LOG_ERROR("gamemode tests failed\n");
 				exit(EXIT_FAILURE);
 			} else {
-				fprintf(stderr, "gamemode test results unknown: %d\n", status);
+				LOG_ERROR("gamemode test results unknown: %d\n", status);
 				exit(EXIT_FAILURE);
 			}
 			break;
 		case 'v':
-			fprintf(stdout, VERSION_TEXT);
+			LOG_MSG(VERSION_TEXT);
 			exit(EXIT_SUCCESS);
 			break;
 		case 'h':
-			fprintf(stdout, USAGE_TEXT, argv[0]);
+			LOG_MSG(USAGE_TEXT, argv[0]);
 			exit(EXIT_SUCCESS);
 			break;
 		default:

+ 12 - 43
data/gamemoded.8 → data/gamemoded.8.in

@@ -28,6 +28,9 @@ Query the current status of gamemode
 .B \-h
 Print help text
 .TP 8
+.B \-t
+Run diagnostic tests on the current installation
+.TP 8
 .B \-v
 Print the version
 
@@ -35,13 +38,19 @@ Print the version
 \fBlibgamemodeauto.so.0\fR can be pre-loaded into any program to request \fBgamemoded\fR begin or end the mode, like so:
 
 .RS 4
-LD_PRELOAD=/usr/\e$LIB/libgamemodeauto.so.0 \./game
+gamemoderun \./game
 .RE
 
 Or by setting the steam launch options for a game:
 
 .RS 4
-LD_PRELOAD=$LD_PRELOAD:/usr/\e$LIB/libgamemodeauto.so.0 %command%
+gamemoderun %command%
+.RE
+
+The library can be manually preloaded if needed:
+
+.RS 4
+LD_PRELOAD=$LD_PRELOAD:/usr/\e$LIB/libgamemodeauto.so.0 ./game
 .RE
 
 The \fBgamemode_client.h\fR header can be used by developers to build the requests into a program:
@@ -93,50 +102,10 @@ Behaviour of the config file can be explained by presenting a commented example:
 
 .RS 4
 .nf
-[general]
-; The reaper thread will check every 10 seconds for exited clients
-reaper_freq=10
-
-; The desired governor is used when entering GameMode instead of "performance"
-desiredgov=performance
-; The default governer is used when leaving GameMode instead of restoring the original value
-defaultgov=powersave
-
-; By default, GameMode changes the scheduler policy to SCHED_ISO with 4 or more CPU cores,
-; force enable or disable with "on" or "off"
-softrealtime=auto
-
-; By default, GameMode renices the client to -4, you can put any value between 1 and 20 here,
-; the value will be negated and applied as a nice value
-renice = 4
-
-; By default, GameMode adjusts the iopriority of clients to BE/0, you can put any value
-; between 0 and 7 here (with 0 being highest priority), or one of the special values
-; "off" (to disable) or "reset" (to restore Linux default behavior based on CPU priority),
-; currently, only the best-effort class is supported thus you cannot set it here
-ioprio = 0
-
-[filter]
-; If "whitelist" entry has a value(s)
-; gamemode will reject anything not in the whitelist
-;whitelist=RiseOfTheTombRaider
-
-; Gamemode will always reject anything in the blacklist
-blacklist=HalfLife3
-    glxgears
-
-[custom]
-; Custom scripts (executed using the shell) when gamemode starts and ends
-start=notify-send "GameMode started"
-    /home/me/bin/stop_ethmining.sh
-
-end=notify-send "GameMode ended"
-    /home/me/bin/start_ethmining.sh
+@GAMEMODE_EXAMPLE_CONFIG@
 .fi
 .RE
 
-This config file will currently reject any games that match \fIHalfLife3\fR or \fIglxgears\fR, but can be modified to only accept \fIRiseOfTheTombRaider\fR by removing the semicolon preceding the fourth line.
-
 .SH SEE ALSO
 systemd(1)
 

+ 11 - 0
data/gamemoderun.in

@@ -0,0 +1,11 @@
+#!/bin/bash
+# Helper script to launch games with gamemode
+
+# Path to install gamemoded auto script
+CONFIG_LIB_DIR="@GAMEMODE_LIB_DIR@/libgamemodeauto.so.0"
+
+# Set the ld library path prefixed libgamemodeauto
+export LD_LIBRARY_PATH=${CONFIG_LIB_DIR}${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
+
+# Launch
+exec "$@"

+ 24 - 2
data/meson.build

@@ -1,6 +1,14 @@
 data_conf = configuration_data()
 data_conf.set('BINDIR', path_bindir)
 data_conf.set('LIBEXECDIR', path_libexecdir)
+data_conf.set('GAMEMODE_LIB_DIR', path_libdir)
+
+# Pull in the example config
+config_example = run_command(
+    'cat',
+    join_paths(meson.source_root(), 'example', 'gamemode.ini')
+).stdout().strip()
+data_conf.set('GAMEMODE_EXAMPLE_CONFIG', config_example)
 
 if with_systemd == true
     # Install systemd user unit
@@ -29,5 +37,19 @@ configure_file(
     install_dir: path_polkit_action_dir,
 )
 
-# Install the man page
-install_man('gamemoded.8')
+# Install the helper run script
+configure_file(
+    input: 'gamemoderun.in',
+    output: 'gamemoderun',
+    configuration: data_conf,
+    install_dir: 'bin',
+    install_mode: 'rwxr-xr-x',
+)
+
+# Configure and install the man page
+manpage = configure_file(
+    input: files('gamemoded.8.in'),
+    output: 'gamemoded.8',
+    configuration: data_conf,
+)
+install_man(manpage)

+ 4 - 0
example/gamemode.ini

@@ -21,6 +21,10 @@ renice = 4
 ; currently, only the best-effort class is supported thus you cannot set it here
 ioprio = 0
 
+; Sets whether gamemode will inhibit the screensaver when active
+; Defaults to 1
+inhibit_screensaver=1
+
 [filter]
 ; If "whitelist" entry has a value(s)
 ; gamemode will reject anything not in the whitelist