Browse Source

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 <rusty@rustcorp.com.au>
Rusty Russell 9 years ago
parent
commit
ba89419ac9
3 changed files with 22 additions and 15 deletions
  1. 15 13
      ccan/tal/tal.c
  2. 3 1
      ccan/tal/tal.h
  3. 4 1
      ccan/tal/test/run-free.c

+ 15 - 13
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;
 }

+ 3 - 1
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.

+ 4 - 1
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;