Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(11)

Side by Side Diff: tests/nonsfi/user_async_signal_test.cc

Issue 1212613002: Non-SFI mode: Add Linux asynchronous signal support (Closed) Base URL: https://chromium.googlesource.com/native_client/src/native_client.git@master
Patch Set: Disabled the async signal test for glibc Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« tests/nonsfi/nacl.scons ('K') | « tests/nonsfi/nacl.scons ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2015 The Native Client Authors. All rights reserved.
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 #include <pthread.h>
8 #include <semaphore.h>
9
10 #include "native_client/src/include/nacl_assert.h"
11 #include "native_client/src/nonsfi/linux/irt_signal_handling.h"
Mark Seaborn 2015/08/12 01:43:08 Shouldn't be needed now -- this is an IRT-internal
Luis Héctor Chávez 2015/08/12 22:14:27 Done.
12 #include "native_client/src/public/nonsfi/irt_signal_handling.h"
Mark Seaborn 2015/08/12 01:43:08 Also shouldn't be needed now -- this is an IRT-int
Luis Héctor Chávez 2015/08/12 22:14:27 Done.
13 #include "native_client/src/untrusted/irt/irt.h"
14 #include "native_client/src/untrusted/nacl/nacl_irt.h"
Mark Seaborn 2015/08/12 01:43:08 Not needed now?
Luis Héctor Chávez 2015/08/12 22:14:27 This is used for __libnacl_irt_thread. We cannot u
15 #include "native_client/src/untrusted/nacl/nacl_thread.h"
16 #include "native_client/src/untrusted/pthread/pthread_types.h"
Mark Seaborn 2015/08/12 01:43:08 Not needed now?
Luis Héctor Chávez 2015/08/12 22:14:27 Done.
17
18 #define CHECK_OK(expr) ASSERT_EQ(expr, 0)
19
20 struct nacl_irt_thread_v0_2 __libnacl_irt_thread_v0_2;
Mark Seaborn 2015/08/12 01:43:08 You shouldn't need the "__" prefix here (or in the
Luis Héctor Chávez 2015/08/12 22:14:27 Done.
21 struct nacl_irt_async_signal_handling __libnacl_irt_async_signal_handling;
22
23 volatile int g_signal_count;
24 volatile int g_signal_arrived;
25 volatile int g_test_running;
26 static nacl_irt_tid_t g_child_tid;
27 void *g_expected_tls;
28 sem_t g_sem;
29
30 int thread_create_wrapper(void (*start_func)(void), void *stack,
31 void *thread_ptr) {
32 return __libnacl_irt_thread_v0_2.thread_create(start_func, stack, thread_ptr,
33 &g_child_tid);
34 }
35
36 int set_async_signal_handler(NaClIrtSignalHandler handler) {
37 return __libnacl_irt_async_signal_handling.set_async_signal_handler(handler);
38 }
39
40 int send_async_signal(nacl_irt_tid_t tid) {
41 return __libnacl_irt_async_signal_handling.send_async_signal(tid);
42 }
43
44 /*
45 * Check that sending a signal before initializing signal support will result in
46 * an error.
47 */
48 void test_send_signal_before_init() {
Mark Seaborn 2015/08/12 01:43:08 How about "before_set_handler", since there is no
Luis Héctor Chávez 2015/08/12 22:14:27 Done.
49 int retval = send_async_signal(0);
50 ASSERT_EQ(retval, ESRCH);
51 }
52
53 /*
54 * Check that nacl_tls_get() is async-signal-safe.
55 */
56 void tls_get_signal_handler(NaClExceptionContext *exc) {
57 if (!g_test_running)
58 return;
59 ASSERT_EQ(nacl_tls_get(), g_expected_tls);
60 g_signal_count++;
61 g_signal_arrived = 1;
62 }
63
64 void *tls_get_thread_func(void *arg) {
65 g_expected_tls = nacl_tls_get();
66 CHECK_OK(sem_post(&g_sem));
67 while (g_test_running) {
68 ASSERT_EQ(nacl_tls_get(), g_expected_tls);
69 if (__sync_bool_compare_and_swap(&g_signal_arrived, 1, 0)) {
70 CHECK_OK(sem_post(&g_sem));
71 }
72 }
73 return NULL;
74 }
75
76 void test_async_safe_tls_get() {
77 CHECK_OK(sem_init(&g_sem, 0, 0));
78 CHECK_OK(set_async_signal_handler(tls_get_signal_handler));
79
80 pthread_t tid;
81 g_signal_count = 0;
82 g_signal_arrived = 0;
83 g_test_running = true;
84 CHECK_OK(pthread_create(&tid, NULL, tls_get_thread_func, NULL));
85
86 CHECK_OK(sem_wait(&g_sem));
87 const int kSignalCount = 1000;
88 for (int i = 0; i < kSignalCount; i++) {
89 CHECK_OK(send_async_signal(g_child_tid));
90 CHECK_OK(sem_wait(&g_sem));
91 }
92 g_test_running = false;
93 /* Send a last signal to make sure any waiting syscalls get interrupted. */
94 CHECK_OK(send_async_signal(g_child_tid));
95 CHECK_OK(pthread_join(tid, NULL));
96 ASSERT_EQ(g_signal_count, kSignalCount);
97 CHECK_OK(sem_destroy(&g_sem));
98 }
99
100 /*
101 * Check that both futex_wake() and futex_wait_abs() are signal-async-safe.
102 */
103 void futex_signal_handler(NaClExceptionContext *exc) {
104 int count = 0;
105 ASSERT_EQ(__sync_bool_compare_and_swap(&g_signal_arrived, 0, 1), 1);
106 CHECK_OK(__libnacl_irt_futex.futex_wake(&g_signal_arrived, INT_MAX, &count));
107 /*
108 * |count| is always 0 since the thread waiting is now running the signal
109 * handler, so it did not actually counts as a wakeup.
Mark Seaborn 2015/08/12 01:43:08 "count"
Luis Héctor Chávez 2015/08/12 22:14:27 Done.
Mark Seaborn 2015/08/13 21:17:50 Er, I didn't mean you should replace '|count|' wit
110 */
111 ASSERT_EQ(count, 0);
112 if (g_test_running)
113 g_signal_count++;
114 }
115
116 void *futex_thread_func(void *arg) {
117 CHECK_OK(sem_post(&g_sem));
118 struct timespec timeout;
119 /*
120 * Make the timeout be the current time plus 10 seconds. This timeout should
121 * never kick in, but if it does it means we deadlocked, so it's better to
122 * assert than letting the job itself time out.
123 */
124 clock_gettime(CLOCK_REALTIME, &timeout);
125 timeout.tv_sec += 10;
126 while (g_test_running) {
127 int retval = __libnacl_irt_futex.futex_wait_abs(&g_signal_arrived, 0,
128 &timeout);
129 if (retval == EWOULDBLOCK) {
130 /*
131 * The signal handler executed before we could wait and changed the value
132 * of |g_signal_arrived|.
133 */
134 } else {
135 ASSERT_EQ(retval, EINTR);
Mark Seaborn 2015/08/12 01:43:08 Is the current implementation giving us EINTR? I
Luis Héctor Chávez 2015/08/12 22:14:27 It appears that FUTEX_WAIT with a timeout does ret
Mark Seaborn 2015/08/17 23:55:56 OK. Are there any test cases in this file that do
Luis Héctor Chávez 2015/08/18 02:53:31 Done. There is one small caveat: the test will sti
136 }
137 ASSERT_EQ(__sync_bool_compare_and_swap(&g_signal_arrived, 1, 0), 1);
138 /*
139 * Have to test again since we could have gone sleeping again after the last
140 * iteration.
141 */
142 if (g_test_running)
143 CHECK_OK(sem_post(&g_sem));
144 }
145 return NULL;
146 }
147
148 void test_async_safe_futex() {
149 CHECK_OK(sem_init(&g_sem, 0, 0));
150 CHECK_OK(set_async_signal_handler(futex_signal_handler));
151
152 pthread_t tid;
153 g_signal_count = 0;
154 g_signal_arrived = 0;
155 g_test_running = true;
156 CHECK_OK(pthread_create(&tid, NULL, futex_thread_func, NULL));
157
158 CHECK_OK(sem_wait(&g_sem));
159 const int kSignalCount = 1000;
160 for (int i = 0; i < kSignalCount; i++) {
161 CHECK_OK(send_async_signal(g_child_tid));
162 CHECK_OK(sem_wait(&g_sem));
163 }
164 g_test_running = false;
165 /* Send a last signal to make sure any waiting syscalls get interrupted. */
166 CHECK_OK(send_async_signal(g_child_tid));
167 CHECK_OK(pthread_join(tid, NULL));
168 ASSERT_EQ(g_signal_count, kSignalCount);
169 CHECK_OK(sem_destroy(&g_sem));
170 }
171
172 /*
173 * Check that send_async_signal() is async-signal-safe.
174 */
175 void signal_signal_handler(NaClExceptionContext *exc) {
176 if (!g_test_running)
177 return;
178 if (++g_signal_count % 2 == 1) {
179 CHECK_OK(send_async_signal(g_child_tid));
180 g_signal_arrived = 1;
181 }
182 }
183
184 void *signal_thread_func(void *arg) {
185 CHECK_OK(sem_post(&g_sem));
186 struct timespec req, rem;
187 /*
188 * In case we are unlucky and the signal arrives before the first sleep, limit
189 * the time sleeping to 10 msec.
190 */
191 req.tv_sec = 0;
192 req.tv_nsec = 10000000;
193 while (g_test_running) {
194 while (g_test_running && !g_signal_arrived) {
195 int retval = nanosleep(&req, &rem);
196 if (retval != 0)
197 ASSERT_EQ(errno, EINTR);
198 }
199 /*
200 * Have to test again since we could have gone sleeping again after the last
201 * iteration.
202 */
203 if (!g_test_running)
204 break;
205 g_signal_arrived = 0;
206 CHECK_OK(sem_post(&g_sem));
207 }
208 return NULL;
209 }
210
211 void test_async_safe_signal() {
212 CHECK_OK(sem_init(&g_sem, 0, 0));
213 CHECK_OK(set_async_signal_handler(signal_signal_handler));
214
215 pthread_t tid;
216 g_test_running = true;
217 g_signal_count = 0;
218 g_signal_arrived = 0;
219 CHECK_OK(pthread_create(&tid, NULL, signal_thread_func, NULL));
220
221 CHECK_OK(sem_wait(&g_sem));
222 const int kSignalCount = 1000;
223 for (int i = 0; i < kSignalCount; i++) {
224 CHECK_OK(send_async_signal(g_child_tid));
225 CHECK_OK(sem_wait(&g_sem));
226 }
227 g_test_running = false;
228 /* Send a last signal to make sure any waiting syscalls get interrupted. */
229 CHECK_OK(send_async_signal(g_child_tid));
230 CHECK_OK(pthread_join(tid, NULL));
231 ASSERT_EQ(g_signal_count, 2 * kSignalCount);
232 CHECK_OK(sem_destroy(&g_sem));
233 }
234
235 /*
236 * Check that passing 0 as |tid| to send_async_signal() works and
237 * sends a signal to the main thread.
238 */
239 void main_signal_handler(NaClExceptionContext *exc) {
240 g_signal_count = 1;
241 }
242
243 void test_main_signal() {
244 CHECK_OK(set_async_signal_handler(main_signal_handler));
245
246 g_signal_count = 0;
247 CHECK_OK(send_async_signal(NACL_IRT_MAIN_THREAD_TID));
248 ASSERT_EQ(g_signal_count, 1);
249 }
250
251 void run_test(const char *test_name, void (*test_func)(void)) {
252 printf("Running %s...\n", test_name);
253 test_func();
254 }
255
256 #define RUN_TEST(test_func) (run_test(#test_func, test_func))
257
258 int main(void) {
259 size_t bytes;
260 bytes = nacl_interface_query(NACL_IRT_THREAD_v0_2, &__libnacl_irt_thread_v0_2,
261 sizeof(__libnacl_irt_thread_v0_2));
262 ASSERT_EQ(bytes, sizeof(__libnacl_irt_thread_v0_2));
263
264 bytes = nacl_interface_query(NACL_IRT_ASYNC_SIGNAL_HANDLING_v0_1,
265 &__libnacl_irt_async_signal_handling,
266 sizeof(__libnacl_irt_async_signal_handling));
267 ASSERT_EQ(bytes, sizeof(__libnacl_irt_async_signal_handling));
268
269 /*
270 * In order to avoid modifying the libpthread implementation to save the
271 * native tid, wrap that functionality so the tid is stored in a global
272 * variable.
273 */
274 __libnacl_irt_thread.thread_create = &thread_create_wrapper;
275
276 RUN_TEST(test_send_signal_before_init);
277
278 RUN_TEST(test_async_safe_tls_get);
279 #if !defined(__arm__)
280 /*
281 * Signals are sometimes delivered after the futex_wait syscall returns (as
282 * opposed to interrupting it), which breaks this test.
Mark Seaborn 2015/08/12 01:43:08 Do you mean the futex_wait syscall doesn't get int
Luis Héctor Chávez 2015/08/12 22:14:27 Yes, futex_wait_abs returns ETIMEDOUT and the sign
283 */
284 RUN_TEST(test_async_safe_futex);
285 #endif
286 RUN_TEST(test_async_safe_signal);
287 RUN_TEST(test_main_signal);
288
289 printf("Done\n");
290
291 return 0;
292 }
OLDNEW
« tests/nonsfi/nacl.scons ('K') | « tests/nonsfi/nacl.scons ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698