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