[ccan] [RFC] tal_stack

Delio Brignoli brignoli.delio at gmail.com
Sun Mar 15 23:59:44 AEDT 2015


Hi All,

tal_stack implements a (trivial) stack of tal contexts. Would this be a worthy addition to CCAN? (not necessarily in its current form).

---
 ccan/tal/tal_stack.c      | 24 +++++++++++++++++++++++
 ccan/tal/tal_stack.h      | 50 +++++++++++++++++++++++++++++++++++++++++++++++
 ccan/tal/test/run-stack.c | 37 +++++++++++++++++++++++++++++++++++
 3 files changed, 111 insertions(+)
 create mode 100644 ccan/tal/tal_stack.c
 create mode 100644 ccan/tal/tal_stack.h
 create mode 100644 ccan/tal/test/run-stack.c

diff --git a/ccan/tal/tal_stack.c b/ccan/tal/tal_stack.c
new file mode 100644
index 0000000..95e24b0
--- /dev/null
+++ b/ccan/tal/tal_stack.c
@@ -0,0 +1,24 @@
+/* Licensed under BSD-MIT - see LICENSE file for details */
+
+#include <ccan/tal/tal_stack.h>
+#include <assert.h>
+
+static tal_t *h = NULL;
+
+static void _free_frame(tal_t *o)
+{
+	h = tal_parent(o);
+}
+
+tal_t *tal_newframe(void)
+{
+	h = tal_alloc_(h, 0, false, NULL);
+	assert(h != NULL);
+	tal_add_destructor(h, _free_frame);
+	return h;
+}
+
+tal_t *tal_curframe(void)
+{
+	return h;
+}
diff --git a/ccan/tal/tal_stack.h b/ccan/tal/tal_stack.h
new file mode 100644
index 0000000..7ea11e5
--- /dev/null
+++ b/ccan/tal/tal_stack.h
@@ -0,0 +1,50 @@
+/* Licensed under BSD-MIT - see LICENSE file for details */
+#ifndef CCAN_TAL_STACK_H
+#define CCAN_TAL_STACK_H
+/*
+
+Implement a stack of tal contexts. A new (empty) context is pushed on top
+of the stack using tal_newframe and it is popped/freed using tal_free().
+tal_curframe() can be used to get the stack's top context.
+
+tal_stack can be used to implement per-function temporary allocation context
+to help avoiding memory leaks, but unlike the plain tal approach it does not
+require the caller to pass a destination context for returning allocated
+values. Instead, allocated values are moved to the parent context using
+tal_steal(tal_parent(tmp_ctx), ptr).
+
+int funcname(int **out)
+{
+	int retval = 0;
+	tal_t *tmp_ctx = tal_newframe();
+
+	int *val = talz(tmp_ctx, int);
+	assert(val != NULL)
+
+	int cnt = libc_call(...);
+	if (cnt < 0) {
+		retval = -errno;
+		goto done;
+	}
+
+	... do something with val ...
+
+done:
+	if (retval >= 0) {
+		tal_steal(tal_parent(tmp_ctx), val);
+		if (*out)
+			*out = val;
+	} else {
+		... undo side-effects ...
+	}
+	tal_free(tmp_ctx);
+	return retval;
+}
+
+*/
+
+#include <ccan/tal/tal.h>
+
+tal_t *tal_newframe(void);
+tal_t *tal_curframe(void);
+#endif /* CCAN_TAL_STACK_H */
diff --git a/ccan/tal/test/run-stack.c b/ccan/tal/test/run-stack.c
new file mode 100644
index 0000000..cd6054d
--- /dev/null
+++ b/ccan/tal/test/run-stack.c
@@ -0,0 +1,37 @@
+#include <ccan/tal/tal.h>
+#include <ccan/tal/tal.c>
+#include <ccan/tal/tal_stack.h>
+#include <ccan/tal/tal_stack.c>
+#include <ccan/tap/tap.h>
+
+int main(void)
+{
+	tal_t *parent, *cur;
+
+	plan_tests(8);
+
+	/* initial frame is NULL */
+	ok1(tal_curframe() == NULL);
+
+	/* create new frame and make sure all is OK */
+	cur = tal_newframe();
+	ok1(tal_curframe() == cur);
+	ok1(tal_parent(cur) == NULL);
+
+	/* create another frame */
+	parent = cur;
+	cur = tal_newframe();
+	ok1(tal_curframe() == cur);
+	ok1(tal_parent(cur) == parent);
+
+	/* unwind */
+	tal_free(cur);
+	ok1(tal_curframe() == parent);
+	cur = tal_curframe();
+	ok1(tal_parent(cur) == NULL);
+	tal_free(cur);
+	ok1(tal_curframe() == NULL);
+
+	tal_cleanup();
+	return exit_status();
+}
-- 
1.9.3 (Apple Git-50)



More information about the ccan mailing list