lib: tevent: Initial test of tevent threaded context code.
authorJeremy Allison <jra@samba.org>
Fri, 24 Jul 2015 15:50:31 +0000 (08:50 -0700)
committerStefan Metzmacher <metze@samba.org>
Thu, 5 Nov 2015 17:04:23 +0000 (18:04 +0100)
Signed-off-by: Jeremy Allison <jra@samba.org>
Signed-off-by: Ralph Boehme <slow@samba.org>
lib/tevent/testsuite.c

index c63c8780262db9fc5605b4ae05f0becfbba773fc..f8f65f8246e45102835eef434f1b486c3db03864 100644 (file)
@@ -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;