Commit a12aae4c authored by Shuhei Matsumoto's avatar Shuhei Matsumoto Committed by Tomasz Zawadzki
Browse files

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: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Change-Id: Ied8f58a2023a3bbe098530810fd3288bef93c3e7
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/1644


Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarAleksey Marchuk <alexeymar@mellanox.com>
Tested-by: default avatarSPDK CI Jenkins <sys_sgci@intel.com>
parent e9aec674
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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];
};
+12 −2
Original line number Diff line number Diff line
@@ -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);
+35 −1
Original line number Diff line number Diff line
@@ -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();
}