aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--degesch.c53
1 files 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);