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.
14 #include "native_client/src/untrusted/valgrind/dynamic_annotations.h"
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.
22 Tests named positive_* have races that should be detectable by ThreadSanitizer.
23 negative_* tests don't have races and ThreadSanitizer should be silent.
26 #define NOINLINE __attribute__((noinline))
27 #define SHOW_ME printf("========== %s: =========\n", __FUNCTION__)
33 typedef void *(*ThreadCallback)(void*);
35 void create_and_join_threads(ThreadCallback *callbacks, int n) {
37 pthread_t t[kMaxNumThreads];
38 int ids[kMaxNumThreads];
39 assert(n <= kMaxNumThreads);
40 for (i = 0; i < n; i++) {
42 pthread_create(&t[i], NULL, callbacks[i], &ids[i]);
44 for (i = 0; i < n; i++) {
45 pthread_join(t[i], NULL);
49 /* Don't let various optimizations (e.g. tail call elimination) to happen. */
50 NOINLINE void break_optimization(void) {
51 #if defined(__pnacl__)
55 __asm__ volatile ("");
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. */
64 NOINLINE void simple_race_write_frame_2(void) {
66 simple_race_obj++; /* Race here. */
68 NOINLINE void simple_race_write_frame_1(void) {
70 simple_race_write_frame_2();
73 void *simple_race_write(void *arg) {
75 simple_race_write_frame_1();
80 void positive_race_on_global_test(void) {
81 ThreadCallback t[] = {simple_race_write, simple_race_write,
84 ANNOTATE_EXPECT_RACE(&simple_race_obj,
85 "positive_race_on_global_test. NACL_UNTRUSTED.");
86 create_and_join_threads(t, 3);
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) {
95 *race_on_heap_obj = 1; /* Race here. */
97 NOINLINE void race_on_heap_frame_1(void) {
99 race_on_heap_frame_2();
100 break_optimization();
102 void *race_on_heap_write(void *unused) {
103 break_optimization();
104 race_on_heap_frame_1();
105 break_optimization();
109 void positive_race_on_heap_test(void) {
110 ThreadCallback t[2] = {race_on_heap_write, race_on_heap_write};
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);
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;
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);
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);
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);
145 ANNOTATE_EXPECT_RACE(&wrong_lock_test_obj,
146 "positive_wrong_lock_test. NACL_UNTRUSTED.");
147 create_and_join_threads(t, 2);
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;
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);
162 void locked_access_test_frame_1(void) {
163 locked_access_test_frame_2();
166 void *locked_access_test_thread(void *unused) {
167 locked_access_test_frame_1();
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);
175 create_and_join_threads(t, 2);
178 /* -------------------------------------------------------------------------- */
179 /* negative_posix_sem_test */
181 int posix_sem_test_glob = 0;
182 sem_t posix_sem_test_sem[2];
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]);
191 void* posix_sem_test_waiter(void* unused) {
192 sem_wait(&posix_sem_test_sem[0]);
193 assert(posix_sem_test_glob == 1);
197 void negative_posix_sem_test(void) {
198 ThreadCallback t[2] = {posix_sem_test_poster, posix_sem_test_waiter};
200 sem_init(&posix_sem_test_sem[0], 0, 0);
201 sem_init(&posix_sem_test_sem[1], 0, 0);
203 create_and_join_threads(t, 2);
205 sem_destroy(&posix_sem_test_sem[0]);
206 sem_destroy(&posix_sem_test_sem[1]);
209 /* -------------------------------------------------------------------------- */
210 /* pthread_create_and_join_test */
211 /* Test that thread creation and joining adds happens-before arcs. */
213 int thread_create_and_join_test_glob;
215 void* thread_create_and_join_test_thread1(void* unused) {
216 thread_create_and_join_test_glob = 2;
220 void thread_create_and_join_test(void) {
221 ThreadCallback t[1] = {thread_create_and_join_test_thread1};
224 ANNOTATE_TRACE_MEMORY(&thread_create_and_join_test_glob);
226 thread_create_and_join_test_glob = 1;
228 create_and_join_threads(t, 1);
230 assert(thread_create_and_join_test_glob == 2);
233 /* -------------------------------------------------------------------------- */
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();