Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
ccan
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
mirror
ccan
Commits
4e5111fb
Commit
4e5111fb
authored
Jul 18, 2009
by
Rusty Russell
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
talloc_link; a replacement for talloc's references.
parent
f8f43498
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
404 additions
and
0 deletions
+404
-0
ccan/talloc_link/_info
ccan/talloc_link/_info
+146
-0
ccan/talloc_link/talloc_link.c
ccan/talloc_link/talloc_link.c
+95
-0
ccan/talloc_link/talloc_link.h
ccan/talloc_link/talloc_link.h
+47
-0
ccan/talloc_link/test/run.c
ccan/talloc_link/test/run.c
+116
-0
No files found.
ccan/talloc_link/_info
0 → 100644
View file @
4e5111fb
#include <stdio.h>
#include <string.h>
#include "config.h"
/**
* talloc_link - link helper for talloc
*
* Talloc references can be confusing and buggy. In the cases where an object
* needs multiple parents, all parents need to be aware of the situation; thus
* talloc_link is a helper where all "parents" talloc_link an object they
* agree to share ownership of.
*
* Example:
* // Silly program which keeps a cache of uppercased strings.
* // The cache wants to keep strings around even after they may have
* // been "freed" by the caller.
* #include <stdio.h>
* #include <err.h>
* #include <string.h>
* #include <ctype.h>
* #include <ccan/talloc/talloc.h>
* #include <ccan/talloc_link/talloc_link.h>
*
* struct upcache {
* const char *str;
* const char *upstr;
* };
*
* static struct upcache *cache;
* static unsigned int cache_hits = 0;
* #define CACHE_SIZE 4
* void init_upcase(void)
* {
* cache = talloc_zero_array(NULL, struct upcache, CACHE_SIZE);
* }
*
* static struct upcache *lookup_upcase(const char *str)
* {
* unsigned int i;
* for (i = 0; i < CACHE_SIZE; i++)
* if (cache[i].str && !strcmp(cache[i].str, str)) {
* cache_hits++;
* return &cache[i];
* }
* return NULL;
* }
*
* static struct upcache *new_upcase(const char *str)
* {
* unsigned int i;
* char *upstr;
*
* upstr = talloc_linked(cache, talloc_strdup(NULL, str));
* if (!upstr)
* return NULL;
*
* i = random() % CACHE_SIZE;
*
* // Throw out old: works fine if cache[i].upstr is NULL.
* talloc_delink(cache, cache[i].upstr);
*
* // Replace with new.
* cache[i].str = str;
* cache[i].upstr = upstr;
* while (*upstr) {
* *upstr = toupper(*upstr);
* upstr++;
* }
* return &cache[i];
* }
*
* // If you want to keep the result, talloc_link it.
* const char *get_upcase(const char *str)
* {
* struct upcache *uc = lookup_upcase(str);
* if (!uc)
* uc = new_upcase(str);
* if (!uc)
* return NULL;
* return uc->upstr;
* }
*
* void exit_upcase(void)
* {
* talloc_free(cache);
* printf("Cache hits: %u\n", cache_hits);
* }
*
* int main(int argc, char *argv[])
* {
* unsigned int i;
* const char **values;
*
* // Will dump any memory leaks to stderr on exit.
* talloc_enable_leak_report();
*
* // Initialize cache.
* init_upcase();
*
* // Throw values in.
* values = talloc_array(NULL, const char *, argc);
* for (i = 1; i < argc; i++) {
* values[i-1] = talloc_link(values, get_upcase(argv[i]));
* if (!values[i-1])
* err(1, "Out of memory");
* }
* // This will free all the values, but cache will still work.
* talloc_free(values);
*
* // Repeat!
* values = talloc_array(NULL, const char *, argc);
* for (i = 1; i < argc; i++) {
* values[i-1] = talloc_link(values, get_upcase(argv[i]));
* if (!values[i-1])
* err(1, "Out of memory");
* }
*
* // This will remove cache links, but we still have a link.
* exit_upcase();
*
* // Show values, so we output something.
* for (i = 0; i < argc - 1; i++)
* printf("%s ", values[i]);
* printf("\n");
*
* // This will finally free the upcase strings (last link).
* talloc_free(values);
*
* return 0;
* }
*
* Licence: GPL (2 or any later version)
*/
int main(int argc, char *argv[])
{
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0) {
printf("ccan/talloc\n");
printf("ccan/list\n");
return 0;
}
return 1;
}
ccan/talloc_link/talloc_link.c
0 → 100644
View file @
4e5111fb
#include <ccan/list/list.h>
#include <ccan/talloc/talloc.h>
#include <ccan/talloc_link/talloc_link.h>
#include <assert.h>
/* Fake parent, if they care. */
static
void
*
talloc_links
=
NULL
;
/* This is the parent of the linked object, so we can implement delink. */
struct
talloc_linked
{
struct
list_head
links
;
const
void
*
obj
;
};
/* This is a child of the linker, but not a parent of ref. */
struct
talloc_link
{
struct
list_node
list
;
struct
talloc_linked
*
linked
;
};
static
int
destroy_link
(
struct
talloc_link
*
link
)
{
list_del
(
&
link
->
list
);
if
(
list_empty
(
&
link
->
linked
->
links
))
talloc_free
(
link
->
linked
);
return
0
;
}
static
bool
add_link
(
const
void
*
ctx
,
struct
talloc_linked
*
linked
)
{
struct
talloc_link
*
link
=
talloc
(
ctx
,
struct
talloc_link
);
if
(
!
link
)
return
false
;
link
->
linked
=
linked
;
list_add
(
&
linked
->
links
,
&
link
->
list
);
talloc_set_destructor
(
link
,
destroy_link
);
return
true
;
}
void
*
_talloc_linked
(
const
void
*
ctx
,
const
void
*
newobj
)
{
struct
talloc_linked
*
linked
;
if
(
talloc_parent
(
newobj
))
{
/* Assume leak reporting is on: create dummy parent. */
if
(
!
talloc_links
)
talloc_links
=
talloc_named_const
(
NULL
,
0
,
"talloc_links"
);
/* This should now have same pseudo-NULL parent. */
assert
(
talloc_parent
(
newobj
)
==
talloc_parent
(
talloc_links
));
}
linked
=
talloc
(
talloc_links
,
struct
talloc_linked
);
if
(
!
linked
)
{
talloc_free
(
newobj
);
return
NULL
;
}
list_head_init
(
&
linked
->
links
);
linked
->
obj
=
talloc_steal
(
linked
,
newobj
);
if
(
!
add_link
(
ctx
,
linked
))
{
talloc_free
(
linked
);
return
NULL
;
}
return
(
void
*
)
newobj
;
}
void
*
_talloc_link
(
const
void
*
ctx
,
const
void
*
obj
)
{
struct
talloc_linked
*
linked
;
linked
=
talloc_get_type
(
talloc_parent
(
obj
),
struct
talloc_linked
);
assert
(
!
list_empty
(
&
linked
->
links
));
return
add_link
(
ctx
,
linked
)
?
(
void
*
)
obj
:
NULL
;
}
void
talloc_delink
(
const
void
*
ctx
,
const
void
*
obj
)
{
struct
talloc_linked
*
linked
;
struct
talloc_link
*
i
;
if
(
!
obj
)
return
;
linked
=
talloc_get_type
(
talloc_parent
(
obj
),
struct
talloc_linked
);
list_for_each
(
&
linked
->
links
,
i
,
list
)
{
if
(
talloc_is_parent
(
i
,
ctx
))
{
talloc_free
(
i
);
return
;
}
}
abort
();
}
ccan/talloc_link/talloc_link.h
0 → 100644
View file @
4e5111fb
#ifndef TALLOC_LINK_H
#define TALLOC_LINK_H
#include <ccan/talloc/talloc.h>
/**
* talloc_linked - set up an object with an initial link.
* @ctx - the context to initially link to
* @newobj - the newly allocated object (with a NULL parent)
*
* The object will be freed when @ctx is freed (or talloc_delink(ctx,
* newobj) is called), unless more links are added using
* talloc_link().
*
* For convenient chaining, it returns @newobj on success, or frees
* @newobj and returns NULL.
*/
#define talloc_linked(ctx, newobj) \
((_TALLOC_TYPEOF(newobj))_talloc_linked((ctx), (newobj)))
/**
* talloc_link - add another link to a linkable object.
* @ctx - the context to link to
* @obj - the object previously made linkable with talloc_linked().
*
* The @obj will only be freed when all contexts linked to it are
* freed (or talloc_delink()ed).
*
* Returns @obj, or NULL on failure (out of memory).
*/
#define talloc_link(ctx, obj) \
((_TALLOC_TYPEOF(obj))_talloc_link((ctx), (obj)))
/**
* talloc_delink - explicitly remove a link from a linkable object.
* @ctx - the context previously used for talloc_link/talloc_linked
* @obj - the object previously used for talloc_link/talloc_linked
*
* Explicitly remove a link: normally it is implied by freeing @ctx.
* Removing the last link frees the object.
*/
void
talloc_delink
(
const
void
*
ctx
,
const
void
*
linked
);
/* Internal helpers. */
void
*
_talloc_link
(
const
void
*
ctx
,
const
void
*
linked
);
void
*
_talloc_linked
(
const
void
*
ctx
,
const
void
*
linked
);
#endif
/* TALLOC_LINK_H */
ccan/talloc_link/test/run.c
0 → 100644
View file @
4e5111fb
#include "talloc_link/talloc_link.h"
#include "tap/tap.h"
#include "talloc_link/talloc_link.c"
#include <stdlib.h>
#include <err.h>
static
unsigned
int
destroy_count
=
0
;
static
int
destroy_obj
(
void
*
obj
)
{
destroy_count
++
;
return
0
;
}
int
main
(
int
argc
,
char
*
argv
[])
{
void
*
obj
,
*
p1
,
*
p2
,
*
p3
;
plan_tests
(
16
);
talloc_enable_leak_report
();
/* Single parent case. */
p1
=
talloc
(
NULL
,
char
);
obj
=
talloc_linked
(
p1
,
talloc
(
NULL
,
char
));
talloc_set_destructor
(
obj
,
destroy_obj
);
ok
(
destroy_count
==
0
,
"destroy_count = %u"
,
destroy_count
);
talloc_free
(
p1
);
ok
(
destroy_count
==
1
,
"destroy_count = %u"
,
destroy_count
);
/* Dual parent case. */
p1
=
talloc
(
NULL
,
char
);
obj
=
talloc_linked
(
p1
,
talloc
(
NULL
,
char
));
talloc_set_destructor
(
obj
,
destroy_obj
);
p2
=
talloc
(
NULL
,
char
);
talloc_link
(
p2
,
obj
);
talloc_free
(
p1
);
ok
(
destroy_count
==
1
,
"destroy_count = %u"
,
destroy_count
);
talloc_free
(
p2
);
ok
(
destroy_count
==
2
,
"destroy_count = %u"
,
destroy_count
);
/* Triple parent case. */
p1
=
talloc
(
NULL
,
char
);
obj
=
talloc_linked
(
p1
,
talloc
(
NULL
,
char
));
talloc_set_destructor
(
obj
,
destroy_obj
);
p2
=
talloc
(
NULL
,
char
);
p3
=
talloc
(
NULL
,
char
);
talloc_link
(
p2
,
obj
);
talloc_link
(
p3
,
obj
);
talloc_free
(
p1
);
ok
(
destroy_count
==
2
,
"destroy_count = %u"
,
destroy_count
);
talloc_free
(
p2
);
ok
(
destroy_count
==
2
,
"destroy_count = %u"
,
destroy_count
);
talloc_free
(
p3
);
ok
(
destroy_count
==
3
,
"destroy_count = %u"
,
destroy_count
);
/* Single delink case. */
p1
=
talloc
(
NULL
,
char
);
obj
=
talloc_linked
(
p1
,
talloc
(
NULL
,
char
));
talloc_set_destructor
(
obj
,
destroy_obj
);
ok
(
destroy_count
==
3
,
"destroy_count = %u"
,
destroy_count
);
talloc_delink
(
p1
,
obj
);
ok
(
destroy_count
==
4
,
"destroy_count = %u"
,
destroy_count
);
talloc_free
(
p1
);
/* Double delink case. */
p1
=
talloc
(
NULL
,
char
);
obj
=
talloc_linked
(
p1
,
talloc
(
NULL
,
char
));
talloc_set_destructor
(
obj
,
destroy_obj
);
p2
=
talloc
(
NULL
,
char
);
talloc_link
(
p2
,
obj
);
talloc_delink
(
p1
,
obj
);
ok
(
destroy_count
==
4
,
"destroy_count = %u"
,
destroy_count
);
talloc_delink
(
p2
,
obj
);
ok
(
destroy_count
==
5
,
"destroy_count = %u"
,
destroy_count
);
talloc_free
(
p1
);
talloc_free
(
p2
);
/* Delink and free. */
p1
=
talloc
(
NULL
,
char
);
obj
=
talloc_linked
(
p1
,
talloc
(
NULL
,
char
));
talloc_set_destructor
(
obj
,
destroy_obj
);
p2
=
talloc
(
NULL
,
char
);
talloc_link
(
p2
,
obj
);
talloc_delink
(
p1
,
obj
);
ok
(
destroy_count
==
5
,
"destroy_count = %u"
,
destroy_count
);
talloc_free
(
p2
);
ok
(
destroy_count
==
6
,
"destroy_count = %u"
,
destroy_count
);
talloc_free
(
p1
);
/* Free and delink. */
p1
=
talloc
(
NULL
,
char
);
obj
=
talloc_linked
(
p1
,
talloc
(
NULL
,
char
));
talloc_set_destructor
(
obj
,
destroy_obj
);
p2
=
talloc
(
NULL
,
char
);
talloc_link
(
p2
,
obj
);
talloc_free
(
p1
);
ok
(
destroy_count
==
6
,
"destroy_count = %u"
,
destroy_count
);
talloc_delink
(
p2
,
obj
);
ok
(
destroy_count
==
7
,
"destroy_count = %u"
,
destroy_count
);
talloc_free
(
p2
);
/* No leaks? */
ok1
(
talloc_total_size
(
NULL
)
==
0
);
return
exit_status
();
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment