From 837b4fe1251f2ac8cf978b1b4ef27afc2c85269d Mon Sep 17 00:00:00 2001 From: Benedikt Heine Date: Fri, 6 Jul 2018 19:41:02 +0200 Subject: [PATCH] Implement refcounting for notifications --- src/dbus.c | 2 +- src/notification.c | 34 +++++++++++++++++++++++++++++++++- src/notification.h | 16 +++++++++++++--- src/queues.c | 10 +++++----- test/notification.c | 4 ++-- 5 files changed, 54 insertions(+), 12 deletions(-) diff --git a/src/dbus.c b/src/dbus.c index fb75b75..603a510 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -282,7 +282,7 @@ static void on_notify(GDBusConnection *connection, // The message got discarded if (id == 0) { signal_notification_closed(n, 2); - notification_free(n); + notification_unref(n); } wake_up(); diff --git a/src/notification.c b/src/notification.c index b36a817..906deab 100644 --- a/src/notification.c +++ b/src/notification.c @@ -42,6 +42,10 @@ const char *enum_to_string_fullscreen(enum behavior_fullscreen in) } } +struct _notification_private { + gint refcount; +}; + /* see notification.h */ void notification_print(const struct notification *n) { @@ -206,12 +210,28 @@ void rawimage_free(struct raw_image *i) g_free(i); } +static void notification_private_free(NotificationPrivate *p) +{ + g_free(p); +} + /* see notification.h */ -void notification_free(struct notification *n) +void notification_ref(struct notification *n) +{ + assert(n->priv->refcount > 0); + g_atomic_int_inc(&n->priv->refcount); +} + +/* see notification.h */ +void notification_unref(struct notification *n) { if (!n) return; + assert(n->priv->refcount > 0); + if (!g_atomic_int_dec_and_test(&n->priv->refcount)) + return; + g_free(n->appname); g_free(n->summary); g_free(n->body); @@ -228,6 +248,8 @@ void notification_free(struct notification *n) actions_free(n->actions); rawimage_free(n->raw_icon); + notification_private_free(n->priv); + g_free(n); } @@ -255,11 +277,21 @@ void notification_replace_single_field(char **haystack, g_free(input); } +static NotificationPrivate *notification_private_create(void) +{ + NotificationPrivate *priv = g_malloc0(sizeof(NotificationPrivate)); + g_atomic_int_set(&priv->refcount, 1); + + return priv; +} + /* see notification.h */ struct notification *notification_create(void) { struct notification *n = g_malloc0(sizeof(struct notification)); + n->priv = notification_private_create(); + /* Unparameterized default values */ n->first_render = true; n->markup = settings.markup; diff --git a/src/notification.h b/src/notification.h index 80d64ab..6f9731b 100644 --- a/src/notification.h +++ b/src/notification.h @@ -42,7 +42,10 @@ struct actions { gsize count; }; +typedef struct _notification_private NotificationPrivate; + struct notification { + NotificationPrivate *priv; int id; char *dbus_client; @@ -90,11 +93,18 @@ struct notification { * - the default (if it's not needed to be freed later) * - its undefined representation (NULL, -1) * + * The reference counter is set to 1. + * * This function is guaranteed to return a valid pointer. * @returns The generated notification */ struct notification *notification_create(void); +/** + * Increase the reference counter of the notification. + */ +void notification_ref(struct notification *n); + /** * Sanitize values of notification, apply all matching rules * and generate derived fields. @@ -118,11 +128,11 @@ void actions_free(struct actions *a); void rawimage_free(struct raw_image *i); /** - * Free the memory used by the given notification. + * Decrease the reference counter of the notification. * - * @param n (nullable): pointer to #notification + * If the reference count drops to 0, the object gets freed. */ -void notification_free(struct notification *n); +void notification_unref(struct notification *n); /** * Helper function to compare two given notifications. diff --git a/src/queues.c b/src/queues.c index f5d2077..06efc50 100644 --- a/src/queues.c +++ b/src/queues.c @@ -191,7 +191,7 @@ static bool queues_stack_duplicate(struct notification *n) if ( allqueues[i] == displayed ) n->start = time_monotonic_now(); - notification_free(orig); + notification_unref(orig); return true; } } @@ -218,7 +218,7 @@ bool queues_notification_replace_id(struct notification *new) notification_run_script(new); } - notification_free(old); + notification_unref(old); return true; } } @@ -278,12 +278,12 @@ void queues_history_push(struct notification *n) if (!n->history_ignore) { if (settings.history_length > 0 && history->length >= settings.history_length) { struct notification *to_free = g_queue_pop_head(history); - notification_free(to_free); + notification_unref(to_free); } g_queue_push_tail(history, n); } else { - notification_free(n); + notification_unref(n); } } @@ -488,7 +488,7 @@ bool queues_pause_status(void) static void teardown_notification(gpointer data) { struct notification *n = data; - notification_free(n); + notification_unref(n); } /* see queues.h */ diff --git a/test/notification.c b/test/notification.c index b2673ac..3a29e98 100644 --- a/test/notification.c +++ b/test/notification.c @@ -121,8 +121,8 @@ SUITE(suite_notification) struct notification *n[2] = {a, b}; RUN_TEST1(test_notification_is_duplicate, (void*) n); - notification_free(a); - notification_free(b); + notification_unref(a); + notification_unref(b); RUN_TEST(test_notification_replace_single_field);