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 ||