diff --git a/lib/thread/thread.c b/lib/thread/thread.c index 0f20a78a4..6165a77fb 100644 --- a/lib/thread/thread.c +++ b/lib/thread/thread.c @@ -349,6 +349,7 @@ int spdk_thread_exit(struct spdk_thread *thread) { struct spdk_poller *poller; + struct spdk_io_channel *ch; SPDK_DEBUGLOG(SPDK_LOG_THREAD, "Exit thread %s\n", thread->name); @@ -382,6 +383,14 @@ spdk_thread_exit(struct spdk_thread *thread) return -EBUSY; } + TAILQ_FOREACH(ch, &thread->io_channels, tailq) { + if (ch->ref != 0) { + SPDK_ERRLOG("thread %s still has active channel for io_device %s\n", + thread->name, ch->dev->name); + return -EBUSY; + } + } + thread->exit = true; return 0; } diff --git a/test/unit/lib/thread/thread.c/thread_ut.c b/test/unit/lib/thread/thread.c/thread_ut.c index ba46149bd..d161bc21e 100644 --- a/test/unit/lib/thread/thread.c/thread_ut.c +++ b/test/unit/lib/thread/thread.c/thread_ut.c @@ -755,7 +755,7 @@ thread_exit(void) bool done1 = false, done2 = false, poller_run = false; int rc __attribute__((unused)); - allocate_threads(5); + allocate_threads(6); /* Test all pending messages are reaped for the thread marked as exited. */ set_thread(0); @@ -820,7 +820,7 @@ thread_exit(void) CU_ASSERT(spdk_thread_exit(thread) == 0); CU_ASSERT(spdk_thread_exit(thread) == -EINVAL); - /* Test if spdk_thread_exit() fails when there is any not-unregistered poller, + /* Test if spdk_thread_exit() fails when there is any registered poller, * and if no poller is executed after the thread is marked as exited. */ set_thread(4); @@ -847,6 +847,32 @@ thread_exit(void) CU_ASSERT(poller_run == false); + /* Test if spdk_thread_exit() fails when there is any active I/O channel. */ + set_thread(5); + thread = spdk_get_thread(); + + spdk_io_device_register(&g_device1, create_cb_1, destroy_cb_1, sizeof(g_ctx1), NULL); + + g_create_cb_calls = 0; + ch = spdk_get_io_channel(&g_device1); + CU_ASSERT(g_create_cb_calls == 1); + CU_ASSERT(ch != NULL); + + CU_ASSERT(spdk_thread_exit(thread) == -EBUSY); + + g_destroy_cb_calls = 0; + spdk_put_io_channel(ch); + CU_ASSERT(g_destroy_cb_calls == 0); + + CU_ASSERT(spdk_thread_exit(thread) == 0); + + poll_threads(); + CU_ASSERT(g_destroy_cb_calls == 1); + + spdk_io_device_unregister(&g_device1, NULL); + + CU_ASSERT(TAILQ_EMPTY(&thread->io_channels)); + free_threads(); }