1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright (C) 2017 Intel Corporation. 3 * All rights reserved. 4 */ 5 6 #include "spdk_internal/cunit.h" 7 #include "spdk/thread.h" 8 #include "spdk_internal/mock.h" 9 10 #include "common/lib/test_env.c" 11 12 static uint32_t g_ut_num_threads; 13 14 int allocate_threads(int num_threads); 15 void free_threads(void); 16 void poll_threads(void); 17 bool poll_thread(uintptr_t thread_id); 18 bool poll_thread_times(uintptr_t thread_id, uint32_t max_polls); 19 20 struct ut_msg { 21 spdk_msg_fn fn; 22 void *ctx; 23 TAILQ_ENTRY(ut_msg) link; 24 }; 25 26 struct ut_thread { 27 struct spdk_thread *thread; 28 struct spdk_io_channel *ch; 29 }; 30 31 struct ut_thread *g_ut_threads; 32 33 #define INVALID_THREAD 0x1000 34 35 static uint64_t g_ut_thread_id = INVALID_THREAD; 36 37 static void 38 set_thread(uintptr_t thread_id) 39 { 40 g_ut_thread_id = thread_id; 41 if (thread_id == INVALID_THREAD) { 42 spdk_set_thread(NULL); 43 } else { 44 spdk_set_thread(g_ut_threads[thread_id].thread); 45 } 46 47 } 48 49 int 50 allocate_threads(int num_threads) 51 { 52 struct spdk_thread *thread; 53 uint32_t i; 54 55 spdk_thread_lib_init(NULL, 0); 56 57 g_ut_num_threads = num_threads; 58 59 g_ut_threads = calloc(num_threads, sizeof(*g_ut_threads)); 60 assert(g_ut_threads != NULL); 61 62 for (i = 0; i < g_ut_num_threads; i++) { 63 set_thread(i); 64 thread = spdk_thread_create(NULL, NULL); 65 assert(thread != NULL); 66 g_ut_threads[i].thread = thread; 67 } 68 69 set_thread(INVALID_THREAD); 70 return 0; 71 } 72 73 void 74 free_threads(void) 75 { 76 uint32_t i, num_threads; 77 struct spdk_thread *thread; 78 79 for (i = 0; i < g_ut_num_threads; i++) { 80 set_thread(i); 81 thread = g_ut_threads[i].thread; 82 spdk_thread_exit(thread); 83 } 84 85 num_threads = g_ut_num_threads; 86 87 while (num_threads != 0) { 88 for (i = 0; i < g_ut_num_threads; i++) { 89 set_thread(i); 90 thread = g_ut_threads[i].thread; 91 if (thread == NULL) { 92 continue; 93 } 94 95 if (spdk_thread_is_exited(thread)) { 96 g_ut_threads[i].thread = NULL; 97 num_threads--; 98 spdk_thread_destroy(thread); 99 } else { 100 spdk_thread_poll(thread, 0, 0); 101 } 102 } 103 } 104 105 g_ut_num_threads = 0; 106 free(g_ut_threads); 107 g_ut_threads = NULL; 108 109 spdk_thread_lib_fini(); 110 } 111 112 bool 113 poll_thread_times(uintptr_t thread_id, uint32_t max_polls) 114 { 115 bool busy = false; 116 struct ut_thread *thread = &g_ut_threads[thread_id]; 117 uintptr_t original_thread_id; 118 uint32_t polls_executed = 0; 119 uint64_t now; 120 121 if (max_polls == 0) { 122 /* If max_polls is set to 0, 123 * poll until no operation is pending. */ 124 return poll_thread(thread_id); 125 } 126 assert(thread_id != (uintptr_t)INVALID_THREAD); 127 assert(thread_id < g_ut_num_threads); 128 129 original_thread_id = g_ut_thread_id; 130 set_thread(INVALID_THREAD); 131 132 now = spdk_get_ticks(); 133 while (polls_executed < max_polls) { 134 if (spdk_thread_poll(thread->thread, 1, now) > 0) { 135 busy = true; 136 } 137 now = spdk_thread_get_last_tsc(thread->thread); 138 polls_executed++; 139 } 140 141 set_thread(original_thread_id); 142 143 return busy; 144 } 145 146 bool 147 poll_thread(uintptr_t thread_id) 148 { 149 bool busy = false; 150 struct ut_thread *thread = &g_ut_threads[thread_id]; 151 uintptr_t original_thread_id; 152 uint64_t now; 153 154 assert(thread_id != (uintptr_t)INVALID_THREAD); 155 assert(thread_id < g_ut_num_threads); 156 157 original_thread_id = g_ut_thread_id; 158 set_thread(INVALID_THREAD); 159 160 now = spdk_get_ticks(); 161 while (spdk_thread_poll(thread->thread, 0, now) > 0) { 162 now = spdk_thread_get_last_tsc(thread->thread); 163 busy = true; 164 } 165 166 set_thread(original_thread_id); 167 168 return busy; 169 } 170 171 void 172 poll_threads(void) 173 { 174 while (true) { 175 bool busy = false; 176 177 for (uint32_t i = 0; i < g_ut_num_threads; i++) { 178 busy = busy || poll_thread(i); 179 } 180 181 if (!busy) { 182 break; 183 } 184 } 185 } 186