From b952fc1f6d6db9658a45cdeba7aaa967f7c069cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Wed, 18 Nov 2015 23:03:21 +0100 Subject: [PATCH] degesch: extend weak pointers --- degesch.c | 53 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/degesch.c b/degesch.c index 74da23d..ce7563b 100644 --- a/degesch.c +++ b/degesch.c @@ -732,16 +732,29 @@ input_on_readable (struct input *self) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// We need a few reference countable objects with support -// for both strong and weak references +// We need a few reference countable objects with support for both strong +// and weak references (mainly used for scripted plugins). +// +// Beware that if you don't own the object, you will most probably want +// to keep the weak reference link so that you can get rid of it later. +// Also note that you have to make sure the user_data don't leak resources. +// +// Having a callback is more versatile than just nulling out a pointer. /// Callback just before a reference counted object is destroyed typedef void (*destroy_cb_fn) (void *object, void *user_data); +struct weak_ref_link +{ + LIST_HEADER (struct weak_ref_link) + + destroy_cb_fn on_destroy; ///< Called when object is destroyed + void *user_data; ///< User data +}; + #define REF_COUNTABLE_HEADER \ size_t ref_count; /**< Reference count */ \ - destroy_cb_fn on_destroy; /**< To remove any weak references */ \ - void *user_data; /**< User data for callbacks */ + struct weak_ref_link *weak_refs; /**< To remove any weak references */ #define REF_COUNTABLE_METHODS(name) \ static struct name * \ @@ -756,9 +769,31 @@ typedef void (*destroy_cb_fn) (void *object, void *user_data); { \ if (--self->ref_count) \ return; \ - if (self->on_destroy) \ - self->on_destroy (self, self->user_data); \ + LIST_FOR_EACH (struct weak_ref_link, iter, self->weak_refs) \ + { \ + iter->on_destroy (self, iter->user_data); \ + free (iter); \ + } \ name ## _destroy (self); \ + } \ + \ + static struct weak_ref_link * \ + name ## _weak_ref (struct name *self, destroy_cb_fn cb, void *user_data) \ + { \ + struct weak_ref_link *link = xcalloc (1, sizeof *link); \ + link->on_destroy = cb; \ + link->user_data = user_data; \ + LIST_PREPEND (self->weak_refs, link); \ + return link; \ + } \ + \ + static void \ + name ## _weak_unref (struct name *self, struct weak_ref_link **link) \ + { \ + if (*link) \ + LIST_UNLINK (self->weak_refs, *link); \ + free (*link); \ + *link = NULL; \ } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -3378,8 +3413,7 @@ irc_make_user (struct server *s, char *nickname) hard_assert (!str_map_find (&s->irc_users, nickname)); struct user *user = user_new (); - user->on_destroy = irc_user_on_destroy; - user->user_data = s; + (void) user_weak_ref (user, irc_user_on_destroy, s); user->nickname = nickname; str_map_set (&s->irc_users, user->nickname, user); return user; @@ -3482,8 +3516,7 @@ irc_make_channel (struct server *s, char *name) hard_assert (!str_map_find (&s->irc_channels, name)); struct channel *channel = channel_new (); - channel->on_destroy = irc_channel_on_destroy; - channel->user_data = s; + (void) channel_weak_ref (channel, irc_channel_on_destroy, s); channel->name = name; channel->topic = NULL; str_map_set (&s->irc_channels, channel->name, channel);