2 * Copyright (c) 2012 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.
16 #include "native_client/src/untrusted/irt/irt.h"
17 #include "native_client/src/untrusted/irt/irt_interfaces.h"
18 #include "native_client/src/untrusted/nacl/tls.h"
19 #include "native_client/src/untrusted/pthread/pthread_internal.h"
22 __thread int tls_var = 123;
24 static pthread_t g_initial_thread_id;
26 /* This flag is set to zero by the IRT's thread_exit() function. */
27 static int32_t g_thread_flag;
29 static __thread uint32_t g_block_hook_call_count = 0;
32 static void wait_for_thread_exit(void) {
33 /* Using a mutex+condvar is a hassle to set up, so wait by spinning. */
34 while (g_thread_flag != 0) {
39 static char *allocate_stack(void) {
40 size_t stack_size = 0x10000;
41 char *stack = malloc(stack_size);
42 assert(stack != NULL);
43 /* We assume that the stack grows downwards. */
44 return stack + stack_size;
47 static void check_thread(void) {
48 /* Check that IRT-internal TLS variables work inside this thread. */
49 assert(tls_var == 123);
52 /* NULL is not a valid thread ID in our pthreads implementation. */
53 assert(pthread_self() != NULL);
55 assert(pthread_self() != g_initial_thread_id);
56 assert(!pthread_equal(pthread_self(), g_initial_thread_id));
59 static void pre_block_hook(void) {
60 g_block_hook_call_count++;
63 static void post_block_hook(void) {
66 static int block_hooks_are_called(void) {
67 uint32_t old_count = g_block_hook_call_count;
69 * Call a syscall that should use NACL_GC_WRAP_SYSCALL. In general,
70 * read() can block, but it does not when we pass it these bad
73 int result = read(-1, NULL, 0);
76 assert(errno == EBADF);
78 uint32_t count_diff = g_block_hook_call_count - old_count;
79 assert(count_diff <= 1);
80 return count_diff == 1;
84 static void user_thread_func(void) {
86 assert(block_hooks_are_called());
87 nacl_irt_thread.thread_exit(&g_thread_flag);
90 void test_user_thread(void) {
91 g_initial_thread_id = pthread_self();
92 /* NULL is not a valid thread ID in our pthreads implementation. */
93 assert(g_initial_thread_id != NULL);
96 void *dummy_tls = &dummy_tls;
97 int rc = nacl_irt_thread.thread_create(user_thread_func, allocate_stack(),
100 wait_for_thread_exit();
101 /* The assignment should not have affected our copy of tls_var. */
102 assert(tls_var == 123);
106 static void *irt_thread_func(void *arg) {
107 assert((uintptr_t) arg == 0x12345678);
109 /* GC block hooks should not be called on IRT-internal threads. */
110 assert(!block_hooks_are_called());
111 return (void *) 0x23456789;
114 void test_irt_thread(void) {
116 * Test that a thread created by the IRT for internal use works, and
117 * that TLS works inside the thread.
120 int rc = pthread_create(&tid, NULL, irt_thread_func, (void *) 0x12345678);
124 rc = pthread_join(tid, &result);
126 assert(result == (void *) 0x23456789);
127 /* The assignment should not have affected our copy of tls_var. */
128 assert(tls_var == 123);
132 /* This waits for the initial thread to exit. */
133 static void initial_thread_exit_helper(void) {
134 wait_for_thread_exit();
138 void test_exiting_initial_thread(void) {
140 void *dummy_tls = &dummy_tls;
141 int rc = nacl_irt_thread.thread_create(initial_thread_exit_helper,
142 allocate_stack(), dummy_tls);
144 nacl_irt_thread.thread_exit(&g_thread_flag);
145 /* Should not reach here. */
152 * Register these at startup because deregistering them is not
153 * allowed by the IRT's interface and nor is registering different
154 * functions afterwards.
156 int rc = nacl_irt_blockhook.register_block_hooks(pre_block_hook,
161 * There are three kinds of thread inside the IRT, which we test here.
163 * Type 1: user threads, created by the IRT's public thread_create()
166 printf("Running test_user_thread...\n");
170 * Type 2: IRT internal threads, created by the IRT's internal
173 printf("Running test_irt_thread...\n");
177 * Type 3: the initial thread
179 assert(block_hooks_are_called());
180 printf("Running test_exiting_initial_thread...\n");
181 test_exiting_initial_thread();
182 /* This last test does not return. */
187 void _start(uint32_t *info) {
188 __pthread_initialize();