xref: /spdk/test/common/lib/ut_multithread.c (revision ae431e31c1adfb2454cf5063338af3df86982221)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2017 Intel Corporation.
3899eb5f1SSeth Howell  *   All rights reserved.
4899eb5f1SSeth Howell  */
5899eb5f1SSeth Howell 
6*ae431e31SKonrad Sztyber #include "spdk_internal/cunit.h"
7a83f91c2SBen Walker #include "spdk/thread.h"
8899eb5f1SSeth Howell #include "spdk_internal/mock.h"
9899eb5f1SSeth Howell 
103c981508SBen Walker #include "common/lib/test_env.c"
113c981508SBen Walker 
12899eb5f1SSeth Howell static uint32_t g_ut_num_threads;
13899eb5f1SSeth Howell 
14899eb5f1SSeth Howell int allocate_threads(int num_threads);
15899eb5f1SSeth Howell void free_threads(void);
16899eb5f1SSeth Howell void poll_threads(void);
173c981508SBen Walker bool poll_thread(uintptr_t thread_id);
18d7aff25dSTomasz Zawadzki bool poll_thread_times(uintptr_t thread_id, uint32_t max_polls);
19899eb5f1SSeth Howell 
20899eb5f1SSeth Howell struct ut_msg {
217b940538SBen Walker 	spdk_msg_fn		fn;
22899eb5f1SSeth Howell 	void			*ctx;
23899eb5f1SSeth Howell 	TAILQ_ENTRY(ut_msg)	link;
24899eb5f1SSeth Howell };
25899eb5f1SSeth Howell 
26899eb5f1SSeth Howell struct ut_thread {
27899eb5f1SSeth Howell 	struct spdk_thread	*thread;
28899eb5f1SSeth Howell 	struct spdk_io_channel	*ch;
29899eb5f1SSeth Howell };
30899eb5f1SSeth Howell 
31899eb5f1SSeth Howell struct ut_thread *g_ut_threads;
32899eb5f1SSeth Howell 
33f56b2300SBen Walker #define INVALID_THREAD 0x1000
34f56b2300SBen Walker 
35515733caSShuhei Matsumoto static uint64_t g_ut_thread_id = INVALID_THREAD;
36899eb5f1SSeth Howell 
37899eb5f1SSeth Howell static void
set_thread(uintptr_t thread_id)38899eb5f1SSeth Howell set_thread(uintptr_t thread_id)
39899eb5f1SSeth Howell {
40515733caSShuhei Matsumoto 	g_ut_thread_id = thread_id;
41f56b2300SBen Walker 	if (thread_id == INVALID_THREAD) {
42605e530aSBen Walker 		spdk_set_thread(NULL);
43f56b2300SBen Walker 	} else {
44605e530aSBen Walker 		spdk_set_thread(g_ut_threads[thread_id].thread);
45f56b2300SBen Walker 	}
46605e530aSBen Walker 
47899eb5f1SSeth Howell }
48899eb5f1SSeth Howell 
49899eb5f1SSeth Howell int
allocate_threads(int num_threads)50899eb5f1SSeth Howell allocate_threads(int num_threads)
51899eb5f1SSeth Howell {
52899eb5f1SSeth Howell 	struct spdk_thread *thread;
53899eb5f1SSeth Howell 	uint32_t i;
54899eb5f1SSeth Howell 
55df912930SBen Walker 	spdk_thread_lib_init(NULL, 0);
56df912930SBen Walker 
57899eb5f1SSeth Howell 	g_ut_num_threads = num_threads;
58899eb5f1SSeth Howell 
59899eb5f1SSeth Howell 	g_ut_threads = calloc(num_threads, sizeof(*g_ut_threads));
60536beb13SBen Walker 	assert(g_ut_threads != NULL);
61899eb5f1SSeth Howell 
62899eb5f1SSeth Howell 	for (i = 0; i < g_ut_num_threads; i++) {
63899eb5f1SSeth Howell 		set_thread(i);
645d0b5e2cSBen Walker 		thread = spdk_thread_create(NULL, NULL);
65536beb13SBen Walker 		assert(thread != NULL);
66899eb5f1SSeth Howell 		g_ut_threads[i].thread = thread;
67899eb5f1SSeth Howell 	}
68899eb5f1SSeth Howell 
69f56b2300SBen Walker 	set_thread(INVALID_THREAD);
70899eb5f1SSeth Howell 	return 0;
71899eb5f1SSeth Howell }
72899eb5f1SSeth Howell 
73899eb5f1SSeth Howell void
free_threads(void)74899eb5f1SSeth Howell free_threads(void)
75899eb5f1SSeth Howell {
76e9aec674SShuhei Matsumoto 	uint32_t i, num_threads;
77e7ead00bSShuhei Matsumoto 	struct spdk_thread *thread;
78899eb5f1SSeth Howell 
79899eb5f1SSeth Howell 	for (i = 0; i < g_ut_num_threads; i++) {
80899eb5f1SSeth Howell 		set_thread(i);
81e7ead00bSShuhei Matsumoto 		thread = g_ut_threads[i].thread;
82e9aec674SShuhei Matsumoto 		spdk_thread_exit(thread);
83e9aec674SShuhei Matsumoto 	}
84e9aec674SShuhei Matsumoto 
85e9aec674SShuhei Matsumoto 	num_threads = g_ut_num_threads;
86e9aec674SShuhei Matsumoto 
87e9aec674SShuhei Matsumoto 	while (num_threads != 0) {
88e9aec674SShuhei Matsumoto 		for (i = 0; i < g_ut_num_threads; i++) {
89e9aec674SShuhei Matsumoto 			set_thread(i);
90e9aec674SShuhei Matsumoto 			thread = g_ut_threads[i].thread;
91e9aec674SShuhei Matsumoto 			if (thread == NULL) {
92e9aec674SShuhei Matsumoto 				continue;
93e9aec674SShuhei Matsumoto 			}
94e9aec674SShuhei Matsumoto 
95e9aec674SShuhei Matsumoto 			if (spdk_thread_is_exited(thread)) {
96e9aec674SShuhei Matsumoto 				g_ut_threads[i].thread = NULL;
97e9aec674SShuhei Matsumoto 				num_threads--;
98e9aec674SShuhei Matsumoto 				spdk_thread_destroy(thread);
99e9aec674SShuhei Matsumoto 			} else {
100e7ead00bSShuhei Matsumoto 				spdk_thread_poll(thread, 0, 0);
101e7ead00bSShuhei Matsumoto 			}
102e9aec674SShuhei Matsumoto 		}
103899eb5f1SSeth Howell 	}
104899eb5f1SSeth Howell 
105899eb5f1SSeth Howell 	g_ut_num_threads = 0;
106899eb5f1SSeth Howell 	free(g_ut_threads);
107899eb5f1SSeth Howell 	g_ut_threads = NULL;
108df912930SBen Walker 
109df912930SBen Walker 	spdk_thread_lib_fini();
110899eb5f1SSeth Howell }
111899eb5f1SSeth Howell 
1123c981508SBen Walker bool
poll_thread_times(uintptr_t thread_id,uint32_t max_polls)113d7aff25dSTomasz Zawadzki poll_thread_times(uintptr_t thread_id, uint32_t max_polls)
114d7aff25dSTomasz Zawadzki {
115d7aff25dSTomasz Zawadzki 	bool busy = false;
116d7aff25dSTomasz Zawadzki 	struct ut_thread *thread = &g_ut_threads[thread_id];
117d7aff25dSTomasz Zawadzki 	uintptr_t original_thread_id;
118d7aff25dSTomasz Zawadzki 	uint32_t polls_executed = 0;
1192139be15SShuhei Matsumoto 	uint64_t now;
120d7aff25dSTomasz Zawadzki 
121d7aff25dSTomasz Zawadzki 	if (max_polls == 0) {
122d7aff25dSTomasz Zawadzki 		/* If max_polls is set to 0,
123d7aff25dSTomasz Zawadzki 		 * poll until no operation is pending. */
124d7aff25dSTomasz Zawadzki 		return poll_thread(thread_id);
125d7aff25dSTomasz Zawadzki 	}
126d7aff25dSTomasz Zawadzki 	assert(thread_id != (uintptr_t)INVALID_THREAD);
127d7aff25dSTomasz Zawadzki 	assert(thread_id < g_ut_num_threads);
128d7aff25dSTomasz Zawadzki 
129515733caSShuhei Matsumoto 	original_thread_id = g_ut_thread_id;
130d7aff25dSTomasz Zawadzki 	set_thread(INVALID_THREAD);
131d7aff25dSTomasz Zawadzki 
1322139be15SShuhei Matsumoto 	now = spdk_get_ticks();
133d7aff25dSTomasz Zawadzki 	while (polls_executed < max_polls) {
1342139be15SShuhei Matsumoto 		if (spdk_thread_poll(thread->thread, 1, now) > 0) {
135d7aff25dSTomasz Zawadzki 			busy = true;
136d7aff25dSTomasz Zawadzki 		}
1372139be15SShuhei Matsumoto 		now = spdk_thread_get_last_tsc(thread->thread);
138d7aff25dSTomasz Zawadzki 		polls_executed++;
139d7aff25dSTomasz Zawadzki 	}
140d7aff25dSTomasz Zawadzki 
141d7aff25dSTomasz Zawadzki 	set_thread(original_thread_id);
142d7aff25dSTomasz Zawadzki 
143d7aff25dSTomasz Zawadzki 	return busy;
144d7aff25dSTomasz Zawadzki }
145d7aff25dSTomasz Zawadzki 
146d7aff25dSTomasz Zawadzki bool
poll_thread(uintptr_t thread_id)147899eb5f1SSeth Howell poll_thread(uintptr_t thread_id)
148899eb5f1SSeth Howell {
1493c981508SBen Walker 	bool busy = false;
150899eb5f1SSeth Howell 	struct ut_thread *thread = &g_ut_threads[thread_id];
151899eb5f1SSeth Howell 	uintptr_t original_thread_id;
1522139be15SShuhei Matsumoto 	uint64_t now;
153899eb5f1SSeth Howell 
1549bef42f2SBen Walker 	assert(thread_id != (uintptr_t)INVALID_THREAD);
1559bef42f2SBen Walker 	assert(thread_id < g_ut_num_threads);
156899eb5f1SSeth Howell 
157515733caSShuhei Matsumoto 	original_thread_id = g_ut_thread_id;
158605e530aSBen Walker 	set_thread(INVALID_THREAD);
159899eb5f1SSeth Howell 
1602139be15SShuhei Matsumoto 	now = spdk_get_ticks();
1612139be15SShuhei Matsumoto 	while (spdk_thread_poll(thread->thread, 0, now) > 0) {
1622139be15SShuhei Matsumoto 		now = spdk_thread_get_last_tsc(thread->thread);
1633c981508SBen Walker 		busy = true;
164899eb5f1SSeth Howell 	}
165899eb5f1SSeth Howell 
166899eb5f1SSeth Howell 	set_thread(original_thread_id);
167899eb5f1SSeth Howell 
1683c981508SBen Walker 	return busy;
169899eb5f1SSeth Howell }
170899eb5f1SSeth Howell 
171899eb5f1SSeth Howell void
poll_threads(void)172899eb5f1SSeth Howell poll_threads(void)
173899eb5f1SSeth Howell {
174899eb5f1SSeth Howell 	while (true) {
1753c981508SBen Walker 		bool busy = false;
176899eb5f1SSeth Howell 
1773c981508SBen Walker 		for (uint32_t i = 0; i < g_ut_num_threads; i++) {
1783c981508SBen Walker 			busy = busy || poll_thread(i);
179899eb5f1SSeth Howell 		}
180899eb5f1SSeth Howell 
1813c981508SBen Walker 		if (!busy) {
182899eb5f1SSeth Howell 			break;
183899eb5f1SSeth Howell 		}
184899eb5f1SSeth Howell 	}
185899eb5f1SSeth Howell }
186