mirror of
https://github.com/FeralInteractive/gamemode.git
synced 2025-06-06 15:47:20 +02:00
Add gamemode_query_status and teach gamemoded '-s'
This allows the client to query the daemon about the status of gamemode. Returns the following: 0 if gamemode is inactive 1 if gamemode is active 2 if gamemode is active and this client is registered -1 if the query failed Passing -s to gamemoded will simply query and print the current status. Allows for more comprehensive testing when using 'gamemoded -r' as well as more reactionary program behaviour
This commit is contained in:
parent
966c207a33
commit
4f3bc2c9a2
@ -68,7 +68,7 @@ Or, distribute `libgamemodeauto.so` and either add `-lgamemodeauto` to your link
|
|||||||
---
|
---
|
||||||
## Components
|
## Components
|
||||||
|
|
||||||
**gamemoded** runs in the background, activates game mode on request, refcounts and also checks caller PID lifetime. Accepts `-d` (daemonize) and `-l` (log to syslog).
|
**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.
|
**libgamemode** is an internal library used to dispatch requests to the daemon. Note: `libgamemode` should never be linked with directly.
|
||||||
|
|
||||||
@ -95,7 +95,6 @@ clang-format -i $(find . -name '*.[ch]' -not -path "*subprojects/*")
|
|||||||
### Planned Features
|
### Planned Features
|
||||||
* Additional mode-switch plugins
|
* Additional mode-switch plugins
|
||||||
* Improved client state tracking (PID is unreliable)
|
* Improved client state tracking (PID is unreliable)
|
||||||
* API to query if game mode is active
|
|
||||||
|
|
||||||
### Maintained by
|
### Maintained by
|
||||||
Feral Interactive
|
Feral Interactive
|
||||||
|
@ -101,6 +101,26 @@ static int method_unregister_game(sd_bus_message *m, void *userdata,
|
|||||||
return sd_bus_reply_method_return(m, "i", 0);
|
return sd_bus_reply_method_return(m, "i", 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the QueryStatus D-BUS Method
|
||||||
|
*/
|
||||||
|
static int method_query_status(sd_bus_message *m, void *userdata,
|
||||||
|
__attribute__((unused)) sd_bus_error *ret_error)
|
||||||
|
{
|
||||||
|
int pid = 0;
|
||||||
|
GameModeContext *context = userdata;
|
||||||
|
|
||||||
|
int ret = sd_bus_message_read(m, "i", &pid);
|
||||||
|
if (ret < 0) {
|
||||||
|
LOG_ERROR("Failed to parse input parameters: %s\n", strerror(-ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int status = game_mode_context_query_status(context, (pid_t)pid);
|
||||||
|
|
||||||
|
return sd_bus_reply_method_return(m, "i", status);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* D-BUS vtable to dispatch virtual methods
|
* D-BUS vtable to dispatch virtual methods
|
||||||
*/
|
*/
|
||||||
@ -108,6 +128,7 @@ static const sd_bus_vtable gamemode_vtable[] =
|
|||||||
{ SD_BUS_VTABLE_START(0),
|
{ SD_BUS_VTABLE_START(0),
|
||||||
SD_BUS_METHOD("RegisterGame", "i", "i", method_register_game, SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_METHOD("RegisterGame", "i", "i", method_register_game, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_METHOD("UnregisterGame", "i", "i", method_unregister_game, SD_BUS_VTABLE_UNPRIVILEGED),
|
SD_BUS_METHOD("UnregisterGame", "i", "i", method_unregister_game, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
|
SD_BUS_METHOD("QueryStatus", "i", "i", method_query_status, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||||
SD_BUS_VTABLE_END };
|
SD_BUS_VTABLE_END };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -366,6 +366,40 @@ bool game_mode_context_unregister(GameModeContext *self, pid_t client)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int game_mode_context_query_status(GameModeContext *self, pid_t client)
|
||||||
|
{
|
||||||
|
GameModeClient *cl = NULL;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check the current refcount on gamemode, this equates to whether gamemode is active or not,
|
||||||
|
* see game_mode_context_register and game_mode_context_unregister
|
||||||
|
*/
|
||||||
|
if (atomic_load_explicit(&self->refcount, memory_order_seq_cst)) {
|
||||||
|
ret++;
|
||||||
|
|
||||||
|
/* Check if the current client is registered */
|
||||||
|
|
||||||
|
/* Requires locking. */
|
||||||
|
pthread_rwlock_rdlock(&self->rwlock);
|
||||||
|
|
||||||
|
for (cl = self->client; cl; cl = cl->next) {
|
||||||
|
if (cl->pid != client) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Found it */
|
||||||
|
ret++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unlock here, potentially yielding */
|
||||||
|
pthread_rwlock_unlock(&self->rwlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a new GameModeClient for the given process ID
|
* Construct a new GameModeClient for the given process ID
|
||||||
*
|
*
|
||||||
|
@ -73,3 +73,13 @@ bool game_mode_context_register(GameModeContext *self, pid_t pid);
|
|||||||
* @returns True if the client was removed, and existed.
|
* @returns True if the client was removed, and existed.
|
||||||
*/
|
*/
|
||||||
bool game_mode_context_unregister(GameModeContext *self, pid_t pid);
|
bool game_mode_context_unregister(GameModeContext *self, pid_t pid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query the current status of gamemode
|
||||||
|
*
|
||||||
|
* @param pid Process ID for the remote client
|
||||||
|
* @returns Positive if gamemode is active
|
||||||
|
* 1 if gamemode is active but the client is not registered
|
||||||
|
* 2 if gamemode is active and the client is registered
|
||||||
|
*/
|
||||||
|
int game_mode_context_query_status(GameModeContext *self, pid_t pid);
|
||||||
|
@ -96,7 +96,7 @@ int main(int argc, char *argv[])
|
|||||||
bool daemon = false;
|
bool daemon = false;
|
||||||
bool use_syslog = false;
|
bool use_syslog = false;
|
||||||
int opt = 0;
|
int opt = 0;
|
||||||
while ((opt = getopt(argc, argv, "dlrvh")) != -1) {
|
while ((opt = getopt(argc, argv, "dlsrvh")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'd':
|
case 'd':
|
||||||
daemon = true;
|
daemon = true;
|
||||||
@ -104,13 +104,38 @@ int main(int argc, char *argv[])
|
|||||||
case 'l':
|
case 'l':
|
||||||
use_syslog = true;
|
use_syslog = true;
|
||||||
break;
|
break;
|
||||||
|
case 's': {
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if ((status = gamemode_query_status()) < 0) {
|
||||||
|
fprintf(stderr, "gamemode status request failed: %s\n", gamemode_error_string());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else if (status > 0) {
|
||||||
|
fprintf(stdout, "gamemode is active\n");
|
||||||
|
} else {
|
||||||
|
fprintf(stdout, "gamemode is inactive\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'r':
|
case 'r':
|
||||||
if (gamemode_request_start() < 0) {
|
if (gamemode_request_start() < 0) {
|
||||||
fprintf(stderr, "gamemode request failed: %s\n", gamemode_error_string());
|
fprintf(stderr, "gamemode request failed: %s\n", gamemode_error_string());
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(stdout, "gamemode request succeeded...\n");
|
int status = gamemode_query_status();
|
||||||
|
if (status == 2) {
|
||||||
|
fprintf(stdout, "gamemode request succeeded and is active\n");
|
||||||
|
} else if (status == 1) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"gamemode request succeeded and is active but registration failed\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "gamemode request succeeded but is not active\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
// Simply pause and wait for any signal
|
// Simply pause and wait for any signal
|
||||||
pause();
|
pause();
|
||||||
|
@ -22,6 +22,9 @@ Log to syslog
|
|||||||
.B \-r
|
.B \-r
|
||||||
Request gamemode and wait for any signal
|
Request gamemode and wait for any signal
|
||||||
.TP 8
|
.TP 8
|
||||||
|
.B \-s
|
||||||
|
Query the current status of gamemode
|
||||||
|
.TP 8
|
||||||
.B \-h
|
.B \-h
|
||||||
Print help text
|
Print help text
|
||||||
.TP 8
|
.TP 8
|
||||||
|
@ -105,3 +105,9 @@ extern int real_gamemode_request_end(void)
|
|||||||
{
|
{
|
||||||
return gamemode_request("UnregisterGame");
|
return gamemode_request("UnregisterGame");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wrapper to call UnregisterGame
|
||||||
|
extern int real_gamemode_query_status(void)
|
||||||
|
{
|
||||||
|
return gamemode_request("QueryStatus");
|
||||||
|
}
|
||||||
|
@ -30,6 +30,28 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||||||
*/
|
*/
|
||||||
#ifndef CLIENT_GAMEMODE_H
|
#ifndef CLIENT_GAMEMODE_H
|
||||||
#define CLIENT_GAMEMODE_H
|
#define CLIENT_GAMEMODE_H
|
||||||
|
/*
|
||||||
|
* GameMode supports the following client functions
|
||||||
|
* Requests are refcounted in the daemon
|
||||||
|
*
|
||||||
|
* int gamemode_request_start() - Request gamemode starts
|
||||||
|
* 0 if the request was sent successfully
|
||||||
|
* -1 if the request failed
|
||||||
|
*
|
||||||
|
* int gamemode_request_end() - Request gamemode ends
|
||||||
|
* 0 if the request was sent successfully
|
||||||
|
* -1 if the request failed
|
||||||
|
*
|
||||||
|
* int gamemode_query_status() - Query the current status of gamemode
|
||||||
|
* 0 if gamemode is inactive
|
||||||
|
* 1 if gamemode is active
|
||||||
|
* 2 if gamemode is active and this client is registered
|
||||||
|
* -1 if the query failed
|
||||||
|
*
|
||||||
|
* const char* gamemode_error_string() - Get an error string
|
||||||
|
* returns a string describing any of the above errors
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@ -51,11 +73,13 @@ static volatile int internal_libgamemode_loaded = 1;
|
|||||||
/* Typedefs for the functions to load */
|
/* Typedefs for the functions to load */
|
||||||
typedef int (*internal_gamemode_request_start)(void);
|
typedef int (*internal_gamemode_request_start)(void);
|
||||||
typedef int (*internal_gamemode_request_end)(void);
|
typedef int (*internal_gamemode_request_end)(void);
|
||||||
|
typedef int (*internal_gamemode_query_status)(void);
|
||||||
typedef const char *(*internal_gamemode_error_string)(void);
|
typedef const char *(*internal_gamemode_error_string)(void);
|
||||||
|
|
||||||
/* Storage for functors */
|
/* Storage for functors */
|
||||||
static internal_gamemode_request_start REAL_internal_gamemode_request_start = NULL;
|
static internal_gamemode_request_start REAL_internal_gamemode_request_start = NULL;
|
||||||
static internal_gamemode_request_end REAL_internal_gamemode_request_end = NULL;
|
static internal_gamemode_request_end REAL_internal_gamemode_request_end = NULL;
|
||||||
|
static internal_gamemode_query_status REAL_internal_gamemode_query_status = NULL;
|
||||||
static internal_gamemode_error_string REAL_internal_gamemode_error_string = NULL;
|
static internal_gamemode_error_string REAL_internal_gamemode_error_string = NULL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -111,6 +135,9 @@ __attribute__((always_inline)) static inline int internal_load_libgamemode(void)
|
|||||||
{ "real_gamemode_request_end",
|
{ "real_gamemode_request_end",
|
||||||
(void **)&REAL_internal_gamemode_request_end,
|
(void **)&REAL_internal_gamemode_request_end,
|
||||||
sizeof(REAL_internal_gamemode_request_end) },
|
sizeof(REAL_internal_gamemode_request_end) },
|
||||||
|
{ "real_gamemode_query_status",
|
||||||
|
(void **)&REAL_internal_gamemode_query_status,
|
||||||
|
sizeof(REAL_internal_gamemode_query_status) },
|
||||||
{ "real_gamemode_error_string",
|
{ "real_gamemode_error_string",
|
||||||
(void **)&REAL_internal_gamemode_error_string,
|
(void **)&REAL_internal_gamemode_error_string,
|
||||||
sizeof(REAL_internal_gamemode_error_string) },
|
sizeof(REAL_internal_gamemode_error_string) },
|
||||||
@ -216,4 +243,15 @@ int gamemode_request_end(void)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Redirect to the real libgamemode */
|
||||||
|
__attribute__((always_inline)) static inline int gamemode_query_status(void)
|
||||||
|
{
|
||||||
|
/* Need to load gamemode */
|
||||||
|
if (internal_load_libgamemode() < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return REAL_internal_gamemode_query_status();
|
||||||
|
}
|
||||||
|
|
||||||
#endif // CLIENT_GAMEMODE_H
|
#endif // CLIENT_GAMEMODE_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user