Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / native_client / tests / irt_private_pthread / irt_thread_test.c
1 /*
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.
5  */
6
7 #include <assert.h>
8 #include <errno.h>
9 #include <pthread.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <sys/stat.h>
14 #include <unistd.h>
15
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"
20
21
22 __thread int tls_var = 123;
23
24 static pthread_t g_initial_thread_id;
25
26 /* This flag is set to zero by the IRT's thread_exit() function. */
27 static int32_t g_thread_flag;
28
29 static __thread uint32_t g_block_hook_call_count = 0;
30
31
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) {
35     sched_yield();
36   }
37 }
38
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;
45 }
46
47 static void check_thread(void) {
48   /* Check that IRT-internal TLS variables work inside this thread. */
49   assert(tls_var == 123);
50   tls_var = 456;
51
52   /* NULL is not a valid thread ID in our pthreads implementation. */
53   assert(pthread_self() != NULL);
54
55   assert(pthread_self() != g_initial_thread_id);
56   assert(!pthread_equal(pthread_self(), g_initial_thread_id));
57 }
58
59 static void pre_block_hook(void) {
60   g_block_hook_call_count++;
61 }
62
63 static void post_block_hook(void) {
64 }
65
66 static int block_hooks_are_called(void) {
67   uint32_t old_count = g_block_hook_call_count;
68   /*
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
71    * arguments.
72    */
73   int result = read(-1, NULL, 0);
74   /* Sanity checks. */
75   assert(result == -1);
76   assert(errno == EBADF);
77
78   uint32_t count_diff = g_block_hook_call_count - old_count;
79   assert(count_diff <= 1);
80   return count_diff == 1;
81 }
82
83
84 static void user_thread_func(void) {
85   check_thread();
86   assert(block_hooks_are_called());
87   nacl_irt_thread.thread_exit(&g_thread_flag);
88 }
89
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);
94
95   g_thread_flag = 1;
96   void *dummy_tls = &dummy_tls;
97   int rc = nacl_irt_thread.thread_create(user_thread_func, allocate_stack(),
98                                          dummy_tls);
99   assert(rc == 0);
100   wait_for_thread_exit();
101   /* The assignment should not have affected our copy of tls_var. */
102   assert(tls_var == 123);
103 }
104
105
106 static void *irt_thread_func(void *arg) {
107   assert((uintptr_t) arg == 0x12345678);
108   check_thread();
109   /* GC block hooks should not be called on IRT-internal threads. */
110   assert(!block_hooks_are_called());
111   return (void *) 0x23456789;
112 }
113
114 void test_irt_thread(void) {
115   /*
116    * Test that a thread created by the IRT for internal use works, and
117    * that TLS works inside the thread.
118    */
119   pthread_t tid;
120   int rc = pthread_create(&tid, NULL, irt_thread_func, (void *) 0x12345678);
121   assert(rc == 0);
122
123   void *result;
124   rc = pthread_join(tid, &result);
125   assert(rc == 0);
126   assert(result == (void *) 0x23456789);
127   /* The assignment should not have affected our copy of tls_var. */
128   assert(tls_var == 123);
129 }
130
131
132 /* This waits for the initial thread to exit. */
133 static void initial_thread_exit_helper(void) {
134   wait_for_thread_exit();
135   _exit(0);
136 }
137
138 void test_exiting_initial_thread(void) {
139   g_thread_flag = 1;
140   void *dummy_tls = &dummy_tls;
141   int rc = nacl_irt_thread.thread_create(initial_thread_exit_helper,
142                                          allocate_stack(), dummy_tls);
143   assert(rc == 0);
144   nacl_irt_thread.thread_exit(&g_thread_flag);
145   /* Should not reach here. */
146   abort();
147 }
148
149
150 int main(void) {
151   /*
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.
155    */
156   int rc = nacl_irt_blockhook.register_block_hooks(pre_block_hook,
157                                                    post_block_hook);
158   assert(rc == 0);
159
160   /*
161    * There are three kinds of thread inside the IRT, which we test here.
162    *
163    * Type 1: user threads, created by the IRT's public thread_create()
164    * interface.
165    */
166   printf("Running test_user_thread...\n");
167   test_user_thread();
168
169   /*
170    * Type 2: IRT internal threads, created by the IRT's internal
171    * pthread_create().
172    */
173   printf("Running test_irt_thread...\n");
174   test_irt_thread();
175
176   /*
177    * Type 3: the initial thread
178    */
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. */
183   return 1;
184 }
185
186
187 void _start(uint32_t *info) {
188   __pthread_initialize();
189   _exit(main());
190 }