diff --git a/include/spdk_internal/thread.h b/include/spdk_internal/thread.h index a047a750e..d517e2c37 100644 --- a/include/spdk_internal/thread.h +++ b/include/spdk_internal/thread.h @@ -121,6 +121,8 @@ struct spdk_thread { SLIST_HEAD(, spdk_msg) msg_cache; size_t msg_cache_count; spdk_msg_fn critical_msg; + uint64_t exit_timeout_tsc; + /* User context allocated at the end */ uint8_t ctx[0]; }; diff --git a/lib/thread/thread.c b/lib/thread/thread.c index 31f9c8645..455d01046 100644 --- a/lib/thread/thread.c +++ b/lib/thread/thread.c @@ -45,6 +45,7 @@ #define SPDK_MSG_BATCH_SIZE 8 #define SPDK_MAX_DEVICE_NAME_LEN 256 +#define SPDK_THREAD_EXIT_TIMEOUT_SEC 5 static pthread_mutex_t g_devlist_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -317,11 +318,17 @@ spdk_set_thread(struct spdk_thread *thread) } static void -_spdk_thread_exit(struct spdk_thread *thread) +_spdk_thread_exit(struct spdk_thread *thread, uint64_t now) { struct spdk_poller *poller; struct spdk_io_channel *ch; + if (now >= thread->exit_timeout_tsc) { + SPDK_ERRLOG("thread %s got timeout, and move it to the exited state forcefully\n", + thread->name); + goto exited; + } + TAILQ_FOREACH(poller, &thread->active_pollers, tailq) { if (poller->state != SPDK_POLLER_STATE_UNREGISTERED) { SPDK_INFOLOG(SPDK_LOG_THREAD, @@ -354,6 +361,7 @@ _spdk_thread_exit(struct spdk_thread *thread) return; } +exited: thread->state = SPDK_THREAD_STATE_EXITED; } @@ -371,6 +379,8 @@ spdk_thread_exit(struct spdk_thread *thread) return 0; } + thread->exit_timeout_tsc = spdk_get_ticks() + (spdk_get_ticks_hz() * + SPDK_THREAD_EXIT_TIMEOUT_SEC); thread->state = SPDK_THREAD_STATE_EXITING; return 0; } @@ -664,7 +674,7 @@ spdk_thread_poll(struct spdk_thread *thread, uint32_t max_msgs, uint64_t now) rc = _spdk_thread_poll(thread, max_msgs, now); if (spdk_unlikely(thread->state == SPDK_THREAD_STATE_EXITING)) { - _spdk_thread_exit(thread); + _spdk_thread_exit(thread, now); } _spdk_thread_update_stats(thread, spdk_get_ticks(), now, rc); diff --git a/test/unit/lib/thread/thread.c/thread_ut.c b/test/unit/lib/thread/thread.c/thread_ut.c index b1b885f24..2e2782fd2 100644 --- a/test/unit/lib/thread/thread.c/thread_ut.c +++ b/test/unit/lib/thread/thread.c/thread_ut.c @@ -810,7 +810,10 @@ thread_exit(void) bool done1 = false, done2 = false, poller1_run = false, poller2_run = false; int rc __attribute__((unused)); - allocate_threads(3); + MOCK_SET(spdk_get_ticks, 10); + MOCK_SET(spdk_get_ticks_hz, 1); + + allocate_threads(4); /* Test if all pending messages are reaped for the exiting thread, and the * thread moves to the exited state. @@ -919,6 +922,37 @@ thread_exit(void) CU_ASSERT(spdk_thread_is_exited(thread) == true); + /* Test if the exiting thread is exited forcefully after timeout. */ + set_thread(3); + thread = spdk_get_thread(); + + poller1 = spdk_poller_register(poller_run_done, &poller1_run, 0); + CU_ASSERT(poller1 != NULL); + + spdk_thread_exit(thread); + + CU_ASSERT(spdk_thread_is_exited(thread) == false); + + MOCK_SET(spdk_get_ticks, 11); + + poll_threads(); + + CU_ASSERT(spdk_thread_is_exited(thread) == false); + + /* Cause timeout forcefully. */ + MOCK_SET(spdk_get_ticks, 15); + + poll_threads(); + + CU_ASSERT(spdk_thread_is_exited(thread) == true); + + spdk_poller_unregister(&poller1); + + poll_threads(); + + MOCK_CLEAR(spdk_get_ticks); + MOCK_CLEAR(spdk_get_ticks_hz); + free_threads(); }