1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "spdk_cunit.h" 35 #include "spdk/thread.h" 36 #include "spdk_internal/mock.h" 37 #include "spdk_internal/thread.h" 38 39 #include "common/lib/test_env.c" 40 41 static uint32_t g_ut_num_threads; 42 43 int allocate_threads(int num_threads); 44 void free_threads(void); 45 void poll_threads(void); 46 bool poll_thread(uintptr_t thread_id); 47 48 struct ut_msg { 49 spdk_msg_fn fn; 50 void *ctx; 51 TAILQ_ENTRY(ut_msg) link; 52 }; 53 54 struct ut_thread { 55 struct spdk_thread *thread; 56 struct spdk_io_channel *ch; 57 }; 58 59 struct ut_thread *g_ut_threads; 60 61 #define INVALID_THREAD 0x1000 62 63 static uintptr_t g_thread_id = INVALID_THREAD; 64 65 static void 66 set_thread(uintptr_t thread_id) 67 { 68 g_thread_id = thread_id; 69 if (thread_id == INVALID_THREAD) { 70 MOCK_CLEAR(pthread_self); 71 spdk_set_thread(NULL); 72 } else { 73 MOCK_SET(pthread_self, (pthread_t)thread_id); 74 spdk_set_thread(g_ut_threads[thread_id].thread); 75 } 76 77 } 78 79 int 80 allocate_threads(int num_threads) 81 { 82 struct spdk_thread *thread; 83 uint32_t i; 84 85 g_ut_num_threads = num_threads; 86 87 g_ut_threads = calloc(num_threads, sizeof(*g_ut_threads)); 88 SPDK_CU_ASSERT_FATAL(g_ut_threads != NULL); 89 90 for (i = 0; i < g_ut_num_threads; i++) { 91 set_thread(i); 92 thread = spdk_allocate_thread(NULL, NULL, NULL, NULL, NULL); 93 SPDK_CU_ASSERT_FATAL(thread != NULL); 94 g_ut_threads[i].thread = thread; 95 } 96 97 set_thread(INVALID_THREAD); 98 return 0; 99 } 100 101 void 102 free_threads(void) 103 { 104 uint32_t i; 105 106 for (i = 0; i < g_ut_num_threads; i++) { 107 set_thread(i); 108 spdk_free_thread(); 109 } 110 111 g_ut_num_threads = 0; 112 free(g_ut_threads); 113 g_ut_threads = NULL; 114 } 115 116 bool 117 poll_thread(uintptr_t thread_id) 118 { 119 bool busy = false; 120 struct ut_thread *thread = &g_ut_threads[thread_id]; 121 uintptr_t original_thread_id; 122 123 CU_ASSERT(thread_id != (uintptr_t)INVALID_THREAD); 124 CU_ASSERT(thread_id < g_ut_num_threads); 125 126 original_thread_id = g_thread_id; 127 set_thread(INVALID_THREAD); 128 129 while (spdk_thread_poll(thread->thread, 0) > 0) { 130 busy = true; 131 } 132 133 set_thread(original_thread_id); 134 135 return busy; 136 } 137 138 void 139 poll_threads(void) 140 { 141 while (true) { 142 bool busy = false; 143 144 for (uint32_t i = 0; i < g_ut_num_threads; i++) { 145 busy = busy || poll_thread(i); 146 } 147 148 if (!busy) { 149 break; 150 } 151 } 152 } 153