struct notifier {
struct prop_hdr hdr; /* NOTIFIER */
enum tal_notify_type types;
- union {
+ union notifier_cb {
void (*notifyfn)(tal_t *, enum tal_notify_type, void *);
void (*destroy)(tal_t *); /* If NOTIFY_IS_DESTRUCTOR set */
void (*destroy2)(tal_t *, void *); /* If NOTIFY_EXTRA_ARG */
return (void *)(hdr + 1);
}
-#ifdef TAL_DEBUG
-static void *from_tal_hdr_or_null(struct tal_hdr *hdr)
+static void *from_tal_hdr_or_null(const struct tal_hdr *hdr)
{
if (hdr == &null_parent.hdr)
return NULL;
return from_tal_hdr(hdr);
}
+#ifdef TAL_DEBUG
static struct tal_hdr *debug_tal(struct tal_hdr *tal)
{
tal_check(from_tal_hdr_or_null(tal), "TAL_DEBUG ");
if (n->types & type) {
errno = saved_errno;
if (n->types & NOTIFY_IS_DESTRUCTOR) {
+ /* Blatt this notifier in case it tries to
+ * tal_del_destructor() from inside */
+ union notifier_cb cb = n->u;
+ /* It's a union, so this NULLs destroy2 too! */
+ n->u.destroy = NULL;
if (n->types & NOTIFY_EXTRA_ARG)
- n->u.destroy2(from_tal_hdr(ctx),
- EXTRA_ARG(n));
+ cb.destroy2(from_tal_hdr(ctx),
+ EXTRA_ARG(n));
else
- n->u.destroy(from_tal_hdr(ctx));
+ cb.destroy(from_tal_hdr(ctx));
} else
- n->u.notifyfn(from_tal_hdr(ctx), type,
+ n->u.notifyfn(from_tal_hdr_or_null(ctx), type,
(void *)info);
}
}
{
struct prop_hdr **prop, *p, *next;
+ assert(!taken(from_tal_hdr(t)));
+
/* Already being destroyed? Don't loop. */
if (unlikely(get_destroying_bit(t->parent_child)))
return;
bool tal_add_notifier_(const tal_t *ctx, enum tal_notify_type types,
void (*callback)(tal_t *, enum tal_notify_type, void *))
{
- tal_t *t = debug_tal(to_tal_hdr(ctx));
+ struct tal_hdr *t = debug_tal(to_tal_hdr_or_null(ctx));
struct notifier *n;
assert(types);
void (*callback)(tal_t *, enum tal_notify_type, void *),
bool match_extra_arg, void *extra_arg)
{
- struct tal_hdr *t = debug_tal(to_tal_hdr(ctx));
+ struct tal_hdr *t = debug_tal(to_tal_hdr_or_null(ctx));
enum tal_notify_type types;
types = del_notifier_property(t, callback, match_extra_arg, extra_arg);
/* Fix up linked list pointers. */
t->list.next->prev = t->list.prev->next = &t->list;
+ /* Copy take() property. */
+ if (taken(from_tal_hdr(old_t)))
+ take(from_tal_hdr(t));
+
/* Fix up child property's parent pointer. */
child = find_property(t, CHILDREN);
if (child) {