lib/thread: Add timeout to wait until exiting thread is exited

Set 5 seconds timeout to wait until exiting thread is exited into
spdk_thread_poll(). After the timeout, collect error log and then
move the thread to exited forcefully.

Add necessary unit test case accordingly.

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: Ied8f58a2023a3bbe098530810fd3288bef93c3e7
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/1644
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
Shuhei Matsumoto 2020-04-05 23:00:53 +09:00 committed by Tomasz Zawadzki
parent e9aec6746a
commit a12aae4c85
3 changed files with 49 additions and 3 deletions

View File

@ -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];
};

View File

@ -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);

View File

@ -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();
}