]> git.ozlabs.org Git - ccan/blob - ccan/talloc_link/talloc_link.c
configurator: HAVE_SECTION_START_STOP
[ccan] / ccan / talloc_link / talloc_link.c
1 /* Licensed under GPLv2+ - see LICENSE file for details */
2 #include <ccan/list/list.h>
3 #include <ccan/talloc/talloc.h>
4 #include <ccan/talloc_link/talloc_link.h>
5 #include <assert.h>
6
7 /* Fake parent, if they care. */
8 static void *talloc_links = NULL;
9
10 /* This is the parent of the linked object, so we can implement delink. */
11 struct talloc_linked {
12         struct list_head links;
13         const void *obj;
14 };
15
16 /* This is a child of the linker, but not a parent of ref. */
17 struct talloc_link {
18         struct list_node list;
19         struct talloc_linked *linked;
20 };
21
22 static int destroy_link(struct talloc_link *link)
23 {
24         list_del(&link->list);
25         if (list_empty(&link->linked->links))
26                 talloc_free(link->linked);
27         return 0;
28 }
29
30 static bool add_link(const void *ctx, struct talloc_linked *linked)
31 {
32         struct talloc_link *link = talloc(ctx, struct talloc_link);
33         if (!link)
34                 return false;
35
36         link->linked = linked;
37         list_add(&linked->links, &link->list);
38         talloc_set_destructor(link, destroy_link);
39         return true;
40 }
41
42 void *_talloc_linked(const void *ctx, const void *newobj)
43 {
44         struct talloc_linked *linked;
45
46         if (talloc_parent(newobj)) {
47                 /* Assume leak reporting is on: create dummy parent. */
48                 if (!talloc_links)
49                         talloc_links = talloc_named_const(NULL, 0,
50                                                           "talloc_links");
51                 /* This should now have same pseudo-NULL parent. */
52                 assert(talloc_parent(newobj) == talloc_parent(talloc_links));
53         }
54
55         linked = talloc(talloc_links, struct talloc_linked);
56         if (!linked) {
57                 talloc_free(newobj);
58                 return NULL;
59         }
60         list_head_init(&linked->links);
61         linked->obj = talloc_steal(linked, newobj);
62
63         if (!add_link(ctx, linked)) {
64                 talloc_free(linked);
65                 return NULL;
66         }
67
68         return (void *)newobj;
69 }
70
71 void *_talloc_link(const void *ctx, const void *obj)
72 {
73         struct talloc_linked *linked;
74
75         linked = talloc_get_type(talloc_parent(obj), struct talloc_linked);
76         assert(!list_empty(&linked->links));
77         return add_link(ctx, linked) ? (void *)obj : NULL;
78 }
79
80 void talloc_delink(const void *ctx, const void *obj)
81 {
82         struct talloc_linked *linked;
83         struct talloc_link *i;
84
85         if (!obj)
86                 return;
87
88         linked = talloc_get_type(talloc_parent(obj), struct talloc_linked);
89         list_for_each(&linked->links, i, list) {
90                 if (talloc_is_parent(i, ctx)) {
91                         talloc_free(i);
92                         return;
93                 }
94         }
95         abort();
96 }