From ba89419ac9074d930eec7ba72c378831c56ed060 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Thu, 29 Dec 2016 14:58:42 +1030 Subject: [PATCH] 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: Rusty Russell --- ccan/tal/tal.c | 28 +++++++++++++++------------- ccan/tal/tal.h | 4 +++- ccan/tal/test/run-free.c | 5 ++++- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/ccan/tal/tal.c b/ccan/tal/tal.c index 842059d0..866f263b 100644 --- a/ccan/tal/tal.c +++ b/ccan/tal/tal.c @@ -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; } diff --git a/ccan/tal/tal.h b/ccan/tal/tal.h index 713db118..af3943ee 100644 --- a/ccan/tal/tal.h +++ b/ccan/tal/tal.h @@ -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. diff --git a/ccan/tal/test/run-free.c b/ccan/tal/test/run-free.c index f2126474..37d03cd6 100644 --- a/ccan/tal/test/run-free.c +++ b/ccan/tal/test/run-free.c @@ -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; -- 2.39.2