#include "system/time.h"
#include <talloc.h>
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+#endif
+
#include "talloc_testsuite.h"
static struct timeval timeval_current(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);
ret &= test_free_children();
test_reset();
ret &= test_memlimit();
+#ifdef HAVE_PTHREAD
+ test_reset();
+ ret &= test_pthread_talloc_passing();
+#endif
if (ret) {