Commit f933b8c3 authored by Rusty Russell's avatar Rusty Russell

Seriously revisit locking required for antithread.

Remove test that never ran properly anyway (still bug in current talloc 
testsuite).
parent aec5e6e9
......@@ -83,9 +83,8 @@ static void *null_context;
static pid_t *autofree_context;
static void *(*tc_external_realloc)(const void *parent, void *ptr, size_t size);
static void (*tc_lock)(void *);
static void (*tc_unlock)(void *);
static void *tc_lock_data;
static void (*tc_lock)(const void *ctx);
static void (*tc_unlock)(void);
struct talloc_reference_handle {
struct talloc_reference_handle *next, *prev;
......@@ -150,16 +149,27 @@ do { \
if ((p) && ((p) != (list))) (p)->next = (p)->prev = NULL; \
} while (0)
static inline void lock(void)
static int locked;
static inline void lock(const void *p)
{
if (tc_lock)
tc_lock(tc_lock_data);
if (tc_lock && p) {
struct talloc_chunk *tc = talloc_chunk_from_ptr(p);
if (tc->flags & TALLOC_FLAG_EXT_ALLOC) {
if (locked)
TALLOC_ABORT("nested locking");
tc_lock(tc);
locked = 1;
}
}
}
static inline void unlock(void)
{
if (tc_lock)
tc_unlock(tc_lock_data);
if (locked) {
tc_unlock();
locked = 0;
}
}
/*
......@@ -179,14 +189,23 @@ static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr)
return tc->parent;
}
void *talloc_parent(const void *ptr)
/* This version doesn't do locking, so you must already have it. */
static void *talloc_parent_nolock(const void *ptr)
{
struct talloc_chunk *tc;
lock();
tc = talloc_parent_chunk(ptr);
return tc ? TC_PTR_FROM_CHUNK(tc) : NULL;
}
void *talloc_parent(const void *ptr)
{
void *parent;
lock(ptr);
parent = talloc_parent_nolock(ptr);
unlock();
return tc? TC_PTR_FROM_CHUNK(tc) : NULL;
return parent;
}
/*
......@@ -196,7 +215,7 @@ const char *talloc_parent_name(const void *ptr)
{
struct talloc_chunk *tc;
lock();
lock(ptr);
tc = talloc_parent_chunk(ptr);
unlock();
......@@ -346,7 +365,7 @@ void *_talloc_reference(const void *context, const void *ptr)
struct talloc_reference_handle *handle;
if (unlikely(ptr == NULL)) return NULL;
lock();
lock(context);
tc = talloc_chunk_from_ptr(ptr);
handle = (struct talloc_reference_handle *)_talloc_named_const(context,
sizeof(struct talloc_reference_handle),
......@@ -497,7 +516,7 @@ static inline int _talloc_free(void *ptr)
}
if (unlikely(tc->flags & TALLOC_FLAG_EXT_ALLOC))
oldparent = talloc_parent(ptr);
oldparent = talloc_parent_nolock(ptr);
if (tc->parent) {
_TLIST_REMOVE(tc->parent->child, tc);
......@@ -546,7 +565,7 @@ void *_talloc_steal(const void *new_ctx, const void *ptr)
{
void *p;
lock();
lock(new_ctx);
p = __talloc_steal(new_ctx, ptr);
unlock();
return p;
......@@ -598,7 +617,7 @@ int talloc_unlink(const void *context, void *ptr)
context = null_context;
}
lock();
lock(context);
if (talloc_unreference(context, ptr) == 0) {
unlock();
return 0;
......@@ -682,7 +701,7 @@ void *talloc_named(const void *context, size_t size, const char *fmt, ...)
void *ptr;
const char *name;
lock();
lock(context);
ptr = __talloc(context, size);
unlock();
if (unlikely(ptr == NULL)) return NULL;
......@@ -747,9 +766,7 @@ void *talloc_init(const char *fmt, ...)
*/
talloc_enable_null_tracking();
lock();
ptr = __talloc(NULL, 0);
unlock();
if (unlikely(ptr == NULL)) return NULL;
va_start(ap, fmt);
......@@ -788,7 +805,7 @@ void talloc_set_name_const(const void *ptr, const char *name)
void *talloc_named_const(const void *context, size_t size, const char *name)
{
void *p;
lock();
lock(context);
p = _talloc_named_const(context, size, name);
unlock();
return p;
......@@ -805,7 +822,8 @@ void *talloc_named_const(const void *context, size_t size, const char *name)
int talloc_free(void *ptr)
{
int saved_errno = errno, ret;
lock();
lock(ptr);
ret = _talloc_free(ptr);
unlock();
if (ret == 0)
......@@ -846,10 +864,10 @@ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *n
return NULL;
}
lock();
lock(ptr);
if (unlikely(tc->flags & TALLOC_FLAG_EXT_ALLOC)) {
/* need to get parent before setting free flag. */
void *parent = talloc_parent(ptr);
void *parent = talloc_parent_nolock(ptr);
tc->flags |= TALLOC_FLAG_FREE;
new_ptr = tc_external_realloc(parent, tc, size + TC_HDR_SIZE);
} else {
......@@ -945,7 +963,7 @@ size_t talloc_total_size(const void *ptr)
return 0;
}
lock();
lock(ptr);
total = _talloc_total_size(ptr);
unlock();
return total;
......@@ -979,26 +997,34 @@ size_t talloc_total_blocks(const void *ptr)
{
size_t total;
lock();
lock(ptr);
total = _talloc_total_blocks(ptr);
unlock();
return total;
}
/*
return the number of external references to a pointer
*/
size_t talloc_reference_count(const void *ptr)
static size_t _talloc_reference_count(const void *ptr)
{
struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr);
struct talloc_reference_handle *h;
size_t ret = 0;
lock();
for (h=tc->refs;h;h=h->next) {
ret++;
}
return ret;
}
/*
return the number of external references to a pointer
*/
size_t talloc_reference_count(const void *ptr)
{
size_t ret;
lock(talloc_chunk_from_ptr(ptr));
ret = _talloc_reference_count(ptr);
unlock();
return ret;
}
......@@ -1051,7 +1077,7 @@ void talloc_report_depth_cb(const void *ptr, int depth, int max_depth,
}
if (ptr == NULL) return;
lock();
lock(ptr);
_talloc_report_depth_cb(ptr, depth, max_depth, callback, private_data);
unlock();
}
......@@ -1069,17 +1095,17 @@ static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_
if (depth == 0) {
fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n",
(max_depth < 0 ? "full " :""), name,
(unsigned long)talloc_total_size(ptr),
(unsigned long)talloc_total_blocks(ptr));
(unsigned long)_talloc_total_size(ptr),
(unsigned long)_talloc_total_blocks(ptr));
return;
}
fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n",
depth*4, "",
name,
(unsigned long)talloc_total_size(ptr),
(unsigned long)talloc_total_blocks(ptr),
(int)talloc_reference_count(ptr), ptr);
(unsigned long)_talloc_total_size(ptr),
(unsigned long)_talloc_total_blocks(ptr),
(int)_talloc_reference_count(ptr), ptr);
#if 0
fprintf(f, "content: ");
......@@ -1149,11 +1175,9 @@ static void talloc_report_null_full(void)
*/
void talloc_enable_null_tracking(void)
{
lock();
if (null_context == NULL) {
null_context = _talloc_named_const(NULL, 0, "null_context");
}
unlock();
}
/*
......@@ -1161,10 +1185,8 @@ void talloc_enable_null_tracking(void)
*/
void talloc_disable_null_tracking(void)
{
lock();
_talloc_free(null_context);
null_context = NULL;
unlock();
}
/*
......@@ -1192,7 +1214,7 @@ void *_talloc_zero(const void *ctx, size_t size, const char *name)
{
void *p;
lock();
lock(ctx);
p = _talloc_named_const(ctx, size, name);
unlock();
......@@ -1210,7 +1232,7 @@ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name
{
void *newp;
lock();
lock(t);
newp = _talloc_named_const(t, size, name);
unlock();
......@@ -1273,7 +1295,7 @@ char *talloc_strndup(const void *t, const char *p, size_t n)
for (len=0; len<n && p[len]; len++) ;
lock();
lock(t);
ret = (char *)__talloc(t, len + 1);
unlock();
if (!ret) { return NULL; }
......@@ -1298,7 +1320,7 @@ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap)
return NULL;
}
lock();
lock(t);
ret = (char *)__talloc(t, len+1);
unlock();
if (ret) {
......@@ -1398,7 +1420,7 @@ void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char
if (count >= MAX_TALLOC_SIZE/el_size) {
return NULL;
}
lock();
lock(ctx);
p = _talloc_named_const(ctx, el_size * count, name);
unlock();
return p;
......@@ -1414,9 +1436,7 @@ void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const
if (count >= MAX_TALLOC_SIZE/el_size) {
return NULL;
}
lock();
p = _talloc_zero(ctx, el_size * count, name);
unlock();
return p;
}
......@@ -1494,7 +1514,7 @@ void *talloc_find_parent_byname(const void *context, const char *name)
return NULL;
}
lock();
lock(context);
tc = talloc_chunk_from_ptr(context);
while (tc) {
if (tc->name && strcmp(tc->name, name) == 0) {
......@@ -1522,7 +1542,7 @@ void talloc_show_parents(const void *context, FILE *file)
return;
}
lock();
lock(context);
tc = talloc_chunk_from_ptr(context);
fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));
while (tc) {
......@@ -1539,19 +1559,20 @@ void talloc_show_parents(const void *context, FILE *file)
int talloc_is_parent(const void *context, const void *ptr)
{
int ret;
lock();
lock(context);
ret = _talloc_is_parent(context, ptr);
unlock();
return ret;
}
void *talloc_add_external(const void *ctx,
void *(*realloc)(const void *, void *, size_t))
void *(*realloc)(const void *, void *, size_t),
void (*lock)(const void *p),
void (*unlock)(void))
{
struct talloc_chunk *tc, *parent;
void *p;
lock();
if (tc_external_realloc && tc_external_realloc != realloc)
TALLOC_ABORT("talloc_add_external realloc replaced");
tc_external_realloc = realloc;
......@@ -1564,14 +1585,8 @@ void *talloc_add_external(const void *ctx,
tc = tc_external_realloc(ctx, NULL, TC_HDR_SIZE);
p = init_talloc(parent, tc, 0, 1);
unlock();
return p;
}
void _talloc_locksafe(void (*lock)(void *), void (*unlock)(void *), void *data)
{
tc_lock = lock;
tc_unlock = unlock;
tc_lock_data = data;
return p;
}
......@@ -917,6 +917,8 @@ void *talloc_find_parent_byname(const void *ctx, const char *name);
* talloc_add_external - create an externally allocated node
* @ctx: the parent
* @realloc: the realloc() equivalent
* @lock: the call to lock before manipulation of external nodes
* @unlock: the call to unlock after manipulation of external nodes
*
* talloc_add_external() creates a node which uses a separate allocator. All
* children allocated from that node will also use that allocator.
......@@ -924,29 +926,17 @@ void *talloc_find_parent_byname(const void *ctx, const char *name);
* Note: Currently there is only one external allocator, not per-node,
* and it is set with this function.
*
* @lock is handed a pointer which was previous returned from your realloc
* function; you should use that to figure out which lock to get if you have
* multiple external pools.
*
* The parent pointers in realloc is the talloc pointer of the parent, if any.
*/
void *talloc_add_external(const void *ctx,
void *(*realloc)(const void *parent,
void *ptr, size_t));
/**
* talloc_locksafe - set locking for talloc on shared memory
* @lock: function to use to lock memory
* @unlock: function to use to unlock memory
* @data: pointer to hand to @lock and @unlock
*
* If talloc is actually dealing with shared memory (threads or shared
* memory using talloc_add_external()) then locking is required on
* allocation and free to avoid corruption.
*
* These hooks allow a very course-grained locking scheme: @lock is
* called before any internal alloc or free, and @unlock is called
* after. */
#define talloc_locksafe(lock, unlock, data) \
_talloc_locksafe(typesafe_cb(void, lock, data), \
typesafe_cb(void, unlock, data), \
data)
void *ptr, size_t),
void (*lock)(const void *p),
void (*unlock)(void));
/* The following definitions come from talloc.c */
void *_talloc(const void *context, size_t size);
......@@ -967,6 +957,5 @@ void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned
void *talloc_realloc_fn(const void *context, void *ptr, size_t size);
void talloc_show_parents(const void *context, FILE *file);
int talloc_is_parent(const void *context, const void *ptr);
void _talloc_locksafe(void (*lock)(void *), void (*unlock)(void *), void *);
#endif /* CCAN_TALLOC_H */
......@@ -2,7 +2,9 @@
#include "tap/tap.h"
#include <assert.h>
static int ext_alloc_count, ext_free_count, ext_realloc_count;
/* Much testing already done in run.c */
static int ext_alloc_count, ext_free_count, ext_realloc_count, lock_count, unlock_count;
static void *expected_parent;
static void *ext_realloc(const void *parent, void *ptr, size_t size)
......@@ -17,13 +19,23 @@ static void *ext_realloc(const void *parent, void *ptr, size_t size)
return realloc(ptr, size);
}
static void ext_lock(const void *ctx)
{
lock_count++;
}
static void ext_unlock(void)
{
unlock_count++;
}
int main(void)
{
char *p, *p2, *head;
plan_tests(12);
plan_tests(13);
expected_parent = NULL;
head = talloc_add_external(NULL, ext_realloc);
head = talloc_add_external(NULL, ext_realloc, ext_lock, ext_unlock);
assert(head);
ok1(ext_alloc_count == 1);
......@@ -50,5 +62,7 @@ int main(void)
talloc_free(p);
ok1(ext_free_count == 2);
ok1(lock_count == unlock_count);
return exit_status();
}
......@@ -30,43 +30,45 @@
#include "tap/tap.h"
#define torture_assert(test, expr, str) \
ok(expr, "failure: %s [\n%s: Expression %s failed: %s\n]\n", \
ok(expr, "%s [\n%s: Expression %s failed: %s\n]\n", \
test, __location__, #expr, str)
#define torture_assert_str_equal(test, arg1, arg2, desc) \
ok(strcmp(arg1, arg2) == 0, \
"failure: %s [\n%s: Expected %s, got %s: %s\n]\n", \
"%s [\n%s: Expected %s, got %s: %s\n]\n", \
test, __location__, arg1, arg2, desc)
#define CHECK_SIZE(test, ptr, tsize) \
ok(talloc_total_size(ptr) == (tsize), \
"failed: %s [\nwrong '%s' tree size: got %u expected %u\n]\n", \
"%s [\nwrong '%s' tree size: got %u expected %u\n]\n", \
test, #ptr, \
(unsigned)talloc_total_size(ptr), \
(unsigned)tsize)
#define CHECK_BLOCKS(test, ptr, tblocks) \
ok(talloc_total_blocks(ptr) == (tblocks), \
"failed: %s [\nwrong '%s' tree blocks: got %u expected %u\n]\n", \
"%s [\nwrong '%s' tree blocks: got %u expected %u\n]\n", \
test, #ptr, \
(unsigned)talloc_total_blocks(ptr), \
(unsigned)tblocks)
#define CHECK_PARENT(test, ptr, parent) \
ok(talloc_parent(ptr) == (parent), \
"failed: %s [\n'%s' has wrong parent: got %p expected %p\n]\n", \
"%s [\n'%s' has wrong parent: got %p expected %p\n]\n", \
test, #ptr, \
talloc_parent(ptr), \
(parent))
struct torture_context;
/*
test references
*/
static bool test_ref1(void)
static bool test_ref1(const struct torture_context *ctx)
{
void *root, *p1, *p2, *ref, *r1;
root = talloc_named_const(NULL, 0, "root");
root = talloc_named_const(ctx, 0, "root");
p1 = talloc_named_const(root, 1, "p1");
p2 = talloc_named_const(p1, 1, "p2");
talloc_named_const(p1, 1, "x1");
......@@ -107,11 +109,11 @@ static bool test_ref1(void)
/*
test references
*/
static bool test_ref2(void)
static bool test_ref2(const struct torture_context *ctx)
{
void *root, *p1, *p2, *ref, *r1;
root = talloc_named_const(NULL, 0, "root");
root = talloc_named_const(ctx, 0, "root");
p1 = talloc_named_const(root, 1, "p1");
talloc_named_const(p1, 1, "x1");
talloc_named_const(p1, 1, "x2");
......@@ -151,11 +153,11 @@ static bool test_ref2(void)
/*
test references
*/
static bool test_ref3(void)
static bool test_ref3(const struct torture_context *ctx)
{
void *root, *p1, *p2, *ref, *r1;
root = talloc_named_const(NULL, 0, "root");
root = talloc_named_const(ctx, 0, "root");
p1 = talloc_named_const(root, 1, "p1");
p2 = talloc_named_const(root, 1, "p2");
r1 = talloc_named_const(p1, 1, "r1");
......@@ -182,11 +184,11 @@ static bool test_ref3(void)
/*
test references
*/
static bool test_ref4(void)
static bool test_ref4(const struct torture_context *ctx)
{
void *root, *p1, *p2, *ref, *r1;
root = talloc_named_const(NULL, 0, "root");
root = talloc_named_const(ctx, 0, "root");
p1 = talloc_named_const(root, 1, "p1");
talloc_named_const(p1, 1, "x1");
talloc_named_const(p1, 1, "x2");
......@@ -222,11 +224,11 @@ static bool test_ref4(void)
/*
test references
*/
static bool test_unlink1(void)
static bool test_unlink1(const struct torture_context *ctx)
{
void *root, *p1, *p2, *ref, *r1;
root = talloc_named_const(NULL, 0, "root");
root = talloc_named_const(ctx, 0, "root");
p1 = talloc_named_const(root, 1, "p1");
talloc_named_const(p1, 1, "x1");
talloc_named_const(p1, 1, "x2");
......@@ -263,14 +265,14 @@ static int fail_destructor(void *ptr)
/*
miscellaneous tests to try to get a higher test coverage percentage
*/
static bool test_misc(void)
static bool test_misc(const struct torture_context *ctx)
{
void *root, *p1;
char *p2;
double *d;
const char *name;
root = talloc_new(NULL);
root = talloc_new(ctx);
p1 = talloc_size(root, 0x7fffffff);
torture_assert("misc", !p1, "failed: large talloc allowed\n");
......@@ -404,11 +406,11 @@ static bool test_misc(void)
/*
test realloc
*/
static bool test_realloc(void)
static bool test_realloc(const struct torture_context *ctx)
{
void *root, *p1, *p2;
root = talloc_new(NULL);
root = talloc_new(ctx);
p1 = talloc_size(root, 10);
CHECK_SIZE("realloc", p1, 10);
......@@ -456,7 +458,7 @@ static bool test_realloc(void)
/*
test realloc with a child
*/
static bool test_realloc_child(void)
static bool test_realloc_child(const struct torture_context *ctx)
{
void *root;
struct el2 {
......@@ -467,7 +469,7 @@ static bool test_realloc_child(void)
struct el2 **list, **list2, **list3;
} *el1;
root = talloc_new(NULL);
root = talloc_new(ctx);
el1 = talloc(root, struct el1);
el1->list = talloc(el1, struct el2 *);
......@@ -498,7 +500,7 @@ static bool test_realloc_child(void)
/*
test type checking
*/
static bool test_type(void)
static bool test_type(const struct torture_context *ctx)
{
void *root;
struct el1 {
......@@ -509,7 +511,7 @@ static bool test_type(void)
};
struct el1 *el1;
root = talloc_new(NULL);
root = talloc_new(ctx);
el1 = talloc(root, struct el1);
......@@ -531,11 +533,11 @@ static bool test_type(void)
/*
test steal
*/
static bool test_steal(void)
static bool test_steal(const struct torture_context *ctx)
{
void *root, *p1, *p2;
root = talloc_new(NULL);
root = talloc_new(ctx);
p1 = talloc_array(root, char, 10);
CHECK_SIZE("steal", p1, 10);
......@@ -579,7 +581,7 @@ static bool test_steal(void)
/*
test move
*/
static bool test_move(void)
static bool test_move(const struct torture_context *ctx)
{
void *root;
struct t_move {
......@@ -587,7 +589,7 @@ static bool test_move(void)
int *x;
} *t1, *t2;
root = talloc_new(NULL);
root = talloc_new(ctx);
t1 = talloc(root, struct t_move);
t2 = talloc(root, struct t_move);
......@@ -609,11 +611,11 @@ static bool test_move(void)
/*
test talloc_realloc_fn
*/
static bool test_realloc_fn(void)
static bool test_realloc_fn(const struct torture_context *ctx)
{
void *root, *p1;
root = talloc_new(NULL);
root = talloc_new(ctx);
p1 = talloc_realloc_fn(root, NULL, 10);
CHECK_BLOCKS("realloc_fn", root, 2);
......@@ -631,11 +633,11 @@ static bool test_realloc_fn(void)
}
static bool test_unref_reparent(void)
static bool test_unref_reparent(const struct torture_context *ctx)
{
void *root, *p1, *p2, *c1;
root = talloc_named_const(NULL, 0, "root");
root = talloc_named_const(ctx, 0, "root");
p1 = talloc_named_const(root, 1, "orig parent");
p2 = talloc_named_const(root, 1, "parent by reference");
......@@ -658,11 +660,11 @@ static bool test_unref_reparent(void)
return true;
}
static bool test_lifeless(void)
static bool test_lifeless(const struct torture_context *ctx)
{
void *top = talloc_new(NULL);
void *top = talloc_new(ctx);
char *parent, *child;
void *child_owner = talloc_new(NULL);
void *child_owner = talloc_new(ctx);
parent = talloc_strdup(top, "parent");
child = talloc_strdup(parent, "child");
......@@ -685,9 +687,9 @@ static int test_loop_destructor(char *ptr)
return 0;
}
static bool test_loop(void)
static bool test_loop(const struct torture_context *ctx)
{
void *top = talloc_new(NULL);
void *top = talloc_new(ctx);
char *parent;
struct req1 {
char *req2, *req3;
......@@ -714,9 +716,9 @@ static int fail_destructor_str(char *ptr)
return -1;
}
static bool test_free_parent_deny_child(void)
static bool test_free_parent_deny_child(const struct torture_context *ctx)
{
void *top = talloc_new(NULL);
void *top = talloc_new(ctx);
char *level1;
char *level2;
char *level3;
......@@ -736,9 +738,9 @@ static bool test_free_parent_deny_child(void)
return true;
}
static bool test_talloc_ptrtype(void)
static bool test_talloc_ptrtype(const struct torture_context *ctx)
{
void *top = talloc_new(NULL);
void *top = talloc_new(ctx);
struct struct1 {
int foo;
int bar;
......@@ -779,13 +781,15 @@ static bool test_talloc_ptrtype(void)
return true;
}
static bool test_talloc_free_in_destructor_run;
static int _test_talloc_free_in_destructor(void **ptr)
{
talloc_free(*ptr);
test_talloc_free_in_destructor_run = true;
return 0;
}
static bool test_talloc_free_in_destructor(void)
static bool test_talloc_free_in_destructor(const struct torture_context *ctx)
{
void *level0;
void *level1;
......@@ -794,28 +798,32 @@ static bool test_talloc_free_in_destructor(void)
void *level4;
void **level5;
level0 = talloc_new(NULL);
/* FIXME: Can't do nested destruction with locking, sorry. */
if (ctx)
return true;
level0 = talloc_new(ctx);
level1 = talloc_new(level0);
level2 = talloc_new(level1);
level3 = talloc_new(level2);
level4 = talloc_new(level3);
level5 = talloc(level4, void *);
*level5 = level3;
(void)talloc_reference(level0, level3);
(void)talloc_reference(level3, level3);
(void)talloc_reference(level5, level3);
*level5 = talloc_reference(NULL, level3);
test_talloc_free_in_destructor_run = false;
talloc_set_destructor(level5, _test_talloc_free_in_destructor);
talloc_free(level1);
talloc_free(level0);
ok1(test_talloc_free_in_destructor_run);
return true;
}
static bool test_autofree(void)
static bool test_autofree(const struct torture_context *ctx)
{
/* autofree test would kill smbtorture */
void *p;
......@@ -828,8 +836,7 @@ static bool test_autofree(void)
return true;
}
struct torture_context;
static bool torture_local_talloc(struct torture_context *tctx)
static bool torture_local_talloc(const struct torture_context *tctx)
{
bool ret = true;
......@@ -838,54 +845,140 @@ static bool torture_local_talloc(struct torture_context *tctx)
talloc_disable_null_tracking();
talloc_enable_null_tracking();
ret &= test_ref1();
ret &= test_ref2();
ret &= test_ref3();
ret &= test_ref4();
ret &= test_unlink1();
ret &= test_misc();
ret &= test_realloc();
ret &= test_realloc_child();
ret &= test_steal();
ret &= test_move();
ret &= test_unref_reparent();
ret &= test_realloc_fn();
ret &= test_type();
ret &= test_lifeless();
ret &= test_loop();
ret &= test_free_parent_deny_child();
ret &= test_talloc_ptrtype();
ret &= test_talloc_free_in_destructor();
ret &= test_autofree();
ret &= test_ref1(tctx);
ret &= test_ref2(tctx);
ret &= test_ref3(tctx);
ret &= test_ref4(tctx);
ret &= test_unlink1(tctx);
ret &= test_misc(tctx);
ret &= test_realloc(tctx);
ret &= test_realloc_child(tctx);
ret &= test_steal(tctx);
ret &= test_move(tctx);
ret &= test_unref_reparent(tctx);
ret &= test_realloc_fn(tctx);
ret &= test_type(tctx);
ret &= test_lifeless(tctx);
ret &= test_loop(tctx);
ret &= test_free_parent_deny_child(tctx);
ret &= test_talloc_ptrtype(tctx);
ret &= test_talloc_free_in_destructor(tctx);
ret &= test_autofree(tctx);
return ret;
}
static int lock_failed = 0, unlock_failed = 0;
static void test_lock(int *locked)
static int lock_failed = 0, unlock_failed = 0, lock_bad = 0;
static int locked;
#define MAX_ALLOCATIONS 100
static void *allocations[MAX_ALLOCATIONS];
static int num_allocs, num_frees, num_reallocs;
static unsigned int find_ptr(const void *p)
{
if (*locked)
unsigned int i;
for (i = 0; i < MAX_ALLOCATIONS; i++)
if (allocations[i] == p)
break;
return i;
}
static unsigned int allocations_used(void)
{
unsigned int i, ret = 0;
for (i = 0; i < MAX_ALLOCATIONS; i++)
if (allocations[i])
ret++;
return ret;
}
static void test_lock(const void *ctx)
{
if (find_ptr(ctx) == MAX_ALLOCATIONS)
lock_bad++;
if (locked)
lock_failed++;
*locked = 1;
locked = 1;
}
static void test_unlock(int *locked)
static void test_unlock(void)
{
if (!*locked)
if (!locked)
unlock_failed++;
*locked = 0;
locked = 0;
}
static int realloc_called, realloc_bad;
static void *normal_realloc(const void *parent, void *ptr, size_t size)
{
unsigned int i = find_ptr(ptr);
realloc_called++;
if (ptr && size)
num_reallocs++;
else if (ptr)
num_frees++;
else if (size)
num_allocs++;
else
abort();
if (i == MAX_ALLOCATIONS) {
if (ptr) {
realloc_bad++;
i = find_ptr(NULL);
} else
abort();
}
allocations[i] = realloc(ptr, size);
/* Not guarenteed by realloc. */
if (!size)
allocations[i] = NULL;
return allocations[i];
}
int main(void)
{
int locked = 0;
struct torture_context *ctx;
plan_tests(136);
talloc_locksafe(test_lock, test_unlock, &locked);
plan_tests(284);
ctx = talloc_add_external(NULL, normal_realloc, test_lock, test_unlock);
torture_local_talloc(NULL);
ok(!lock_bad, "%u locks on bad pointer", lock_bad);
ok(!lock_failed, "lock_failed count %u should be zero", lock_failed);
ok(!unlock_failed, "unlock_failed count %u should be zero",
unlock_failed);
ok(realloc_called == 1, "our realloc should not be called again");
torture_local_talloc(ctx);
ok(!lock_bad, "%u locks on bad pointer", lock_bad);
ok(!lock_failed, "lock_failed count %u should be zero", lock_failed);
ok(!unlock_failed, "unlock_failed count %u should be zero", unlock_failed);
ok(!unlock_failed, "unlock_failed count %u should be zero",
unlock_failed);
ok(realloc_called, "our realloc should be called");
ok(!realloc_bad, "our realloc given unknown pointer %u times",
realloc_bad);
talloc_free(ctx);
ok(!lock_bad, "%u locks on bad pointer", lock_bad);
ok(!lock_failed, "lock_failed count %u should be zero", lock_failed);
ok(!unlock_failed, "unlock_failed count %u should be zero",
unlock_failed);
ok(realloc_called, "our realloc should be called");
ok(!realloc_bad, "our realloc given unknown pointer %u times",
realloc_bad);
ok(allocations_used() == 0, "%u allocations still used?",
allocations_used());
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment