lib/thread: Fail spdk_thread_exit() if thread has active I/O channel

This is a preparation to support voluntary thread termination by
calling spdk_thread_exit().

The comment in the header file has already said that all associated
I/O channels must be released before calling spdk_thread_exit().
This patch actually checks if it is satisfied in spdk_thread_exit().

Signed-off-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: I56ac50b561c6ca91d3dc2d60c21c8d91d38f081b
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/823
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Aleksey Marchuk <alexeymar@mellanox.com>
This commit is contained in:
Shuhei Matsumoto 2020-02-10 20:03:41 -05:00 committed by Tomasz Zawadzki
parent 648d6cd5dd
commit e038e096e3
2 changed files with 37 additions and 2 deletions

View File

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

View File

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