Chromium Code Reviews| OLD | NEW |
|---|---|
| (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/nacl_signal.h" | |
| 11 #include "native_client/src/include/nacl_assert.h" | |
| 12 #include "native_client/src/public/nonsfi/irt_signal_handling.h" | |
| 13 #include "native_client/src/untrusted/irt/irt.h" | |
| 14 #include "native_client/src/untrusted/nacl/nacl_irt.h" | |
| 15 #include "native_client/src/untrusted/nacl/nacl_thread.h" | |
| 16 #include "native_client/src/untrusted/pthread/pthread_types.h" | |
| 17 | |
| 18 volatile int g_signal_count; | |
| 19 volatile int g_futex; | |
| 20 volatile int g_test_running; | |
| 21 int g_tid; | |
| 22 void* g_expected_tls; | |
| 23 sem_t g_sem; | |
| 24 | |
| 25 /* | |
| 26 * Check that sending a signal before initializing signal support will result in | |
| 27 * an error. | |
| 28 */ | |
| 29 void test_send_signal_before_init() { | |
| 30 int retval = nacl_signal_send_async_signal(0); | |
| 31 ASSERT_EQ(retval, ESRCH); | |
| 32 } | |
| 33 | |
| 34 /* | |
| 35 * Check that nacl_tls_get() is signal-async-safe. | |
|
Mark Seaborn
2015/06/26 18:32:00
Nit: "async-signal-safe"
Luis Héctor Chávez
2015/07/06 23:45:00
Done.
| |
| 36 */ | |
| 37 void tls_get_signal_handler(NaClExceptionContext *exc) { | |
| 38 if (!g_test_running) | |
| 39 return; | |
| 40 ASSERT_EQ(nacl_tls_get(), g_expected_tls); | |
| 41 g_signal_count++; | |
| 42 sem_post(&g_sem); | |
|
Mark Seaborn
2015/06/26 18:32:00
Nit: check return value on all calls (sem_post(),
Luis Héctor Chávez
2015/07/06 23:45:00
Done.
| |
| 43 } | |
| 44 | |
| 45 void *tls_get_thread_func(void *arg) { | |
| 46 g_expected_tls = nacl_tls_get(); | |
| 47 sem_post(&g_sem); | |
| 48 while (g_test_running) { | |
| 49 ASSERT_EQ(nacl_tls_get(), g_expected_tls); | |
| 50 } | |
| 51 return NULL; | |
| 52 } | |
| 53 | |
| 54 void test_async_safe_tls_get() { | |
| 55 nacl_signal_set_handler(tls_get_signal_handler); | |
| 56 | |
| 57 pthread_t tid; | |
| 58 g_signal_count = 0; | |
| 59 g_test_running = true; | |
| 60 int result = pthread_create(&tid, NULL, tls_get_thread_func, NULL); | |
| 61 ASSERT_EQ(0, result); | |
| 62 | |
| 63 sem_wait(&g_sem); | |
| 64 const int kSignalCount = 1000; | |
| 65 for (int i = 0; i < kSignalCount; i++) { | |
| 66 nacl_signal_send_async_signal(tid->native_tid); | |
|
Mark Seaborn
2015/06/26 18:32:00
Using tid->native_tid here is unfortunate because
Luis Héctor Chávez
2015/07/06 23:45:00
The trick was not needed, since I need to be able
| |
| 67 sem_wait(&g_sem); | |
| 68 } | |
| 69 g_test_running = false; | |
| 70 // Send a last signal to make sure any waiting syscalls get interrupted. | |
| 71 nacl_signal_send_async_signal(tid->native_tid); | |
| 72 pthread_join(tid, NULL); | |
| 73 ASSERT_EQ(g_signal_count, kSignalCount); | |
| 74 } | |
| 75 | |
| 76 /* | |
| 77 * Check that both futex_wake() and futex_wait_abs() are signal-async-safe. | |
| 78 */ | |
| 79 void futex_signal_handler(NaClExceptionContext *exc) { | |
| 80 if (!g_test_running) | |
| 81 return; | |
| 82 g_signal_count++; | |
| 83 sem_post(&g_sem); | |
| 84 int count = 0; | |
| 85 int retval = __libnacl_irt_futex.futex_wake(&g_futex, 1, &count); | |
| 86 ASSERT_EQ(retval, 0); | |
| 87 ASSERT_EQ(count, 0); | |
| 88 } | |
| 89 | |
| 90 void *futex_thread_func(void *arg) { | |
| 91 sem_post(&g_sem); | |
| 92 while (g_test_running) { | |
| 93 int retval = __libnacl_irt_futex.futex_wait_abs(&g_futex, 0, NULL); | |
| 94 ASSERT_EQ(retval, EINTR); | |
| 95 } | |
| 96 return NULL; | |
| 97 } | |
| 98 | |
| 99 void test_async_safe_futex() { | |
| 100 nacl_signal_set_handler(futex_signal_handler); | |
| 101 | |
| 102 pthread_t tid; | |
| 103 g_test_running = true; | |
| 104 g_futex = 0; | |
| 105 int result = pthread_create(&tid, NULL, futex_thread_func, NULL); | |
| 106 ASSERT_EQ(0, result); | |
| 107 | |
| 108 sem_wait(&g_sem); | |
| 109 g_signal_count = 0; | |
| 110 const int kSignalCount = 1000; | |
| 111 for (int i = 0; i < kSignalCount; i++) { | |
| 112 nacl_signal_send_async_signal(tid->native_tid); | |
| 113 sem_wait(&g_sem); | |
| 114 } | |
| 115 g_test_running = false; | |
| 116 // Send a last signal to make sure any waiting syscalls get interrupted. | |
| 117 nacl_signal_send_async_signal(tid->native_tid); | |
| 118 pthread_join(tid, NULL); | |
| 119 ASSERT_EQ(g_signal_count, kSignalCount); | |
| 120 } | |
| 121 | |
| 122 /* | |
| 123 * Check that nacl_signal_send_async_signal() is async-signal-safe. | |
| 124 */ | |
| 125 void signal_signal_handler(NaClExceptionContext *exc) { | |
| 126 if (!g_test_running) | |
| 127 return; | |
| 128 if (++g_signal_count % 2 == 1) { | |
| 129 nacl_signal_send_async_signal(g_tid); | |
| 130 sem_post(&g_sem); | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 void *signal_thread_func(void *arg) { | |
| 135 sem_post(&g_sem); | |
| 136 while (g_test_running) { | |
| 137 int retval = sleep(1); | |
| 138 ASSERT_EQ(retval, 1); | |
| 139 ASSERT_EQ(errno, EINTR); | |
| 140 } | |
| 141 return NULL; | |
| 142 } | |
| 143 | |
| 144 void test_async_safe_signal() { | |
| 145 nacl_signal_set_handler(signal_signal_handler); | |
| 146 | |
| 147 pthread_t tid; | |
| 148 g_test_running = true; | |
| 149 g_signal_count = 0; | |
| 150 int result = pthread_create(&tid, NULL, signal_thread_func, NULL); | |
| 151 ASSERT_EQ(0, result); | |
| 152 g_tid = tid->native_tid; | |
| 153 | |
| 154 sem_wait(&g_sem); | |
| 155 const int kSignalCount = 1000; | |
| 156 for (int i = 0; i < kSignalCount; i++) { | |
| 157 nacl_signal_send_async_signal(g_tid); | |
| 158 sem_wait(&g_sem); | |
| 159 } | |
| 160 g_test_running = false; | |
| 161 // Send a last signal to make sure any waiting syscalls get interrupted. | |
| 162 nacl_signal_send_async_signal(g_tid); | |
| 163 pthread_join(tid, NULL); | |
| 164 ASSERT_EQ(g_signal_count, 2 * kSignalCount); | |
| 165 } | |
| 166 | |
| 167 /* | |
| 168 * Check that passing 0 as |tid| to nacl_signal_send_async_signal() works and | |
| 169 * sends a signal to the main thread. | |
| 170 */ | |
| 171 void main_signal_handler(NaClExceptionContext *exc) { | |
| 172 g_signal_count = 1; | |
| 173 } | |
| 174 | |
| 175 void test_main_signal() { | |
| 176 nacl_signal_set_handler(main_signal_handler); | |
| 177 | |
| 178 g_signal_count = 0; | |
| 179 int retval = nacl_signal_send_async_signal(0); | |
| 180 ASSERT_EQ(retval, 0); | |
| 181 ASSERT_EQ(g_signal_count, 1); | |
| 182 } | |
| 183 | |
| 184 void run_test(const char *test_name, void (*test_func)(void)) { | |
| 185 printf("Running %s...\n", test_name); | |
| 186 test_func(); | |
| 187 } | |
| 188 | |
| 189 #define RUN_TEST(test_func) (run_test(#test_func, test_func)) | |
| 190 | |
| 191 int main(void) { | |
| 192 RUN_TEST(test_send_signal_before_init); | |
| 193 | |
| 194 nonsfi_initialize_signal_handler(); | |
| 195 sem_init(&g_sem, 0, 0); | |
| 196 | |
| 197 RUN_TEST(test_async_safe_tls_get); | |
| 198 RUN_TEST(test_async_safe_futex); | |
| 199 RUN_TEST(test_async_safe_signal); | |
| 200 RUN_TEST(test_main_signal); | |
| 201 | |
| 202 return 0; | |
| 203 } | |
| OLD | NEW |