1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 */ 21 22 #include "uv.h" 23 #include "task.h" 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> /* memset */ 28 29 #ifdef __POSIX__ 30 #include <pthread.h> 31 #endif 32 33 struct getaddrinfo_req { 34 uv_thread_t thread_id; 35 unsigned int counter; 36 uv_loop_t* loop; 37 uv_getaddrinfo_t handle; 38 }; 39 40 41 struct fs_req { 42 uv_thread_t thread_id; 43 unsigned int counter; 44 uv_loop_t* loop; 45 uv_fs_t handle; 46 }; 47 48 49 struct test_thread { 50 uv_thread_t thread_id; 51 int thread_called; 52 }; 53 54 static void getaddrinfo_do(struct getaddrinfo_req* req); 55 static void getaddrinfo_cb(uv_getaddrinfo_t* handle, 56 int status, 57 struct addrinfo* res); 58 static void fs_do(struct fs_req* req); 59 static void fs_cb(uv_fs_t* handle); 60 61 static int thread_called; 62 static uv_key_t tls_key; 63 64 65 static void getaddrinfo_do(struct getaddrinfo_req* req) { 66 int r; 67 68 r = uv_getaddrinfo(req->loop, 69 &req->handle, 70 getaddrinfo_cb, 71 "localhost", 72 NULL, 73 NULL); 74 ASSERT(r == 0); 75 } 76 77 78 static void getaddrinfo_cb(uv_getaddrinfo_t* handle, 79 int status, 80 struct addrinfo* res) { 81 /* TODO(gengjiawen): Fix test on QEMU. */ 82 #if defined(__QEMU__) 83 RETURN_SKIP("Test does not currently work in QEMU"); 84 #endif 85 struct getaddrinfo_req* req; 86 87 ASSERT(status == 0); 88 89 req = container_of(handle, struct getaddrinfo_req, handle); 90 uv_freeaddrinfo(res); 91 92 if (--req->counter) 93 getaddrinfo_do(req); 94 } 95 96 97 static void fs_do(struct fs_req* req) { 98 int r; 99 100 r = uv_fs_stat(req->loop, &req->handle, ".", fs_cb); 101 ASSERT(r == 0); 102 } 103 104 105 static void fs_cb(uv_fs_t* handle) { 106 struct fs_req* req = container_of(handle, struct fs_req, handle); 107 108 uv_fs_req_cleanup(handle); 109 110 if (--req->counter) 111 fs_do(req); 112 } 113 114 115 static void do_work(void* arg) { 116 struct getaddrinfo_req getaddrinfo_reqs[4]; 117 struct fs_req fs_reqs[4]; 118 uv_loop_t loop; 119 size_t i; 120 struct test_thread* thread = arg; 121 122 ASSERT(0 == uv_loop_init(&loop)); 123 124 for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) { 125 struct getaddrinfo_req* req = getaddrinfo_reqs + i; 126 req->counter = 4; 127 req->loop = &loop; 128 getaddrinfo_do(req); 129 } 130 131 for (i = 0; i < ARRAY_SIZE(fs_reqs); i++) { 132 struct fs_req* req = fs_reqs + i; 133 req->counter = 4; 134 req->loop = &loop; 135 fs_do(req); 136 } 137 138 ASSERT(0 == uv_run(&loop, UV_RUN_DEFAULT)); 139 ASSERT(0 == uv_loop_close(&loop)); 140 thread->thread_called = 1; 141 } 142 143 144 static void thread_entry(void* arg) { 145 ASSERT(arg == (void *) 42); 146 thread_called++; 147 } 148 149 150 TEST_IMPL(thread_create) { 151 uv_thread_t tid; 152 int r; 153 154 r = uv_thread_create(&tid, thread_entry, (void *) 42); 155 ASSERT(r == 0); 156 157 r = uv_thread_join(&tid); 158 ASSERT(r == 0); 159 160 ASSERT(thread_called == 1); 161 162 return 0; 163 } 164 165 166 /* Hilariously bad test name. Run a lot of tasks in the thread pool and verify 167 * that each "finished" callback is run in its originating thread. 168 */ 169 TEST_IMPL(threadpool_multiple_event_loops) { 170 struct test_thread threads[8]; 171 size_t i; 172 int r; 173 174 memset(threads, 0, sizeof(threads)); 175 176 for (i = 0; i < ARRAY_SIZE(threads); i++) { 177 r = uv_thread_create(&threads[i].thread_id, do_work, &threads[i]); 178 ASSERT(r == 0); 179 } 180 181 for (i = 0; i < ARRAY_SIZE(threads); i++) { 182 r = uv_thread_join(&threads[i].thread_id); 183 ASSERT(r == 0); 184 ASSERT(threads[i].thread_called == 1); 185 } 186 187 return 0; 188 } 189 190 191 static void tls_thread(void* arg) { 192 ASSERT(NULL == uv_key_get(&tls_key)); 193 uv_key_set(&tls_key, arg); 194 ASSERT(arg == uv_key_get(&tls_key)); 195 uv_key_set(&tls_key, NULL); 196 ASSERT(NULL == uv_key_get(&tls_key)); 197 } 198 199 200 TEST_IMPL(thread_local_storage) { 201 char name[] = "main"; 202 uv_thread_t threads[2]; 203 ASSERT(0 == uv_key_create(&tls_key)); 204 ASSERT(NULL == uv_key_get(&tls_key)); 205 uv_key_set(&tls_key, name); 206 ASSERT(name == uv_key_get(&tls_key)); 207 ASSERT(0 == uv_thread_create(threads + 0, tls_thread, threads + 0)); 208 ASSERT(0 == uv_thread_create(threads + 1, tls_thread, threads + 1)); 209 ASSERT(0 == uv_thread_join(threads + 0)); 210 ASSERT(0 == uv_thread_join(threads + 1)); 211 uv_key_delete(&tls_key); 212 return 0; 213 } 214 215 216 static void thread_check_stack(void* arg) { 217 #if defined(__APPLE__) 218 size_t expected; 219 expected = arg == NULL ? 0 : ((uv_thread_options_t*)arg)->stack_size; 220 /* 512 kB is the default stack size of threads other than the main thread 221 * on MacOS. */ 222 if (expected == 0) 223 expected = 512 * 1024; 224 ASSERT(pthread_get_stacksize_np(pthread_self()) >= expected); 225 #elif defined(__linux__) && defined(__GLIBC__) 226 size_t expected; 227 struct rlimit lim; 228 size_t stack_size; 229 pthread_attr_t attr; 230 ASSERT(0 == getrlimit(RLIMIT_STACK, &lim)); 231 if (lim.rlim_cur == RLIM_INFINITY) 232 lim.rlim_cur = 2 << 20; /* glibc default. */ 233 ASSERT(0 == pthread_getattr_np(pthread_self(), &attr)); 234 ASSERT(0 == pthread_attr_getstacksize(&attr, &stack_size)); 235 expected = arg == NULL ? 0 : ((uv_thread_options_t*)arg)->stack_size; 236 if (expected == 0) 237 expected = (size_t)lim.rlim_cur; 238 ASSERT(stack_size >= expected); 239 ASSERT(0 == pthread_attr_destroy(&attr)); 240 #endif 241 } 242 243 244 TEST_IMPL(thread_stack_size) { 245 uv_thread_t thread; 246 ASSERT(0 == uv_thread_create(&thread, thread_check_stack, NULL)); 247 ASSERT(0 == uv_thread_join(&thread)); 248 return 0; 249 } 250 251 TEST_IMPL(thread_stack_size_explicit) { 252 uv_thread_t thread; 253 uv_thread_options_t options; 254 255 options.flags = UV_THREAD_HAS_STACK_SIZE; 256 options.stack_size = 1024 * 1024; 257 ASSERT(0 == uv_thread_create_ex(&thread, &options, 258 thread_check_stack, &options)); 259 ASSERT(0 == uv_thread_join(&thread)); 260 261 options.stack_size = 8 * 1024 * 1024; /* larger than most default os sizes */ 262 ASSERT(0 == uv_thread_create_ex(&thread, &options, 263 thread_check_stack, &options)); 264 ASSERT(0 == uv_thread_join(&thread)); 265 266 options.stack_size = 0; 267 ASSERT(0 == uv_thread_create_ex(&thread, &options, 268 thread_check_stack, &options)); 269 ASSERT(0 == uv_thread_join(&thread)); 270 271 #ifdef PTHREAD_STACK_MIN 272 options.stack_size = PTHREAD_STACK_MIN - 42; /* unaligned size */ 273 ASSERT(0 == uv_thread_create_ex(&thread, &options, 274 thread_check_stack, &options)); 275 ASSERT(0 == uv_thread_join(&thread)); 276 277 options.stack_size = PTHREAD_STACK_MIN / 2 - 42; /* unaligned size */ 278 ASSERT(0 == uv_thread_create_ex(&thread, &options, 279 thread_check_stack, &options)); 280 ASSERT(0 == uv_thread_join(&thread)); 281 #endif 282 283 /* unaligned size, should be larger than PTHREAD_STACK_MIN */ 284 options.stack_size = 1234567; 285 ASSERT(0 == uv_thread_create_ex(&thread, &options, 286 thread_check_stack, &options)); 287 ASSERT(0 == uv_thread_join(&thread)); 288 289 return 0; 290 } 291