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(r == 0);
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 /* 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 req = container_of(handle, struct getaddrinfo_req, handle);
88 uv_freeaddrinfo(res);
89
90 if (--req->counter)
91 getaddrinfo_do(req);
92 }
93
94
fs_do(struct fs_req * req)95 static void fs_do(struct fs_req* req) {
96 int r;
97
98 r = uv_fs_stat(req->loop, &req->handle, ".", fs_cb);
99 ASSERT(r == 0);
100 }
101
102
fs_cb(uv_fs_t * handle)103 static void fs_cb(uv_fs_t* handle) {
104 struct fs_req* req = container_of(handle, struct fs_req, handle);
105
106 uv_fs_req_cleanup(handle);
107
108 if (--req->counter)
109 fs_do(req);
110 }
111
112
thread_entry(void * arg)113 static void thread_entry(void* arg) {
114 ASSERT(arg == (void *) 42);
115 thread_called++;
116 }
117
118
TEST_IMPL(thread_create)119 TEST_IMPL(thread_create) {
120 uv_thread_t tid;
121 int r;
122
123 r = uv_thread_create(&tid, thread_entry, (void *) 42);
124 ASSERT(r == 0);
125
126 r = uv_thread_join(&tid);
127 ASSERT(r == 0);
128
129 ASSERT(thread_called == 1);
130
131 return 0;
132 }
133
134
tls_thread(void * arg)135 static void tls_thread(void* arg) {
136 ASSERT_NULL(uv_key_get(&tls_key));
137 uv_key_set(&tls_key, arg);
138 ASSERT(arg == uv_key_get(&tls_key));
139 uv_key_set(&tls_key, NULL);
140 ASSERT_NULL(uv_key_get(&tls_key));
141 }
142
143
TEST_IMPL(thread_local_storage)144 TEST_IMPL(thread_local_storage) {
145 char name[] = "main";
146 uv_thread_t threads[2];
147 ASSERT(0 == uv_key_create(&tls_key));
148 ASSERT_NULL(uv_key_get(&tls_key));
149 uv_key_set(&tls_key, name);
150 ASSERT(name == uv_key_get(&tls_key));
151 ASSERT(0 == uv_thread_create(threads + 0, tls_thread, threads + 0));
152 ASSERT(0 == uv_thread_create(threads + 1, tls_thread, threads + 1));
153 ASSERT(0 == uv_thread_join(threads + 0));
154 ASSERT(0 == uv_thread_join(threads + 1));
155 uv_key_delete(&tls_key);
156 return 0;
157 }
158
159
thread_check_stack(void * arg)160 static void thread_check_stack(void* arg) {
161 #if defined(__APPLE__)
162 size_t expected;
163 expected = arg == NULL ? 0 : ((uv_thread_options_t*)arg)->stack_size;
164 /* 512 kB is the default stack size of threads other than the main thread
165 * on MacOS. */
166 if (expected == 0)
167 expected = 512 * 1024;
168 ASSERT(pthread_get_stacksize_np(pthread_self()) >= expected);
169 #elif defined(__linux__) && defined(__GLIBC__)
170 size_t expected;
171 struct rlimit lim;
172 size_t stack_size;
173 pthread_attr_t attr;
174 ASSERT(0 == getrlimit(RLIMIT_STACK, &lim));
175 if (lim.rlim_cur == RLIM_INFINITY)
176 lim.rlim_cur = 2 << 20; /* glibc default. */
177 ASSERT(0 == pthread_getattr_np(pthread_self(), &attr));
178 ASSERT(0 == pthread_attr_getstacksize(&attr, &stack_size));
179 expected = arg == NULL ? 0 : ((uv_thread_options_t*)arg)->stack_size;
180 if (expected == 0)
181 expected = (size_t)lim.rlim_cur;
182 ASSERT(stack_size >= expected);
183 ASSERT(0 == pthread_attr_destroy(&attr));
184 #endif
185 }
186
187
TEST_IMPL(thread_stack_size)188 TEST_IMPL(thread_stack_size) {
189 uv_thread_t thread;
190 ASSERT(0 == uv_thread_create(&thread, thread_check_stack, NULL));
191 ASSERT(0 == uv_thread_join(&thread));
192 return 0;
193 }
194
TEST_IMPL(thread_stack_size_explicit)195 TEST_IMPL(thread_stack_size_explicit) {
196 uv_thread_t thread;
197 uv_thread_options_t options;
198
199 options.flags = UV_THREAD_HAS_STACK_SIZE;
200 options.stack_size = 1024 * 1024;
201 ASSERT(0 == uv_thread_create_ex(&thread, &options,
202 thread_check_stack, &options));
203 ASSERT(0 == uv_thread_join(&thread));
204
205 options.stack_size = 8 * 1024 * 1024; /* larger than most default os sizes */
206 ASSERT(0 == uv_thread_create_ex(&thread, &options,
207 thread_check_stack, &options));
208 ASSERT(0 == uv_thread_join(&thread));
209
210 options.stack_size = 0;
211 ASSERT(0 == uv_thread_create_ex(&thread, &options,
212 thread_check_stack, &options));
213 ASSERT(0 == uv_thread_join(&thread));
214
215 options.stack_size = 42;
216 ASSERT(0 == uv_thread_create_ex(&thread, &options,
217 thread_check_stack, &options));
218 ASSERT(0 == uv_thread_join(&thread));
219
220 #ifdef PTHREAD_STACK_MIN
221 options.stack_size = PTHREAD_STACK_MIN - 42; /* unaligned size */
222 ASSERT(0 == uv_thread_create_ex(&thread, &options,
223 thread_check_stack, &options));
224 ASSERT(0 == uv_thread_join(&thread));
225
226 options.stack_size = PTHREAD_STACK_MIN / 2 - 42; /* unaligned size */
227 ASSERT(0 == uv_thread_create_ex(&thread, &options,
228 thread_check_stack, &options));
229 ASSERT(0 == uv_thread_join(&thread));
230 #endif
231
232 /* unaligned size, should be larger than PTHREAD_STACK_MIN */
233 options.stack_size = 1234567;
234 ASSERT(0 == uv_thread_create_ex(&thread, &options,
235 thread_check_stack, &options));
236 ASSERT(0 == uv_thread_join(&thread));
237
238 return 0;
239 }
240