1 /* Licensed under BSD-MIT - see LICENSE file for details */
2 #include <ccan/tal/link/link.h>
3 #include <ccan/container_of/container_of.h>
4 #include <ccan/list/list.h>
7 /* Our linkable parent. */
9 struct list_head links;
13 struct list_node list;
16 static void linkable_notifier(tal_t *linkable,
17 enum tal_notify_type type,
20 struct linkable *l = tal_parent(linkable);
21 assert(type == TAL_NOTIFY_STEAL || type == TAL_NOTIFY_FREE);
23 /* We let you free it if you haven't linked it yet. */
24 if (type == TAL_NOTIFY_FREE && list_empty(&l->links)) {
29 /* Don't try to steal or free this: it has multiple links! */
33 void *tal_linkable_(tal_t *newobj)
37 /* Must be a fresh object. */
38 assert(!tal_parent(newobj));
40 l = tal(NULL, struct linkable);
43 list_head_init(&l->links);
45 if (!tal_steal(l, newobj))
48 if (!tal_add_notifier(newobj, TAL_NOTIFY_STEAL|TAL_NOTIFY_FREE,
50 tal_steal(NULL, newobj);
54 return (void *)newobj;
61 static void destroy_link(struct link *lnk)
65 /* Only true if we're first in list! */
66 l = container_of(lnk->list.prev, struct linkable, links.n);
70 if (list_empty(&l->links))
74 void *tal_link_(const tal_t *ctx, const tal_t *link)
76 struct linkable *l = tal_parent(link);
77 struct link *lnk = tal(ctx, struct link);
81 if (!tal_add_destructor(lnk, destroy_link)) {
85 list_add(&l->links, &lnk->list);
89 void tal_delink_(const tal_t *ctx, const tal_t *link)
91 struct linkable *l = tal_parent(link);
97 /* FIXME: slow, but hopefully unusual. */
98 list_for_each(&l->links, i, list) {
99 if (tal_parent(i) == ctx) {