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
getaddrinfo_do(struct getaddrinfo_req * req)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_OK(r);
75 }
76
77
getaddrinfo_cb(uv_getaddrinfo_t * handle,int status,struct addrinfo * res)78 static void getaddrinfo_cb(uv_getaddrinfo_t* handle,
79 int status,
80 struct addrinfo* res) {
81 struct getaddrinfo_req* req;
82
83 ASSERT_OK(status);
84
85 req = container_of(handle, struct getaddrinfo_req, handle);
86 uv_freeaddrinfo(res);
87
88 if (--req->counter)
89 getaddrinfo_do(req);
90 }
91
92
fs_do(struct fs_req * req)93 static void fs_do(struct fs_req* req) {
94 int r;
95
96 r = uv_fs_stat(req->loop, &req->handle, ".", fs_cb);
97 ASSERT_OK(r);
98 }
99
100
fs_cb(uv_fs_t * handle)101 static void fs_cb(uv_fs_t* handle) {
102 struct fs_req* req = container_of(handle, struct fs_req, handle);
103
104 uv_fs_req_cleanup(handle);
105
106 if (--req->counter)
107 fs_do(req);
108 }
109
110
do_work(void * arg)111 static void do_work(void* arg) {
112 struct getaddrinfo_req getaddrinfo_reqs[4];
113 struct fs_req fs_reqs[4];
114 uv_loop_t loop;
115 size_t i;
116 struct test_thread* thread = arg;
117
118 ASSERT_OK(uv_loop_init(&loop));
119
120 for (i = 0; i < ARRAY_SIZE(getaddrinfo_reqs); i++) {
121 struct getaddrinfo_req* req = getaddrinfo_reqs + i;
122 req->counter = 4;
123 req->loop = &loop;
124 getaddrinfo_do(req);
125 }
126
127 for (i = 0; i < ARRAY_SIZE(fs_reqs); i++) {
128 struct fs_req* req = fs_reqs + i;
129 req->counter = 4;
130 req->loop = &loop;
131 fs_do(req);
132 }
133
134 ASSERT_OK(uv_run(&loop, UV_RUN_DEFAULT));
135 ASSERT_OK(uv_loop_close(&loop));
136 thread->thread_called = 1;
137 }
138
139
thread_entry(void * arg)140 static void thread_entry(void* arg) {
141 ASSERT_PTR_EQ(arg, (void *) 42);
142 thread_called++;
143 }
144
145
TEST_IMPL(thread_create)146 TEST_IMPL(thread_create) {
147 uv_thread_t tid;
148 int r;
149
150 r = uv_thread_create(&tid, thread_entry, (void *) 42);
151 ASSERT_OK(r);
152
153 r = uv_thread_join(&tid);
154 ASSERT_OK(r);
155
156 ASSERT_EQ(1, thread_called);
157
158 return 0;
159 }
160
161
162 /* Hilariously bad test name. Run a lot of tasks in the thread pool and verify
163 * that each "finished" callback is run in its originating thread.
164 */
TEST_IMPL(threadpool_multiple_event_loops)165 TEST_IMPL(threadpool_multiple_event_loops) {
166 /* TODO(gengjiawen): Fix test on QEMU. */
167 #if defined(__QEMU__)
168 RETURN_SKIP("Test does not currently work in QEMU");
169 #endif
170
171 struct test_thread threads[8];
172 size_t i;
173 int r;
174
175 memset(threads, 0, sizeof(threads));
176
177 for (i = 0; i < ARRAY_SIZE(threads); i++) {
178 r = uv_thread_create(&threads[i].thread_id, do_work, &threads[i]);
179 ASSERT_OK(r);
180 }
181
182 for (i = 0; i < ARRAY_SIZE(threads); i++) {
183 r = uv_thread_join(&threads[i].thread_id);
184 ASSERT_OK(r);
185 ASSERT_EQ(1, threads[i].thread_called);
186 }
187
188 return 0;
189 }
190
191
tls_thread(void * arg)192 static void tls_thread(void* arg) {
193 ASSERT_NULL(uv_key_get(&tls_key));
194 uv_key_set(&tls_key, arg);
195 ASSERT_PTR_EQ(arg, uv_key_get(&tls_key));
196 uv_key_set(&tls_key, NULL);
197 ASSERT_NULL(uv_key_get(&tls_key));
198 }
199
200
TEST_IMPL(thread_local_storage)201 TEST_IMPL(thread_local_storage) {
202 char name[] = "main";
203 uv_thread_t threads[2];
204 ASSERT_OK(uv_key_create(&tls_key));
205 ASSERT_NULL(uv_key_get(&tls_key));
206 uv_key_set(&tls_key, name);
207 ASSERT_PTR_EQ(name, uv_key_get(&tls_key));
208 ASSERT_OK(uv_thread_create(threads + 0, tls_thread, threads + 0));
209 ASSERT_OK(uv_thread_create(threads + 1, tls_thread, threads + 1));
210 ASSERT_OK(uv_thread_join(threads + 0));
211 ASSERT_OK(uv_thread_join(threads + 1));
212 uv_key_delete(&tls_key);
213 return 0;
214 }
215
216
thread_check_stack(void * arg)217 static void thread_check_stack(void* arg) {
218 #if defined(__APPLE__)
219 size_t expected;
220 expected = arg == NULL ? 0 : ((uv_thread_options_t*)arg)->stack_size;
221 /* 512 kB is the default stack size of threads other than the main thread
222 * on MacOS. */
223 if (expected == 0)
224 expected = 512 * 1024;
225 ASSERT_GE(pthread_get_stacksize_np(pthread_self()), expected);
226 #elif defined(__linux__) && defined(__GLIBC__)
227 size_t expected;
228 struct rlimit lim;
229 size_t stack_size;
230 pthread_attr_t attr;
231 ASSERT_OK(getrlimit(RLIMIT_STACK, &lim));
232 if (lim.rlim_cur == RLIM_INFINITY)
233 lim.rlim_cur = 2 << 20; /* glibc default. */
234 ASSERT_OK(pthread_getattr_np(pthread_self(), &attr));
235 ASSERT_OK(pthread_attr_getstacksize(&attr, &stack_size));
236 expected = arg == NULL ? 0 : ((uv_thread_options_t*)arg)->stack_size;
237 if (expected == 0)
238 expected = (size_t)lim.rlim_cur;
239 ASSERT_GE(stack_size, expected);
240 ASSERT_OK(pthread_attr_destroy(&attr));
241 #endif
242 }
243
244
TEST_IMPL(thread_stack_size)245 TEST_IMPL(thread_stack_size) {
246 uv_thread_t thread;
247 ASSERT_OK(uv_thread_create(&thread, thread_check_stack, NULL));
248 ASSERT_OK(uv_thread_join(&thread));
249 return 0;
250 }
251
TEST_IMPL(thread_stack_size_explicit)252 TEST_IMPL(thread_stack_size_explicit) {
253 uv_thread_t thread;
254 uv_thread_options_t options;
255
256 options.flags = UV_THREAD_HAS_STACK_SIZE;
257 options.stack_size = 1024 * 1024;
258 ASSERT_OK(uv_thread_create_ex(&thread, &options,
259 thread_check_stack, &options));
260 ASSERT_OK(uv_thread_join(&thread));
261
262 options.stack_size = 8 * 1024 * 1024; /* larger than most default os sizes */
263 ASSERT_OK(uv_thread_create_ex(&thread, &options,
264 thread_check_stack, &options));
265 ASSERT_OK(uv_thread_join(&thread));
266
267 options.stack_size = 0;
268 ASSERT_OK(uv_thread_create_ex(&thread, &options,
269 thread_check_stack, &options));
270 ASSERT_OK(uv_thread_join(&thread));
271
272 options.stack_size = 42;
273 ASSERT_OK(uv_thread_create_ex(&thread, &options,
274 thread_check_stack, &options));
275 ASSERT_OK(uv_thread_join(&thread));
276
277 #ifdef PTHREAD_STACK_MIN
278 options.stack_size = PTHREAD_STACK_MIN - 42; /* unaligned size */
279 ASSERT_OK(uv_thread_create_ex(&thread, &options,
280 thread_check_stack, &options));
281 ASSERT_OK(uv_thread_join(&thread));
282
283 options.stack_size = PTHREAD_STACK_MIN / 2 - 42; /* unaligned size */
284 ASSERT_OK(uv_thread_create_ex(&thread, &options,
285 thread_check_stack, &options));
286 ASSERT_OK(uv_thread_join(&thread));
287 #endif
288
289 /* unaligned size, should be larger than PTHREAD_STACK_MIN */
290 options.stack_size = 1234567;
291 ASSERT_OK(uv_thread_create_ex(&thread, &options,
292 thread_check_stack, &options));
293 ASSERT_OK(uv_thread_join(&thread));
294
295 return 0;
296 }
297
thread_detach_cb(void * arg)298 static void thread_detach_cb(void* arg) {}
299
TEST_IMPL(thread_detach)300 TEST_IMPL(thread_detach) {
301 uv_thread_t thread;
302 ASSERT_OK(uv_thread_create(&thread, thread_detach_cb, NULL));
303 ASSERT_OK(uv_thread_detach(&thread));
304
305 return 0;
306 }
307