So the errno when you call tal_free() is handed to all the notifiers,
independent of what the others do.
This makes sense, but also helps for the upcoming ccan/io change.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
#endif
static void notify(const struct tal_hdr *ctx,
#endif
static void notify(const struct tal_hdr *ctx,
- enum tal_notify_type type, const void *info)
+ enum tal_notify_type type, const void *info,
+ int saved_errno)
{
const struct prop_hdr *p;
{
const struct prop_hdr *p;
continue;
n = (struct notifier *)p;
if (n->types & type) {
continue;
n = (struct notifier *)p;
if (n->types & type) {
if (n->types & NOTIFY_IS_DESTRUCTOR)
n->u.destroy(from_tal_hdr(ctx));
else
if (n->types & NOTIFY_IS_DESTRUCTOR)
n->u.destroy(from_tal_hdr(ctx));
else
-static void del_tree(struct tal_hdr *t, const tal_t *orig)
+static void del_tree(struct tal_hdr *t, const tal_t *orig, int saved_errno)
{
struct prop_hdr **prop, *p, *next;
{
struct prop_hdr **prop, *p, *next;
set_destroying_bit(&t->parent_child);
/* Call free notifiers. */
set_destroying_bit(&t->parent_child);
/* Call free notifiers. */
- notify(t, TAL_NOTIFY_FREE, (tal_t *)orig);
+ notify(t, TAL_NOTIFY_FREE, (tal_t *)orig, saved_errno);
/* Now free children and groups. */
prop = find_property_ptr(t, CHILDREN);
/* Now free children and groups. */
prop = find_property_ptr(t, CHILDREN);
while ((i = list_top(&c->children, struct tal_hdr, list))) {
list_del(&i->list);
while ((i = list_top(&c->children, struct tal_hdr, list))) {
list_del(&i->list);
+ del_tree(i, orig, saved_errno);
}
debug_tal(parent);
if (notifiers)
}
debug_tal(parent);
if (notifiers)
- notify(parent, TAL_NOTIFY_ADD_CHILD, from_tal_hdr(child));
+ notify(parent, TAL_NOTIFY_ADD_CHILD, from_tal_hdr(child), 0);
return from_tal_hdr(debug_tal(child));
}
return from_tal_hdr(debug_tal(child));
}
t = debug_tal(to_tal_hdr(ctx));
if (notifiers)
notify(ignore_destroying_bit(t->parent_child)->parent,
t = debug_tal(to_tal_hdr(ctx));
if (notifiers)
notify(ignore_destroying_bit(t->parent_child)->parent,
- TAL_NOTIFY_DEL_CHILD, ctx);
+ TAL_NOTIFY_DEL_CHILD, ctx, saved_errno);
+ del_tree(t, ctx, saved_errno);
errno = saved_errno;
}
return NULL;
errno = saved_errno;
}
return NULL;
}
debug_tal(newpar);
if (notifiers)
}
debug_tal(newpar);
if (notifiers)
- notify(t, TAL_NOTIFY_STEAL, new_parent);
+ notify(t, TAL_NOTIFY_STEAL, new_parent, 0);
return false;
if (notifiers)
return false;
if (notifiers)
- notify(t, TAL_NOTIFY_ADD_NOTIFIER, callback);
+ notify(t, TAL_NOTIFY_ADD_NOTIFIER, callback, 0);
n->types = types;
if (types != TAL_NOTIFY_FREE)
n->types = types;
if (types != TAL_NOTIFY_FREE)
types = del_notifier_property(t, callback);
if (types) {
types = del_notifier_property(t, callback);
if (types) {
- notify(t, TAL_NOTIFY_DEL_NOTIFIER, callback);
+ notify(t, TAL_NOTIFY_DEL_NOTIFIER, callback, 0);
if (types != TAL_NOTIFY_FREE)
notifiers--;
return true;
if (types != TAL_NOTIFY_FREE)
notifiers--;
return true;
debug_tal(t);
if (notifiers)
debug_tal(t);
if (notifiers)
- notify(t, TAL_NOTIFY_RENAME, name);
+ notify(t, TAL_NOTIFY_RENAME, name, 0);
}
*ctxp = from_tal_hdr(debug_tal(t));
if (notifiers)
}
*ctxp = from_tal_hdr(debug_tal(t));
if (notifiers)
- notify(t, TAL_NOTIFY_MOVE, from_tal_hdr(old_t));
+ notify(t, TAL_NOTIFY_MOVE, from_tal_hdr(old_t), 0);
- notify(t, TAL_NOTIFY_RESIZE, (void *)size);
+ notify(t, TAL_NOTIFY_RESIZE, (void *)size, 0);
* children (recursively) before finally freeing the memory. It returns
* NULL, for convenience.
*
* children (recursively) before finally freeing the memory. It returns
* NULL, for convenience.
*
- * Note: errno is preserved by this call.
+ * Note: errno is preserved by this call, and also saved and restored
+ * for any destructors or notifiers.
*
* Example:
* p = tal_free(p);
*
* Example:
* p = tal_free(p);
* TAL_NOTIFY_FREE is called when @ptr is freed, either directly or
* because an ancestor is freed: @info is the argument to tal_free().
* It is exactly equivalent to a destructor, with more information.
* TAL_NOTIFY_FREE is called when @ptr is freed, either directly or
* because an ancestor is freed: @info is the argument to tal_free().
* It is exactly equivalent to a destructor, with more information.
+ * errno is set to the value it was at the call of tal_free().
*
* TAL_NOTIFY_STEAL is called when @ptr's parent changes: @info is the
* new parent.
*
* TAL_NOTIFY_STEAL is called when @ptr's parent changes: @info is the
* new parent.
static void destroy_errno(char *p UNNEEDED)
{
static void destroy_errno(char *p UNNEEDED)
{
+ /* Errno restored for all the destructors. */
+ ok1(errno == EINVAL);
p = tal(NULL, char);
ok1(tal_add_destructor(p, destroy_errno));
p = tal(NULL, char);
ok1(tal_add_destructor(p, destroy_errno));
+ ok1(tal_add_destructor(p, destroy_errno));
/* Errno save/restored across free. */
errno = EINVAL;
/* Errno save/restored across free. */
errno = EINVAL;