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) ...@@ -203,7 +203,8 @@ static struct tal_hdr *debug_tal(struct tal_hdr *tal)
#endif #endif
static void notify(const struct tal_hdr *ctx, 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;
...@@ -216,6 +217,7 @@ static void notify(const struct tal_hdr *ctx, ...@@ -216,6 +217,7 @@ static void notify(const struct tal_hdr *ctx,
continue; continue;
n = (struct notifier *)p; n = (struct notifier *)p;
if (n->types & type) { if (n->types & type) {
errno = saved_errno;
if (n->types & NOTIFY_IS_DESTRUCTOR) if (n->types & NOTIFY_IS_DESTRUCTOR)
n->u.destroy(from_tal_hdr(ctx)); n->u.destroy(from_tal_hdr(ctx));
else else
...@@ -348,7 +350,7 @@ static bool add_child(struct tal_hdr *parent, struct tal_hdr *child) ...@@ -348,7 +350,7 @@ static bool add_child(struct tal_hdr *parent, struct tal_hdr *child)
return true; 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; struct prop_hdr **prop, *p, *next;
...@@ -359,7 +361,7 @@ static void del_tree(struct tal_hdr *t, const tal_t *orig) ...@@ -359,7 +361,7 @@ static void del_tree(struct tal_hdr *t, const tal_t *orig)
set_destroying_bit(&t->parent_child); set_destroying_bit(&t->parent_child);
/* Call free notifiers. */ /* 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. */ /* Now free children and groups. */
prop = find_property_ptr(t, CHILDREN); prop = find_property_ptr(t, CHILDREN);
...@@ -369,7 +371,7 @@ static void del_tree(struct tal_hdr *t, const tal_t *orig) ...@@ -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))) { while ((i = list_top(&c->children, struct tal_hdr, list))) {
list_del(&i->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, ...@@ -426,7 +428,7 @@ void *tal_alloc_(const tal_t *ctx, size_t size,
} }
debug_tal(parent); debug_tal(parent);
if (notifiers) 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));
} }
...@@ -466,9 +468,9 @@ void *tal_free(const tal_t *ctx) ...@@ -466,9 +468,9 @@ void *tal_free(const tal_t *ctx)
t = debug_tal(to_tal_hdr(ctx)); t = debug_tal(to_tal_hdr(ctx));
if (notifiers) if (notifiers)
notify(ignore_destroying_bit(t->parent_child)->parent, notify(ignore_destroying_bit(t->parent_child)->parent,
TAL_NOTIFY_DEL_CHILD, ctx); TAL_NOTIFY_DEL_CHILD, ctx, saved_errno);
list_del(&t->list); list_del(&t->list);
del_tree(t, ctx); del_tree(t, ctx, saved_errno);
errno = saved_errno; errno = saved_errno;
} }
return NULL; return NULL;
...@@ -495,7 +497,7 @@ void *tal_steal_(const tal_t *new_parent, const tal_t *ctx) ...@@ -495,7 +497,7 @@ void *tal_steal_(const tal_t *new_parent, const tal_t *ctx)
} }
debug_tal(newpar); debug_tal(newpar);
if (notifiers) if (notifiers)
notify(t, TAL_NOTIFY_STEAL, new_parent); notify(t, TAL_NOTIFY_STEAL, new_parent, 0);
} }
return (void *)ctx; return (void *)ctx;
} }
...@@ -526,7 +528,7 @@ bool tal_add_notifier_(const tal_t *ctx, enum tal_notify_type types, ...@@ -526,7 +528,7 @@ bool tal_add_notifier_(const tal_t *ctx, enum tal_notify_type types,
return false; return false;
if (notifiers) if (notifiers)
notify(t, TAL_NOTIFY_ADD_NOTIFIER, callback); notify(t, TAL_NOTIFY_ADD_NOTIFIER, callback, 0);
n->types = types; n->types = types;
if (types != TAL_NOTIFY_FREE) if (types != TAL_NOTIFY_FREE)
...@@ -542,7 +544,7 @@ bool tal_del_notifier_(const tal_t *ctx, ...@@ -542,7 +544,7 @@ bool tal_del_notifier_(const tal_t *ctx,
types = del_notifier_property(t, callback); types = del_notifier_property(t, callback);
if (types) { if (types) {
notify(t, TAL_NOTIFY_DEL_NOTIFIER, callback); notify(t, TAL_NOTIFY_DEL_NOTIFIER, callback, 0);
if (types != TAL_NOTIFY_FREE) if (types != TAL_NOTIFY_FREE)
notifiers--; notifiers--;
return true; return true;
...@@ -582,7 +584,7 @@ bool tal_set_name_(tal_t *ctx, const char *name, bool literal) ...@@ -582,7 +584,7 @@ bool tal_set_name_(tal_t *ctx, const char *name, bool literal)
debug_tal(t); debug_tal(t);
if (notifiers) if (notifiers)
notify(t, TAL_NOTIFY_RENAME, name); notify(t, TAL_NOTIFY_RENAME, name, 0);
return true; return true;
} }
...@@ -720,10 +722,10 @@ bool tal_resize_(tal_t **ctxp, size_t size, size_t count, bool clear) ...@@ -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)); *ctxp = from_tal_hdr(debug_tal(t));
if (notifiers) 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) if (notifiers)
notify(t, TAL_NOTIFY_RESIZE, (void *)size); notify(t, TAL_NOTIFY_RESIZE, (void *)size, 0);
return true; return true;
} }
......
...@@ -56,7 +56,8 @@ typedef void tal_t; ...@@ -56,7 +56,8 @@ typedef void tal_t;
* children (recursively) before finally freeing the memory. It returns * children (recursively) before finally freeing the memory. It returns
* NULL, for convenience. * 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: * Example:
* p = tal_free(p); * p = tal_free(p);
...@@ -194,6 +195,7 @@ enum tal_notify_type { ...@@ -194,6 +195,7 @@ enum tal_notify_type {
* TAL_NOTIFY_FREE is called when @ptr is freed, either directly or * TAL_NOTIFY_FREE is called when @ptr is freed, either directly or
* because an ancestor is freed: @info is the argument to tal_free(). * because an ancestor is freed: @info is the argument to tal_free().
* It is exactly equivalent to a destructor, with more information. * 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 * TAL_NOTIFY_STEAL is called when @ptr's parent changes: @info is the
* new parent. * new parent.
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
static void destroy_errno(char *p UNNEEDED) static void destroy_errno(char *p UNNEEDED)
{ {
/* Errno restored for all the destructors. */
ok1(errno == EINVAL);
errno = ENOENT; errno = ENOENT;
} }
...@@ -11,10 +13,11 @@ int main(void) ...@@ -11,10 +13,11 @@ int main(void)
{ {
char *p; char *p;
plan_tests(2); plan_tests(5);
p = tal(NULL, char); p = tal(NULL, char);
ok1(tal_add_destructor(p, destroy_errno)); ok1(tal_add_destructor(p, destroy_errno));
ok1(tal_add_destructor(p, destroy_errno));
/* Errno save/restored across free. */ /* Errno save/restored across free. */
errno = EINVAL; 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