Branch data Line data Source code
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 : 1344734 : set_thread(uintptr_t thread_id) 39 : : { 40 : 1344734 : g_ut_thread_id = thread_id; 41 [ + + ]: 1344734 : if (thread_id == INVALID_THREAD) { 42 : 670553 : spdk_set_thread(NULL); 43 : : } else { 44 : 674181 : spdk_set_thread(g_ut_threads[thread_id].thread); 45 : : } 46 : : 47 : 1344734 : } 48 : : 49 : : int 50 : 259 : allocate_threads(int num_threads) 51 : : { 52 : : struct spdk_thread *thread; 53 : : uint32_t i; 54 : : 55 : 259 : spdk_thread_lib_init(NULL, 0); 56 : : 57 : 259 : g_ut_num_threads = num_threads; 58 : : 59 : 259 : g_ut_threads = calloc(num_threads, sizeof(*g_ut_threads)); 60 [ - + ]: 259 : assert(g_ut_threads != NULL); 61 : : 62 [ + + ]: 775 : for (i = 0; i < g_ut_num_threads; i++) { 63 : 516 : set_thread(i); 64 : 516 : thread = spdk_thread_create(NULL, NULL); 65 [ - + ]: 516 : assert(thread != NULL); 66 : 516 : g_ut_threads[i].thread = thread; 67 : : } 68 : : 69 : 259 : set_thread(INVALID_THREAD); 70 : 259 : return 0; 71 : : } 72 : : 73 : : void 74 : 259 : free_threads(void) 75 : : { 76 : : uint32_t i, num_threads; 77 : : struct spdk_thread *thread; 78 : : 79 [ + + ]: 775 : for (i = 0; i < g_ut_num_threads; i++) { 80 : 516 : set_thread(i); 81 : 516 : thread = g_ut_threads[i].thread; 82 : 516 : spdk_thread_exit(thread); 83 : : } 84 : : 85 : 259 : num_threads = g_ut_num_threads; 86 : : 87 [ + + ]: 767 : while (num_threads != 0) { 88 [ + + ]: 1516 : for (i = 0; i < g_ut_num_threads; i++) { 89 : 1008 : set_thread(i); 90 : 1008 : thread = g_ut_threads[i].thread; 91 [ + + ]: 1008 : if (thread == NULL) { 92 : 10 : continue; 93 : : } 94 : : 95 [ + + ]: 998 : if (spdk_thread_is_exited(thread)) { 96 : 516 : g_ut_threads[i].thread = NULL; 97 : 516 : num_threads--; 98 : 516 : spdk_thread_destroy(thread); 99 : : } else { 100 : 482 : spdk_thread_poll(thread, 0, 0); 101 : : } 102 : : } 103 : : } 104 : : 105 : 259 : g_ut_num_threads = 0; 106 : 259 : free(g_ut_threads); 107 : 259 : g_ut_threads = NULL; 108 : : 109 : 259 : spdk_thread_lib_fini(); 110 : 259 : } 111 : : 112 : : bool 113 : 612 : poll_thread_times(uintptr_t thread_id, uint32_t max_polls) 114 : : { 115 : 612 : bool busy = false; 116 : 612 : struct ut_thread *thread = &g_ut_threads[thread_id]; 117 : : uintptr_t original_thread_id; 118 : 612 : uint32_t polls_executed = 0; 119 : : uint64_t now; 120 : : 121 [ - + ]: 612 : if (max_polls == 0) { 122 : : /* If max_polls is set to 0, 123 : : * poll until no operation is pending. */ 124 : 0 : return poll_thread(thread_id); 125 : : } 126 [ - + ]: 612 : assert(thread_id != (uintptr_t)INVALID_THREAD); 127 [ - + ]: 612 : assert(thread_id < g_ut_num_threads); 128 : : 129 : 612 : original_thread_id = g_ut_thread_id; 130 : 612 : set_thread(INVALID_THREAD); 131 : : 132 : 612 : now = spdk_get_ticks(); 133 [ + + ]: 1736 : while (polls_executed < max_polls) { 134 [ + + ]: 1124 : if (spdk_thread_poll(thread->thread, 1, now) > 0) { 135 : 952 : busy = true; 136 : : } 137 : 1124 : now = spdk_thread_get_last_tsc(thread->thread); 138 : 1124 : polls_executed++; 139 : : } 140 : : 141 : 612 : set_thread(original_thread_id); 142 : : 143 : 612 : return busy; 144 : : } 145 : : 146 : : bool 147 : 669682 : poll_thread(uintptr_t thread_id) 148 : : { 149 : 669682 : bool busy = false; 150 : 669682 : struct ut_thread *thread = &g_ut_threads[thread_id]; 151 : : uintptr_t original_thread_id; 152 : : uint64_t now; 153 : : 154 [ - + ]: 669682 : assert(thread_id != (uintptr_t)INVALID_THREAD); 155 [ - + ]: 669682 : assert(thread_id < g_ut_num_threads); 156 : : 157 : 669682 : original_thread_id = g_ut_thread_id; 158 : 669682 : set_thread(INVALID_THREAD); 159 : : 160 : 669682 : now = spdk_get_ticks(); 161 [ + + ]: 1091240 : while (spdk_thread_poll(thread->thread, 0, now) > 0) { 162 : 421558 : now = spdk_thread_get_last_tsc(thread->thread); 163 : 421558 : busy = true; 164 : : } 165 : : 166 : 669682 : set_thread(original_thread_id); 167 : : 168 : 669682 : return busy; 169 : : } 170 : : 171 : : void 172 : 443646 : poll_threads(void) 173 : : { 174 : 193948 : while (true) { 175 : 443950 : bool busy = false; 176 : : 177 [ + + ]: 1289008 : for (uint32_t i = 0; i < g_ut_num_threads; i++) { 178 [ + + + + ]: 845058 : busy = busy || poll_thread(i); 179 : : } 180 : : 181 [ + + ]: 443950 : if (!busy) { 182 : 250002 : break; 183 : : } 184 : : } 185 : 250002 : }