Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / native_client / tests / threads / race_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 <pthread.h>
9 #include <semaphore.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13
14 #include "native_client/src/untrusted/valgrind/dynamic_annotations.h"
15
16 /*
17  This small test is mainly for checking sanity of ThreadSanitizer on NaCl
18  and is not a substitute for the ThreadSanitizer's full test suite.
19  TODO(kcc): once ThreadSanitizer starts working reliably on NaCl,
20  create a golden file to compare with the ThreadSanitizer's output.
21
22  Tests named positive_* have races that should be detectable by ThreadSanitizer.
23  negative_* tests don't have races and ThreadSanitizer should be silent.
24 */
25
26 #define NOINLINE __attribute__((noinline))
27 #define SHOW_ME    printf("========== %s: =========\n", __FUNCTION__)
28
29 enum {
30   kMaxNumThreads = 5
31 };
32
33 typedef void *(*ThreadCallback)(void*);
34
35 void create_and_join_threads(ThreadCallback *callbacks, int n) {
36   int i;
37   pthread_t t[kMaxNumThreads];
38   int ids[kMaxNumThreads];
39   assert(n <= kMaxNumThreads);
40   for (i = 0; i < n; i++) {
41     ids[i] = i;
42     pthread_create(&t[i], NULL, callbacks[i], &ids[i]);
43   }
44   for (i = 0; i < n; i++) {
45     pthread_join(t[i], NULL);
46   }
47 }
48
49 /* Don't let various optimizations (e.g. tail call elimination) to happen. */
50 NOINLINE void break_optimization(void) {
51 #if defined(__pnacl__)
52   volatile int foo;
53   foo = 0;
54 #else
55   __asm__ volatile ("");
56 #endif
57 }
58
59 /* -------------------------------------------------------------------------- */
60 /* positive_race_on_global_test
61    Simle race on a global variable between three threads.
62    We have few stack frames here to test ThreadSanitizer's output. */
63 int simple_race_obj;
64 NOINLINE void simple_race_write_frame_2(void) {
65   break_optimization();
66   simple_race_obj++;  /* Race here. */
67 }
68 NOINLINE void simple_race_write_frame_1(void) {
69   break_optimization();
70   simple_race_write_frame_2();
71   break_optimization();
72 }
73 void *simple_race_write(void *arg) {
74   break_optimization();
75   simple_race_write_frame_1();
76   break_optimization();
77   return NULL;
78 }
79
80 void positive_race_on_global_test(void) {
81   ThreadCallback t[] = {simple_race_write, simple_race_write,
82     simple_race_write};
83   SHOW_ME;
84   ANNOTATE_EXPECT_RACE(&simple_race_obj,
85       "positive_race_on_global_test. NACL_UNTRUSTED.");
86   create_and_join_threads(t, 3);
87 }
88
89 /* -------------------------------------------------------------------------- */
90 /* positive_race_on_heap_test
91    Simple race on a heap object. */
92 int *race_on_heap_obj;
93 NOINLINE void race_on_heap_frame_2(void) {
94   break_optimization();
95   *race_on_heap_obj = 1;  /* Race here. */
96 }
97 NOINLINE void race_on_heap_frame_1(void) {
98   break_optimization();
99   race_on_heap_frame_2();
100   break_optimization();
101 }
102 void *race_on_heap_write(void *unused) {
103   break_optimization();
104   race_on_heap_frame_1();
105   break_optimization();
106   return NULL;
107 }
108
109 void positive_race_on_heap_test(void) {
110   ThreadCallback t[2] = {race_on_heap_write, race_on_heap_write};
111   SHOW_ME;
112   race_on_heap_obj = (int*)malloc(sizeof(int));
113   ANNOTATE_EXPECT_RACE(race_on_heap_obj,
114       "positive_race_on_heap_test. NACL_UNTRUSTED.");
115   create_and_join_threads(t, 2);
116   free(race_on_heap_obj);
117 }
118
119 /* -------------------------------------------------------------------------- */
120 /* positive_wrong_lock_test
121    Race on a global object between two threads, each holding its own lock. */
122 pthread_mutex_t wrong_lock_test_mu_1;
123 pthread_mutex_t wrong_lock_test_mu_2;
124 int wrong_lock_test_obj;
125
126 void *wrong_lock_test_access1(void *unused) {
127   pthread_mutex_lock(&wrong_lock_test_mu_1);
128   wrong_lock_test_obj++;  /* Race here. */
129   pthread_mutex_unlock(&wrong_lock_test_mu_1);
130   return NULL;
131 }
132
133 void *wrong_lock_test_access2(void *unused) {
134   pthread_mutex_lock(&wrong_lock_test_mu_2);
135   wrong_lock_test_obj++;  /* Race here. */
136   pthread_mutex_unlock(&wrong_lock_test_mu_2);
137   return NULL;
138 }
139
140 void positive_wrong_lock_test(void) {
141   ThreadCallback t[2] = {wrong_lock_test_access1, wrong_lock_test_access2};
142   pthread_mutex_init(&wrong_lock_test_mu_1, NULL);
143   pthread_mutex_init(&wrong_lock_test_mu_2, NULL);
144   SHOW_ME;
145   ANNOTATE_EXPECT_RACE(&wrong_lock_test_obj,
146       "positive_wrong_lock_test. NACL_UNTRUSTED.");
147   create_and_join_threads(t, 2);
148 }
149
150 /* -------------------------------------------------------------------------- */
151 /* negative_locked_access_test
152    Correctly synchronized code: an object is accessed
153    by different threads under the same lock. */
154 pthread_mutex_t locked_access_test_mu;
155 int locked_access_test_obj;
156
157 void locked_access_test_frame_2(void) {
158   pthread_mutex_lock(&locked_access_test_mu);
159   locked_access_test_obj++;  /* No race here. */
160   pthread_mutex_unlock(&locked_access_test_mu);
161 }
162 void locked_access_test_frame_1(void) {
163   locked_access_test_frame_2();
164 }
165
166 void *locked_access_test_thread(void *unused) {
167   locked_access_test_frame_1();
168   return NULL;
169 }
170
171 void negative_locked_access_test(void) {
172   ThreadCallback t[2] = {locked_access_test_thread, locked_access_test_thread};
173   pthread_mutex_init(&locked_access_test_mu, NULL);
174   SHOW_ME;
175   create_and_join_threads(t, 2);
176 }
177
178 /* -------------------------------------------------------------------------- */
179 /* negative_posix_sem_test */
180
181 int     posix_sem_test_glob = 0;
182 sem_t   posix_sem_test_sem[2];
183
184 void* posix_sem_test_poster(void* unused) {
185   posix_sem_test_glob = 1;
186   sem_post(&posix_sem_test_sem[0]);
187   sem_post(&posix_sem_test_sem[1]);
188   return NULL;
189 }
190
191 void* posix_sem_test_waiter(void* unused) {
192   sem_wait(&posix_sem_test_sem[0]);
193   assert(posix_sem_test_glob == 1);
194   return NULL;
195 }
196
197 void negative_posix_sem_test(void) {
198   ThreadCallback t[2] = {posix_sem_test_poster, posix_sem_test_waiter};
199   SHOW_ME;
200   sem_init(&posix_sem_test_sem[0], 0, 0);
201   sem_init(&posix_sem_test_sem[1], 0, 0);
202
203   create_and_join_threads(t, 2);
204
205   sem_destroy(&posix_sem_test_sem[0]);
206   sem_destroy(&posix_sem_test_sem[1]);
207 }
208
209 /* -------------------------------------------------------------------------- */
210 /* pthread_create_and_join_test */
211 /* Test that thread creation and joining adds happens-before arcs. */
212
213 int thread_create_and_join_test_glob;
214
215 void* thread_create_and_join_test_thread1(void* unused) {
216   thread_create_and_join_test_glob = 2;
217   return NULL;
218 }
219
220 void thread_create_and_join_test(void) {
221   ThreadCallback t[1] = {thread_create_and_join_test_thread1};
222
223   SHOW_ME;
224   ANNOTATE_TRACE_MEMORY(&thread_create_and_join_test_glob);
225
226   thread_create_and_join_test_glob = 1;
227
228   create_and_join_threads(t, 1);
229
230   assert(thread_create_and_join_test_glob == 2);
231 }
232
233 /* -------------------------------------------------------------------------- */
234 int main(void) {
235   if (1) positive_race_on_global_test();
236   if (1) positive_race_on_heap_test();
237   if (1) positive_wrong_lock_test();
238   if (1) negative_locked_access_test();
239   if (1) negative_posix_sem_test();
240   if (1) thread_create_and_join_test();
241   return 0;
242 }