thread: Add a mechanism to exit a lightweight thread
Lightweight threads may now be exited by calling spdk_thread_exit() within the thread. The framework polling the thread can release the resources associated with that lightweight thread by calling spdk_thread_destroy(). Change-Id: I6586b9d22556b3874fb113ce5402c6b1f371786e Signed-off-by: Ben Walker <benjamin.walker@intel.com> Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/455319 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Seth Howell <seth.howell5141@gmail.com> Reviewed-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com>
This commit is contained in:
parent
f658a867f9
commit
e036215fe9
@ -147,6 +147,7 @@ spdk_fio_cleanup_thread(struct spdk_fio_thread *fio_thread)
|
||||
spdk_set_thread(fio_thread->thread);
|
||||
|
||||
spdk_thread_exit(fio_thread->thread);
|
||||
spdk_thread_destroy(fio_thread->thread);
|
||||
free(fio_thread->iocq);
|
||||
free(fio_thread);
|
||||
}
|
||||
|
@ -206,8 +206,9 @@ void spdk_thread_lib_fini(void);
|
||||
struct spdk_thread *spdk_thread_create(const char *name, struct spdk_cpuset *cpumask);
|
||||
|
||||
/**
|
||||
* Release any resources related to the given thread and destroy it. Execution
|
||||
* continues on the current system thread after returning.
|
||||
* Mark the thread as exited, failing all future spdk_thread_poll() calls. May
|
||||
* only be called within an spdk poller or message.
|
||||
*
|
||||
*
|
||||
* \param thread The thread to destroy.
|
||||
*
|
||||
@ -216,6 +217,15 @@ struct spdk_thread *spdk_thread_create(const char *name, struct spdk_cpuset *cpu
|
||||
*/
|
||||
void spdk_thread_exit(struct spdk_thread *thread);
|
||||
|
||||
/**
|
||||
* Destroy a thread, releasing all of its resources. May only be called
|
||||
* on a thread previously marked as exited.
|
||||
*
|
||||
* \param thread The thread to destroy.
|
||||
*
|
||||
*/
|
||||
void spdk_thread_destroy(struct spdk_thread *thread);
|
||||
|
||||
/**
|
||||
* Return a pointer to this thread's context.
|
||||
*
|
||||
@ -255,7 +265,7 @@ struct spdk_thread *spdk_thread_get_from_ctx(void *ctx);
|
||||
* \param now The current time, in ticks. Optional. If 0 is passed, this
|
||||
* function may call spdk_get_ticks() to get the current time.
|
||||
*
|
||||
* \return 1 if work was done. 0 if no work was done. -1 if unknown.
|
||||
* \return 1 if work was done. 0 if no work was done. -1 if thread has exited.
|
||||
*/
|
||||
int spdk_thread_poll(struct spdk_thread *thread, uint32_t max_msgs, uint64_t now);
|
||||
|
||||
|
@ -258,6 +258,7 @@ _spdk_reactor_run(void *arg)
|
||||
|
||||
while (1) {
|
||||
uint64_t now;
|
||||
int rc;
|
||||
|
||||
/* For each loop through the reactor, capture the time. This time
|
||||
* is used for all threads. */
|
||||
@ -268,7 +269,11 @@ _spdk_reactor_run(void *arg)
|
||||
TAILQ_FOREACH_SAFE(lw_thread, &reactor->threads, link, tmp) {
|
||||
thread = spdk_thread_get_from_ctx(lw_thread);
|
||||
|
||||
spdk_thread_poll(thread, 0, now);
|
||||
rc = spdk_thread_poll(thread, 0, now);
|
||||
if (rc < 0) {
|
||||
TAILQ_REMOVE(&reactor->threads, lw_thread, link);
|
||||
spdk_thread_destroy(thread);
|
||||
}
|
||||
}
|
||||
|
||||
if (g_reactor_state != SPDK_REACTOR_STATE_RUNNING) {
|
||||
@ -286,7 +291,9 @@ _spdk_reactor_run(void *arg)
|
||||
TAILQ_FOREACH_SAFE(lw_thread, &reactor->threads, link, tmp) {
|
||||
thread = spdk_thread_get_from_ctx(lw_thread);
|
||||
TAILQ_REMOVE(&reactor->threads, lw_thread, link);
|
||||
spdk_set_thread(thread);
|
||||
spdk_thread_exit(thread);
|
||||
spdk_thread_destroy(thread);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -105,6 +105,8 @@ struct spdk_thread {
|
||||
TAILQ_ENTRY(spdk_thread) tailq;
|
||||
char *name;
|
||||
|
||||
bool exit;
|
||||
|
||||
struct spdk_cpuset *cpumask;
|
||||
|
||||
uint64_t tsc_last;
|
||||
@ -330,7 +332,19 @@ spdk_set_thread(struct spdk_thread *thread)
|
||||
void
|
||||
spdk_thread_exit(struct spdk_thread *thread)
|
||||
{
|
||||
SPDK_DEBUGLOG(SPDK_LOG_THREAD, "Freeing thread %s\n", thread->name);
|
||||
SPDK_DEBUGLOG(SPDK_LOG_THREAD, "Exit thread %s\n", thread->name);
|
||||
|
||||
assert(tls_thread == thread);
|
||||
|
||||
thread->exit = true;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_thread_destroy(struct spdk_thread *thread)
|
||||
{
|
||||
SPDK_DEBUGLOG(SPDK_LOG_THREAD, "Destroy thread %s\n", thread->name);
|
||||
|
||||
assert(thread->exit == true);
|
||||
|
||||
if (tls_thread == thread) {
|
||||
tls_thread = NULL;
|
||||
@ -400,6 +414,10 @@ _spdk_msg_queue_run_batch(struct spdk_thread *thread, uint32_t max_msgs)
|
||||
assert(msg != NULL);
|
||||
msg->fn(msg->arg);
|
||||
|
||||
if (thread->exit) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (thread->msg_cache_count < SPDK_MSG_MEMPOOL_CACHE_SIZE) {
|
||||
/* Insert the messages at the head. We want to re-use the hot
|
||||
* ones. */
|
||||
@ -459,6 +477,10 @@ spdk_thread_poll(struct spdk_thread *thread, uint32_t max_msgs, uint64_t now)
|
||||
active_pollers_head, tailq, tmp) {
|
||||
int poller_rc;
|
||||
|
||||
if (thread->exit) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (poller->state == SPDK_POLLER_STATE_UNREGISTERED) {
|
||||
TAILQ_REMOVE(&thread->active_pollers, poller, tailq);
|
||||
free(poller);
|
||||
@ -491,6 +513,10 @@ spdk_thread_poll(struct spdk_thread *thread, uint32_t max_msgs, uint64_t now)
|
||||
TAILQ_FOREACH_SAFE(poller, &thread->timer_pollers, tailq, tmp) {
|
||||
int timer_rc = 0;
|
||||
|
||||
if (thread->exit) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (poller->state == SPDK_POLLER_STATE_UNREGISTERED) {
|
||||
TAILQ_REMOVE(&thread->timer_pollers, poller, tailq);
|
||||
free(poller);
|
||||
|
@ -106,6 +106,7 @@ free_threads(void)
|
||||
for (i = 0; i < g_ut_num_threads; i++) {
|
||||
set_thread(i);
|
||||
spdk_thread_exit(g_ut_threads[i].thread);
|
||||
spdk_thread_destroy(g_ut_threads[i].thread);
|
||||
g_ut_threads[i].thread = NULL;
|
||||
}
|
||||
|
||||
|
@ -409,8 +409,13 @@ int main(int argc, char **argv)
|
||||
while (spdk_thread_poll(g_dispatch_thread, 0, 0) > 0) {}
|
||||
while (spdk_thread_poll(thread, 0, 0) > 0) {}
|
||||
|
||||
spdk_set_thread(thread);
|
||||
spdk_thread_exit(thread);
|
||||
spdk_thread_destroy(thread);
|
||||
|
||||
spdk_set_thread(g_dispatch_thread);
|
||||
spdk_thread_exit(g_dispatch_thread);
|
||||
spdk_thread_destroy(g_dispatch_thread);
|
||||
|
||||
spdk_thread_lib_fini();
|
||||
|
||||
|
@ -120,7 +120,9 @@ void
|
||||
test_free_ftl_dev(struct spdk_ftl_dev *dev)
|
||||
{
|
||||
SPDK_CU_ASSERT_FATAL(dev != NULL);
|
||||
spdk_set_thread(dev->core_thread.thread);
|
||||
spdk_thread_exit(dev->core_thread.thread);
|
||||
spdk_thread_destroy(dev->core_thread.thread);
|
||||
free(dev->punits);
|
||||
free(dev->bands);
|
||||
free(dev);
|
||||
|
@ -431,6 +431,7 @@ portal_grp_add_delete_case(void)
|
||||
CU_ASSERT(TAILQ_EMPTY(&g_spdk_iscsi.pg_head));
|
||||
|
||||
spdk_thread_exit(thread);
|
||||
spdk_thread_destroy(thread);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -491,6 +492,7 @@ portal_grp_add_delete_twice_case(void)
|
||||
|
||||
MOCK_CLEAR_P(spdk_sock_listen);
|
||||
spdk_thread_exit(thread);
|
||||
spdk_thread_destroy(thread);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -305,6 +305,7 @@ test_nvmf_tcp_create(void)
|
||||
CU_ASSERT_PTR_NULL(transport);
|
||||
|
||||
spdk_thread_exit(thread);
|
||||
spdk_thread_destroy(thread);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -334,6 +335,7 @@ test_nvmf_tcp_destroy(void)
|
||||
CU_ASSERT(spdk_nvmf_tcp_destroy(transport) == 0);
|
||||
|
||||
spdk_thread_exit(thread);
|
||||
spdk_thread_destroy(thread);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -369,6 +371,7 @@ test_nvmf_tcp_poll_group_create(void)
|
||||
spdk_nvmf_tcp_destroy(transport);
|
||||
|
||||
spdk_thread_exit(thread);
|
||||
spdk_thread_destroy(thread);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
@ -57,7 +57,9 @@ thread_alloc(void)
|
||||
spdk_thread_lib_init(NULL, 0);
|
||||
thread = spdk_thread_create(NULL, NULL);
|
||||
SPDK_CU_ASSERT_FATAL(thread != NULL);
|
||||
spdk_set_thread(thread);
|
||||
spdk_thread_exit(thread);
|
||||
spdk_thread_destroy(thread);
|
||||
spdk_thread_lib_fini();
|
||||
|
||||
/* Schedule callback exists */
|
||||
@ -67,7 +69,9 @@ thread_alloc(void)
|
||||
g_sched_rc = 0;
|
||||
thread = spdk_thread_create(NULL, NULL);
|
||||
SPDK_CU_ASSERT_FATAL(thread != NULL);
|
||||
spdk_set_thread(thread);
|
||||
spdk_thread_exit(thread);
|
||||
spdk_thread_destroy(thread);
|
||||
|
||||
/* Scheduling fails */
|
||||
g_sched_rc = -1;
|
||||
@ -381,6 +385,7 @@ thread_name(void)
|
||||
name = spdk_thread_get_name(thread);
|
||||
CU_ASSERT(name != NULL);
|
||||
spdk_thread_exit(thread);
|
||||
spdk_thread_destroy(thread);
|
||||
|
||||
/* Create thread named "test_thread" */
|
||||
thread = spdk_thread_create("test_thread", NULL);
|
||||
@ -391,6 +396,7 @@ thread_name(void)
|
||||
SPDK_CU_ASSERT_FATAL(name != NULL);
|
||||
CU_ASSERT(strcmp(name, "test_thread") == 0);
|
||||
spdk_thread_exit(thread);
|
||||
spdk_thread_destroy(thread);
|
||||
|
||||
spdk_thread_lib_fini();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user