Commit ba89419a authored by Rusty Russell's avatar Rusty Russell

tal: save and restore errno across all notifiers.

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: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 0fe2d094
......@@ -203,7 +203,8 @@ static struct tal_hdr *debug_tal(struct tal_hdr *tal)
#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;
......@@ -216,6 +217,7 @@ static void notify(const struct tal_hdr *ctx,
continue;
n = (struct notifier *)p;
if (n->types & type) {
errno = saved_errno;
if (n->types & NOTIFY_IS_DESTRUCTOR)
n->u.destroy(from_tal_hdr(ctx));
else
......@@ -348,7 +350,7 @@ static bool add_child(struct tal_hdr *parent, struct tal_hdr *child)
return true;
}
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;
......@@ -359,7 +361,7 @@ static void del_tree(struct tal_hdr *t, const tal_t *orig)
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);
......@@ -369,7 +371,7 @@ static void del_tree(struct tal_hdr *t, const tal_t *orig)
while ((i = list_top(&c->children, struct tal_hdr, list))) {
list_del(&i->list);
del_tree(i, orig);
del_tree(i, orig, saved_errno);
}
}
......@@ -426,7 +428,7 @@ void *tal_alloc_(const tal_t *ctx, size_t size,
}
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));
}
......@@ -466,9 +468,9 @@ void *tal_free(const tal_t *ctx)
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);
list_del(&t->list);
del_tree(t, ctx);
del_tree(t, ctx, saved_errno);
errno = saved_errno;
}
return NULL;
......@@ -495,7 +497,7 @@ void *tal_steal_(const tal_t *new_parent, const tal_t *ctx)
}
debug_tal(newpar);
if (notifiers)
notify(t, TAL_NOTIFY_STEAL, new_parent);
notify(t, TAL_NOTIFY_STEAL, new_parent, 0);
}
return (void *)ctx;
}
......@@ -526,7 +528,7 @@ bool tal_add_notifier_(const tal_t *ctx, enum tal_notify_type types,
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)
......@@ -542,7 +544,7 @@ bool tal_del_notifier_(const tal_t *ctx,
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;
......@@ -582,7 +584,7 @@ bool tal_set_name_(tal_t *ctx, const char *name, bool literal)
debug_tal(t);
if (notifiers)
notify(t, TAL_NOTIFY_RENAME, name);
notify(t, TAL_NOTIFY_RENAME, name, 0);
return true;
}
......@@ -720,10 +722,10 @@ bool tal_resize_(tal_t **ctxp, size_t size, size_t count, bool clear)
}
*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);
}
if (notifiers)
notify(t, TAL_NOTIFY_RESIZE, (void *)size);
notify(t, TAL_NOTIFY_RESIZE, (void *)size, 0);
return true;
}
......
......@@ -56,7 +56,8 @@ typedef void tal_t;
* 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);
......@@ -194,6 +195,7 @@ enum tal_notify_type {
* 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.
......
......@@ -4,6 +4,8 @@
static void destroy_errno(char *p UNNEEDED)
{
/* Errno restored for all the destructors. */
ok1(errno == EINVAL);
errno = ENOENT;
}
......@@ -11,10 +13,11 @@ int main(void)
{
char *p;
plan_tests(2);
plan_tests(5);
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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment