From 1a863f32a164aa76bec479877e7930efdd0c5f15 Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Mon, 1 Jul 2019 17:53:45 +0200 Subject: [PATCH] daemon: add ref-counting to GameModeClient This is so it can out-live its membership in the client list, e.g. when it is passed outside of gamemode-context.c and the reaper comes along and reaps a client in the background but we still are using the struct outside. --- daemon/gamemode-context.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/daemon/gamemode-context.c b/daemon/gamemode-context.c index c401632..e9151f7 100644 --- a/daemon/gamemode-context.c +++ b/daemon/gamemode-context.c @@ -52,6 +52,7 @@ POSSIBILITY OF SUCH DAMAGE. * form to contain the pid and credentials. */ struct GameModeClient { + _Atomic int refcount; /**client); + game_mode_client_unref(self->client); end_reaper_thread(self); @@ -444,7 +445,7 @@ error_cleanup: if (errno != 0) LOG_ERROR("Failed to register client [%d]: %s\n", client, strerror(errno)); free(executable); - game_mode_client_free(cl); + game_mode_client_unref(cl); return err; } @@ -508,7 +509,7 @@ int game_mode_context_unregister(GameModeContext *self, pid_t client, pid_t requ self->client = cl->next; } cl->next = NULL; - game_mode_client_free(cl); + game_mode_client_unref(cl); break; } @@ -616,20 +617,24 @@ static GameModeClient *game_mode_client_new(pid_t pid, char *executable) return NULL; } *ret = c; + ret->refcount = ATOMIC_VAR_INIT(1); strncpy(ret->executable, executable, PATH_MAX - 1); return ret; } /** - * Free a client and the next element in the list. + * Unref a client and the next element in the list, if non-null. */ -static void game_mode_client_free(GameModeClient *client) +static void game_mode_client_unref(GameModeClient *client) { if (!client) { return; } + if (atomic_fetch_sub_explicit(&client->refcount, 1, memory_order_seq_cst) > 1) { + return; /* object is still alive */ + } if (client->next) { - game_mode_client_free(client->next); + game_mode_client_unref(client->next); } free(client); }