diff --git a/include/spdk/thread.h b/include/spdk/thread.h index deea20c30..c78ae7547 100644 --- a/include/spdk/thread.h +++ b/include/spdk/thread.h @@ -224,13 +224,14 @@ void spdk_set_thread(struct spdk_thread *thread); * Mark the thread as exited, failing all future spdk_thread_poll() calls. May * only be called within an spdk poller or message. * + * All I/O channel references associated with the thread must be released using + * spdk_put_io_channel() prior to calling this function. * * \param thread The thread to destroy. * - * All I/O channel references associated with the thread must be released using - * spdk_put_io_channel() prior to calling this function. + * \return 0 on success, negated errno on failure. */ -void spdk_thread_exit(struct spdk_thread *thread); +int spdk_thread_exit(struct spdk_thread *thread); /** * Returns whether the thread is marked as exited. diff --git a/lib/event/reactor.c b/lib/event/reactor.c index d848e65c9..e89f647b4 100644 --- a/lib/event/reactor.c +++ b/lib/event/reactor.c @@ -312,6 +312,7 @@ _spdk_reactor_run(void *arg) struct spdk_lw_thread *lw_thread, *tmp; char thread_name[32]; uint64_t rusage_period = 0; + int rc __attribute__((unused)); SPDK_NOTICELOG("Reactor started on core %u\n", reactor->lcore); @@ -353,7 +354,10 @@ _spdk_reactor_run(void *arg) thread = spdk_thread_get_from_ctx(lw_thread); TAILQ_REMOVE(&reactor->threads, lw_thread, link); spdk_set_thread(thread); - spdk_thread_exit(thread); + if (!spdk_thread_is_exited(thread)) { + rc = spdk_thread_exit(thread); + assert(rc == 0); + } spdk_thread_destroy(thread); } diff --git a/lib/thread/thread.c b/lib/thread/thread.c index 71c483154..69d96844c 100644 --- a/lib/thread/thread.c +++ b/lib/thread/thread.c @@ -345,14 +345,21 @@ spdk_set_thread(struct spdk_thread *thread) tls_thread = thread; } -void +int spdk_thread_exit(struct spdk_thread *thread) { SPDK_DEBUGLOG(SPDK_LOG_THREAD, "Exit thread %s\n", thread->name); assert(tls_thread == thread); + if (thread->exit) { + SPDK_ERRLOG("thread %s is already marked as exited\n", + thread->name); + return -EINVAL; + } + thread->exit = true; + return 0; } bool diff --git a/test/common/lib/ut_multithread.c b/test/common/lib/ut_multithread.c index 48bd31379..143fdd32e 100644 --- a/test/common/lib/ut_multithread.c +++ b/test/common/lib/ut_multithread.c @@ -102,10 +102,14 @@ void free_threads(void) { uint32_t i; + int rc __attribute__((unused)); for (i = 0; i < g_ut_num_threads; i++) { set_thread(i); - spdk_thread_exit(g_ut_threads[i].thread); + if (!spdk_thread_is_exited(g_ut_threads[i].thread)) { + rc = spdk_thread_exit(g_ut_threads[i].thread); + assert(rc == 0); + } spdk_thread_destroy(g_ut_threads[i].thread); g_ut_threads[i].thread = NULL; } diff --git a/test/unit/lib/thread/thread.c/thread_ut.c b/test/unit/lib/thread/thread.c/thread_ut.c index c3b5d19d3..681ec4230 100644 --- a/test/unit/lib/thread/thread.c/thread_ut.c +++ b/test/unit/lib/thread/thread.c/thread_ut.c @@ -754,7 +754,7 @@ thread_exit(void) bool done1 = false, done2 = false; int rc __attribute__((unused)); - allocate_threads(3); + allocate_threads(4); /* Test all pending messages are reaped for the thread marked as exited. */ set_thread(0); @@ -811,6 +811,14 @@ thread_exit(void) spdk_io_device_unregister(&g_device1, NULL); poll_threads(); + /* Test call spdk_thread_exit() is only once for a single thread. */ + set_thread(3); + + thread = spdk_get_thread(); + + CU_ASSERT(spdk_thread_exit(thread) == 0); + CU_ASSERT(spdk_thread_exit(thread) == -EINVAL); + free_threads(); }