tal: save and restore errno across all notifiers.
authorRusty Russell <rusty@rustcorp.com.au>
Thu, 29 Dec 2016 04:28:42 +0000 (14:58 +1030)
committerRusty Russell <rusty@rustcorp.com.au>
Thu, 29 Dec 2016 23:12:44 +0000 (09:42 +1030)
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>
ccan/tal/tal.c
ccan/tal/tal.h
ccan/tal/test/run-free.c

index 842059d031b76977d665b31f1aedd3259a86ff0f..866f263ba871f7e2ca4cb430bc9a790f1637b941 100644 (file)
@@ -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;
 }
index 713db118819c4d7ce128bab723d62f924566ca8c..af3943eebafec9b593e15a8fe5c951cc138a2481 100644 (file)
@@ -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.
index f21264748d40a056a7e1ae5ed1d0976190d86e5a..37d03cd6ff4cbd0233950f0808129e939f9975e1 100644 (file)
@@ -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;