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