From 0f2ef7cf222dcc0ef2ead346f074baeaab3cee27 Mon Sep 17 00:00:00 2001 From: GangCao Date: Sun, 4 Feb 2018 18:50:57 -0500 Subject: [PATCH] ut_multithread: add the support of periodic poller This patch is to add the support of periodically running poller. A setting is added for the increased time so that the poller on that thread can be running or not depending on the required setting. UT code also added for this new functionality. Change-Id: I0d012ddb18c9b0f6ae8aa877a30d214d6ba34946 Signed-off-by: GangCao Reviewed-on: https://review.gerrithub.io/398359 Tested-by: SPDK Automated Test System Reviewed-by: Jim Harris Reviewed-by: Shuhei Matsumoto Reviewed-by: Daniel Verkamp --- test/lib/ut_multithread.c | 54 +++++++++++++++- test/unit/lib/bdev/mt/bdev.c/bdev_ut.c | 85 ++++++++++++++++++++++++++ 2 files changed, 137 insertions(+), 2 deletions(-) diff --git a/test/lib/ut_multithread.c b/test/lib/ut_multithread.c index a19b6bb11..17d89d846 100644 --- a/test/lib/ut_multithread.c +++ b/test/lib/ut_multithread.c @@ -36,11 +36,14 @@ #include "spdk_internal/mock.h" static uint32_t g_ut_num_threads; +static uint64_t g_current_time_in_us = 0; int allocate_threads(int num_threads); void free_threads(void); void poll_threads(void); int poll_thread(uintptr_t thread_id); +void increment_time(uint64_t time_in_us); +void reset_time(void); struct ut_msg { spdk_thread_fn fn; @@ -61,6 +64,8 @@ struct ut_poller { spdk_poller_fn fn; void *arg; TAILQ_ENTRY(ut_poller) tailq; + uint64_t period_us; + uint64_t next_expiration_in_us; }; static void @@ -87,6 +92,8 @@ __start_poller(void *thread_ctx, spdk_thread_fn fn, void *arg, uint64_t period_m poller->fn = fn; poller->arg = arg; + poller->period_us = period_microseconds; + poller->next_expiration_in_us = g_current_time_in_us + poller->period_us; TAILQ_INSERT_TAIL(&thread->pollers, poller, tailq); @@ -153,6 +160,41 @@ free_threads(void) g_ut_threads = NULL; } +void +increment_time(uint64_t time_in_us) +{ + g_current_time_in_us += time_in_us; +} + +static void +reset_pollers(void) +{ + uint32_t i = 0; + struct ut_thread *thread = NULL; + struct ut_poller *poller = NULL; + uintptr_t original_thread_id = g_thread_id; + + CU_ASSERT(g_current_time_in_us == 0); + + for (i = 0; i < g_ut_num_threads; i++) { + set_thread(i); + thread = &g_ut_threads[i]; + + TAILQ_FOREACH(poller, &thread->pollers, tailq) { + poller->next_expiration_in_us = g_current_time_in_us + poller->period_us; + } + } + + set_thread(original_thread_id); +} + +void +reset_time(void) +{ + g_current_time_in_us = 0; + reset_pollers(); +} + int poll_thread(uintptr_t thread_id) { @@ -184,8 +226,16 @@ poll_thread(uintptr_t thread_id) poller = TAILQ_FIRST(&thread->pollers); TAILQ_REMOVE(&thread->pollers, poller, tailq); - if (poller->fn) { - poller->fn(poller->arg); + while (g_current_time_in_us >= poller->next_expiration_in_us) { + if (poller->fn) { + poller->fn(poller->arg); + } + + if (poller->period_us == 0) { + break; + } else { + poller->next_expiration_in_us += poller->period_us; + } } TAILQ_INSERT_TAIL(&tmp_pollers, poller, tailq); diff --git a/test/unit/lib/bdev/mt/bdev.c/bdev_ut.c b/test/unit/lib/bdev/mt/bdev.c/bdev_ut.c index 6c6627127..b43c4030c 100644 --- a/test/unit/lib/bdev/mt/bdev.c/bdev_ut.c +++ b/test/unit/lib/bdev/mt/bdev.c/bdev_ut.c @@ -269,6 +269,90 @@ basic(void) teardown_test(); } +static void +poller_run_done(void *ctx) +{ + bool *poller_run = ctx; + + *poller_run = true; +} + +static void +poller_run_times_done(void *ctx) +{ + int *poller_run_times = ctx; + + (*poller_run_times)++; +} + +static void +basic_poller(void) +{ + struct spdk_poller *poller = NULL; + bool poller_run = false; + int poller_run_times = 0; + + setup_test(); + + set_thread(0); + reset_time(); + /* Register a poller with no-wait time and test execution */ + poller = spdk_poller_register(poller_run_done, &poller_run, 0); + CU_ASSERT(poller != NULL); + + poll_threads(); + CU_ASSERT(poller_run == true); + + spdk_poller_unregister(&poller); + CU_ASSERT(poller == NULL); + + /* Register a poller with 1000us wait time and test single execution */ + poller_run = false; + poller = spdk_poller_register(poller_run_done, &poller_run, 1000); + CU_ASSERT(poller != NULL); + + poll_threads(); + CU_ASSERT(poller_run == false); + + increment_time(1000); + poll_threads(); + CU_ASSERT(poller_run == true); + + reset_time(); + poller_run = false; + poll_threads(); + CU_ASSERT(poller_run == false); + + increment_time(1000); + poll_threads(); + CU_ASSERT(poller_run == true); + + spdk_poller_unregister(&poller); + CU_ASSERT(poller == NULL); + + reset_time(); + /* Register a poller with 1000us wait time and test multiple execution */ + poller = spdk_poller_register(poller_run_times_done, &poller_run_times, 1000); + CU_ASSERT(poller != NULL); + + poll_threads(); + CU_ASSERT(poller_run_times == 0); + + increment_time(1000); + poll_threads(); + CU_ASSERT(poller_run_times == 1); + + poller_run_times = 0; + increment_time(2000); + poll_threads(); + CU_ASSERT(poller_run_times == 2); + + spdk_poller_unregister(&poller); + CU_ASSERT(poller == NULL); + + teardown_test(); +} + static void reset_done(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg) { @@ -689,6 +773,7 @@ main(int argc, char **argv) if ( CU_add_test(suite, "basic", basic) == NULL || + CU_add_test(suite, "basic_poller", basic_poller) == NULL || CU_add_test(suite, "put_channel_during_reset", put_channel_during_reset) == NULL || CU_add_test(suite, "aborted_reset", aborted_reset) == NULL || CU_add_test(suite, "io_during_reset", io_during_reset) == NULL ||