From a0502456a6479e8557566d361561dc8f9544229a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 24 Jul 2015 08:50:31 -0700 Subject: [PATCH] lib: tevent: Initial test of tevent threaded context code. Bug: https://bugzilla.samba.org/show_bug.cgi?id=11771 Signed-off-by: Jeremy Allison Signed-off-by: Ralph Boehme (cherry picked from commit 187aebb25b970a3679a72109def8e8b85622722e) --- lib/tevent/testsuite.c | 125 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/lib/tevent/testsuite.c b/lib/tevent/testsuite.c index c63c8780262..f8f65f8246e 100644 --- a/lib/tevent/testsuite.c +++ b/lib/tevent/testsuite.c @@ -808,6 +808,127 @@ static bool test_event_context_threaded(struct torture_context *test, return true; } +#define NUM_TEVENT_THREADS 100 + +/* Ugly, but needed for torture_comment... */ +static struct torture_context *thread_test_ctx; +static pthread_t thread_map[NUM_TEVENT_THREADS]; +static unsigned thread_counter; + +/* Called in master thread context */ +static void callback_nowait(struct tevent_context *ev, + struct tevent_immediate *im, + void *private_ptr) +{ + pthread_t *thread_id_ptr = + talloc_get_type_abort(private_ptr, pthread_t); + unsigned i; + + for (i = 0; i < NUM_TEVENT_THREADS; i++) { + if (pthread_equal(*thread_id_ptr, + thread_map[i])) { + break; + } + } + torture_comment(thread_test_ctx, + "Callback %u from thread %u\n", + thread_counter, + i); + thread_counter++; +} + +/* Blast the master tevent_context with a callback, no waiting. */ +static void *thread_fn_nowait(void *private_ptr) +{ + struct tevent_thread_proxy *master_tp = + talloc_get_type_abort(private_ptr, struct tevent_thread_proxy); + struct tevent_immediate *im; + pthread_t *thread_id_ptr; + + im = tevent_create_immediate(NULL); + if (im == NULL) { + return NULL; + } + thread_id_ptr = talloc(NULL, pthread_t); + if (thread_id_ptr == NULL) { + return NULL; + } + *thread_id_ptr = pthread_self(); + + tevent_thread_proxy_schedule(master_tp, + &im, + callback_nowait, + &thread_id_ptr); + return NULL; +} + +static void timeout_fn(struct tevent_context *ev, + struct tevent_timer *te, + struct timeval tv, void *p) +{ + thread_counter = NUM_TEVENT_THREADS * 10; +} + +static bool test_multi_tevent_threaded(struct torture_context *test, + const void *test_data) +{ + unsigned i; + struct tevent_context *master_ev; + struct tevent_thread_proxy *tp; + + talloc_disable_null_tracking(); + + /* Ugly global stuff. */ + thread_test_ctx = test; + thread_counter = 0; + + master_ev = tevent_context_init(NULL); + if (master_ev == NULL) { + return false; + } + tevent_set_debug_stderr(master_ev); + + tp = tevent_thread_proxy_create(master_ev); + if (tp == NULL) { + torture_fail(test, + talloc_asprintf(test, + "tevent_thread_proxy_create failed\n")); + talloc_free(master_ev); + return false; + } + + for (i = 0; i < NUM_TEVENT_THREADS; i++) { + int ret = pthread_create(&thread_map[i], + NULL, + thread_fn_nowait, + tp); + if (ret != 0) { + torture_fail(test, + talloc_asprintf(test, + "Failed to create thread %i, %d\n", + i, ret)); + return false; + } + } + + /* Ensure we don't wait more than 10 seconds. */ + tevent_add_timer(master_ev, + master_ev, + timeval_current_ofs(10,0), + timeout_fn, + NULL); + + while (thread_counter < NUM_TEVENT_THREADS) { + int ret = tevent_loop_once(master_ev); + torture_assert(test, ret == 0, "tevent_loop_once failed"); + } + + torture_assert(test, thread_counter == NUM_TEVENT_THREADS, + "thread_counter fail\n"); + + talloc_free(master_ev); + return true; +} #endif struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx) @@ -841,6 +962,10 @@ struct torture_suite *torture_local_event(TALLOC_CTX *mem_ctx) torture_suite_add_simple_tcase_const(suite, "threaded_poll_mt", test_event_context_threaded, NULL); + + torture_suite_add_simple_tcase_const(suite, "multi_tevent_threaded", + test_multi_tevent_threaded, + NULL); #endif return suite; -- 2.34.1