From fdb16dd247797eabfdda49d6b6fb40a4642c0664 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 16 Mar 2015 12:18:17 -0700 Subject: [PATCH] lib: talloc: tests - add test_pthread_talloc_passing() testing talloc in a pthread environment. Signed-off-by: Jeremy Allison Reviewed-by: Simo Reviewed-by: "Stefan (metze) Metzmacher" Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Tue Mar 17 19:23:29 CET 2015 on sn-devel-104 --- lib/talloc/testsuite.c | 153 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/talloc/wscript | 6 +- 2 files changed, 158 insertions(+), 1 deletion(-) diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c index eb3e13d5af0..6d0fe94479e 100644 --- a/lib/talloc/testsuite.c +++ b/lib/talloc/testsuite.c @@ -27,6 +27,10 @@ #include "system/time.h" #include +#ifdef HAVE_PTHREAD +#include +#endif + #include "talloc_testsuite.h" static struct timeval timeval_current(void) @@ -1701,6 +1705,151 @@ static bool test_memlimit(void) return true; } +#ifdef HAVE_PTHREAD + +#define NUM_THREADS 100 + +/* Sync variables. */ +static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t condvar = PTHREAD_COND_INITIALIZER; +static void *intermediate_ptr; + +/* Subthread. */ +static void *thread_fn(void *arg) +{ + int ret; + const char *ctx_name = (const char *)arg; + void *sub_ctx = NULL; + /* + * Do stuff that creates a new talloc hierarchy in + * this thread. + */ + void *top_ctx = talloc_named_const(NULL, 0, "top"); + if (top_ctx == NULL) { + return NULL; + } + sub_ctx = talloc_named_const(top_ctx, 100, ctx_name); + if (sub_ctx == NULL) { + return NULL; + } + + /* + * Now transfer a pointer from our hierarchy + * onto the intermediate ptr. + */ + ret = pthread_mutex_lock(&mtx); + if (ret != 0) { + talloc_free(top_ctx); + return NULL; + } + /* Wait for intermediate_ptr to be free. */ + while (intermediate_ptr != NULL) { + ret = pthread_cond_wait(&condvar, &mtx); + if (ret != 0) { + talloc_free(top_ctx); + return NULL; + } + } + + /* and move our memory onto it from our toplevel hierarchy. */ + intermediate_ptr = talloc_move(NULL, &sub_ctx); + + /* Tell the main thread it's ready for pickup. */ + pthread_cond_broadcast(&condvar); + pthread_mutex_unlock(&mtx); + + talloc_free(top_ctx); + return NULL; +} + +/* Main thread. */ +static bool test_pthread_talloc_passing(void) +{ + int i; + int ret; + char str_array[NUM_THREADS][20]; + pthread_t thread_id; + void *mem_ctx; + + /* + * Important ! Null tracking breaks threaded talloc. + * It *must* be turned off. + */ + talloc_disable_null_tracking(); + + printf("test: pthread_talloc_passing\n# PTHREAD TALLOC PASSING\n"); + + /* Main thread toplevel context. */ + mem_ctx = talloc_named_const(NULL, 0, "toplevel"); + if (mem_ctx == NULL) { + printf("failed to create toplevel context\n"); + return false; + } + + /* + * Spin off NUM_THREADS threads. + * They will use their own toplevel contexts. + */ + for (i = 0; i < NUM_THREADS; i++) { + (void)snprintf(str_array[i], + 20, + "thread:%d", + i); + if (str_array[i] == NULL) { + printf("snprintf %d failed\n", i); + return false; + } + ret = pthread_create(&thread_id, + NULL, + thread_fn, + str_array[i]); + if (ret != 0) { + printf("failed to create thread %d (%d)\n", i, ret); + return false; + } + } + + printf("Created %d threads\n", NUM_THREADS); + + /* Now wait for NUM_THREADS transfers of the talloc'ed memory. */ + for (i = 0; i < NUM_THREADS; i++) { + ret = pthread_mutex_lock(&mtx); + if (ret != 0) { + printf("pthread_mutex_lock %d failed (%d)\n", i, ret); + talloc_free(mem_ctx); + return false; + } + + /* Wait for intermediate_ptr to have our data. */ + while (intermediate_ptr == NULL) { + ret = pthread_cond_wait(&condvar, &mtx); + if (ret != 0) { + printf("pthread_cond_wait %d failed (%d)\n", i, + ret); + talloc_free(mem_ctx); + return false; + } + } + + /* and move it onto our toplevel hierarchy. */ + (void)talloc_move(mem_ctx, &intermediate_ptr); + + /* Tell the sub-threads we're ready for another. */ + pthread_cond_broadcast(&condvar); + pthread_mutex_unlock(&mtx); + } + + CHECK_SIZE("pthread_talloc_passing", mem_ctx, NUM_THREADS * 100); +#if 1 + /* Dump the hierarchy. */ + talloc_report(mem_ctx, stdout); +#endif + talloc_free(mem_ctx); + printf("success: pthread_talloc_passing\n"); + return true; +} +#endif + static void test_reset(void) { talloc_set_log_fn(test_log_stdout); @@ -1771,6 +1920,10 @@ bool torture_local_talloc(struct torture_context *tctx) ret &= test_free_children(); test_reset(); ret &= test_memlimit(); +#ifdef HAVE_PTHREAD + test_reset(); + ret &= test_pthread_talloc_passing(); +#endif if (ret) { diff --git a/lib/talloc/wscript b/lib/talloc/wscript index 97c52c3e3ed..9efc895b558 100644 --- a/lib/talloc/wscript +++ b/lib/talloc/wscript @@ -89,9 +89,13 @@ def build(bld): public_headers=[], enabled=bld.env.TALLOC_COMPAT1) + testsuite_deps = 'talloc' + if bld.CONFIG_SET('HAVE_PTHREAD'): + testsuite_deps += ' pthread' + bld.SAMBA_BINARY('talloc_testsuite', 'testsuite_main.c testsuite.c', - deps='talloc', + testsuite_deps, install=False) else: -- 2.11.4.GIT