[llvm-commits] [compiler-rt] r156545 - in /compiler-rt/trunk/lib/tsan: benchmarks/ output_tests/ rtl_tests/ unit_tests/

Kostya Serebryany kcc at google.com
Thu May 10 07:18:22 PDT 2012


Author: kcc
Date: Thu May 10 09:18:22 2012
New Revision: 156545

URL: http://llvm.org/viewvc/llvm-project?rev=156545&view=rev
Log:
[tsan] ThreadSanitizer tests and micro benchmarks. No makefiles yet.

Added:
    compiler-rt/trunk/lib/tsan/benchmarks/
    compiler-rt/trunk/lib/tsan/benchmarks/mini_bench_local.cc
    compiler-rt/trunk/lib/tsan/benchmarks/mini_bench_shared.cc
    compiler-rt/trunk/lib/tsan/benchmarks/start_many_threads.cc
    compiler-rt/trunk/lib/tsan/benchmarks/vts_many_threads_bench.cc
    compiler-rt/trunk/lib/tsan/output_tests/
    compiler-rt/trunk/lib/tsan/output_tests/free_race.c
    compiler-rt/trunk/lib/tsan/output_tests/heap_race.cc
    compiler-rt/trunk/lib/tsan/output_tests/memcpy_race.cc
    compiler-rt/trunk/lib/tsan/output_tests/mop_with_offset.cc
    compiler-rt/trunk/lib/tsan/output_tests/mop_with_offset2.cc
    compiler-rt/trunk/lib/tsan/output_tests/race_on_barrier.c
    compiler-rt/trunk/lib/tsan/output_tests/race_on_barrier2.c
    compiler-rt/trunk/lib/tsan/output_tests/race_on_mutex.c
    compiler-rt/trunk/lib/tsan/output_tests/race_with_finished_thread.cc
    compiler-rt/trunk/lib/tsan/output_tests/simple_race.c
    compiler-rt/trunk/lib/tsan/output_tests/simple_race.cc
    compiler-rt/trunk/lib/tsan/output_tests/simple_stack.c
    compiler-rt/trunk/lib/tsan/output_tests/simple_stack2.cc
    compiler-rt/trunk/lib/tsan/output_tests/static_init1.cc
    compiler-rt/trunk/lib/tsan/output_tests/static_init2.cc
    compiler-rt/trunk/lib/tsan/output_tests/static_init3.cc
    compiler-rt/trunk/lib/tsan/output_tests/static_init4.cc
    compiler-rt/trunk/lib/tsan/output_tests/static_init5.cc
    compiler-rt/trunk/lib/tsan/output_tests/suppress_same_address.cc
    compiler-rt/trunk/lib/tsan/output_tests/suppress_same_stacks.cc
    compiler-rt/trunk/lib/tsan/output_tests/suppress_sequence.cc
    compiler-rt/trunk/lib/tsan/output_tests/test_output.sh   (with props)
    compiler-rt/trunk/lib/tsan/output_tests/thread_leak.c
    compiler-rt/trunk/lib/tsan/output_tests/thread_leak2.c
    compiler-rt/trunk/lib/tsan/output_tests/thread_leak3.c
    compiler-rt/trunk/lib/tsan/output_tests/vptr_benign_race.cc
    compiler-rt/trunk/lib/tsan/output_tests/vptr_harmful_race.cc
    compiler-rt/trunk/lib/tsan/rtl_tests/
    compiler-rt/trunk/lib/tsan/rtl_tests/tsan_bench.cc
    compiler-rt/trunk/lib/tsan/rtl_tests/tsan_mop.cc
    compiler-rt/trunk/lib/tsan/rtl_tests/tsan_mutex.cc
    compiler-rt/trunk/lib/tsan/rtl_tests/tsan_posix.cc
    compiler-rt/trunk/lib/tsan/rtl_tests/tsan_string.cc
    compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test.cc
    compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test_util.h
    compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test_util_linux.cc
    compiler-rt/trunk/lib/tsan/rtl_tests/tsan_thread.cc
    compiler-rt/trunk/lib/tsan/unit_tests/
    compiler-rt/trunk/lib/tsan/unit_tests/tsan_allocator_test.cc
    compiler-rt/trunk/lib/tsan/unit_tests/tsan_clock_test.cc
    compiler-rt/trunk/lib/tsan/unit_tests/tsan_flags_test.cc
    compiler-rt/trunk/lib/tsan/unit_tests/tsan_mman_test.cc
    compiler-rt/trunk/lib/tsan/unit_tests/tsan_mutex_test.cc
    compiler-rt/trunk/lib/tsan/unit_tests/tsan_platform_test.cc
    compiler-rt/trunk/lib/tsan/unit_tests/tsan_printf_test.cc
    compiler-rt/trunk/lib/tsan/unit_tests/tsan_shadow_test.cc
    compiler-rt/trunk/lib/tsan/unit_tests/tsan_suppressions_test.cc
    compiler-rt/trunk/lib/tsan/unit_tests/tsan_sync_test.cc
    compiler-rt/trunk/lib/tsan/unit_tests/tsan_vector_test.cc

Added: compiler-rt/trunk/lib/tsan/benchmarks/mini_bench_local.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/benchmarks/mini_bench_local.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/benchmarks/mini_bench_local.cc (added)
+++ compiler-rt/trunk/lib/tsan/benchmarks/mini_bench_local.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,49 @@
+// Mini-benchmark for tsan: non-shared memory writes.
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+int len;
+int *a;
+const int kNumIter = 1000;
+
+__attribute__((noinline))
+void Run(int idx) {
+  for (int i = 0, n = len; i < n; i++)
+    a[i + idx * n] = i;
+}
+
+void *Thread(void *arg) {
+  long idx = (long)arg;
+  printf("Thread %ld started\n", idx);
+  for (int i = 0; i < kNumIter; i++)
+    Run(idx);
+  printf("Thread %ld done\n", idx);
+  return 0;
+}
+
+int main(int argc, char **argv) {
+  int n_threads = 0;
+  if (argc != 3) {
+    n_threads = 4;
+    len = 1000000;
+  } else {
+    n_threads = atoi(argv[1]);
+    assert(n_threads > 0 && n_threads <= 32);
+    len = atoi(argv[2]);
+  }
+  printf("%s: n_threads=%d len=%d iter=%d\n",
+         __FILE__, n_threads, len, kNumIter);
+  a = new int[n_threads * len];
+  pthread_t *t = new pthread_t[n_threads];
+  for (int i = 0; i < n_threads; i++) {
+    pthread_create(&t[i], 0, Thread, (void*)i);
+  }
+  for (int i = 0; i < n_threads; i++) {
+    pthread_join(t[i], 0);
+  }
+  delete [] t;
+  delete [] a;
+  return 0;
+}

Added: compiler-rt/trunk/lib/tsan/benchmarks/mini_bench_shared.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/benchmarks/mini_bench_shared.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/benchmarks/mini_bench_shared.cc (added)
+++ compiler-rt/trunk/lib/tsan/benchmarks/mini_bench_shared.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,51 @@
+// Mini-benchmark for tsan: shared memory reads.
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+int len;
+int *a;
+const int kNumIter = 1000;
+
+__attribute__((noinline))
+void Run(int idx) {
+  for (int i = 0, n = len; i < n; i++)
+    if (a[i] != i) abort();
+}
+
+void *Thread(void *arg) {
+  long idx = (long)arg;
+  printf("Thread %ld started\n", idx);
+  for (int i = 0; i < kNumIter; i++)
+    Run(idx);
+  printf("Thread %ld done\n", idx);
+  return 0;
+}
+
+int main(int argc, char **argv) {
+  int n_threads = 0;
+  if (argc != 3) {
+    n_threads = 4;
+    len = 1000000;
+  } else {
+    n_threads = atoi(argv[1]);
+    assert(n_threads > 0 && n_threads <= 32);
+    len = atoi(argv[2]);
+  }
+  printf("%s: n_threads=%d len=%d iter=%d\n",
+         __FILE__, n_threads, len, kNumIter);
+  a = new int[len];
+  for (int i = 0, n = len; i < n; i++)
+    a[i] = i;
+  pthread_t *t = new pthread_t[n_threads];
+  for (int i = 0; i < n_threads; i++) {
+    pthread_create(&t[i], 0, Thread, (void*)i);
+  }
+  for (int i = 0; i < n_threads; i++) {
+    pthread_join(t[i], 0);
+  }
+  delete [] t;
+  delete [] a;
+  return 0;
+}

Added: compiler-rt/trunk/lib/tsan/benchmarks/start_many_threads.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/benchmarks/start_many_threads.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/benchmarks/start_many_threads.cc (added)
+++ compiler-rt/trunk/lib/tsan/benchmarks/start_many_threads.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,52 @@
+// Mini-benchmark for creating a lot of threads.
+//
+// Some facts:
+// a) clang -O1 takes <15ms to start N=500 threads,
+//    consuming ~4MB more RAM than N=1.
+// b) clang -O1 -ftsan takes ~26s to start N=500 threads,
+//    eats 5GB more RAM than N=1 (which is somewhat expected but still a lot)
+//    but then it consumes ~4GB of extra memory when the threads shut down!
+//        (definitely not in the barrier_wait interceptor)
+//    Also, it takes 26s to run with N=500 vs just 1.1s to run with N=1.
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+pthread_barrier_t all_threads_ready;
+
+void* Thread(void *unused) {
+  pthread_barrier_wait(&all_threads_ready);
+  return 0;
+}
+
+int main(int argc, char **argv) {
+  int n_threads;
+  if (argc == 1) {
+    n_threads = 100;
+  } else if (argc == 2) {
+    n_threads = atoi(argv[1]);
+  } else {
+    printf("Usage: %s n_threads\n", argv[0]);
+    return 1;
+  }
+  printf("%s: n_threads=%d\n", __FILE__, n_threads);
+
+  pthread_barrier_init(&all_threads_ready, NULL, n_threads + 1);
+
+  pthread_t *t = new pthread_t[n_threads];
+  for (int i = 0; i < n_threads; i++) {
+    int status = pthread_create(&t[i], 0, Thread, (void*)i);
+    assert(status == 0);
+  }
+  // sleep(5);  // FIXME: simplify measuring the memory usage.
+  pthread_barrier_wait(&all_threads_ready);
+  for (int i = 0; i < n_threads; i++) {
+    pthread_join(t[i], 0);
+  }
+  // sleep(5);  // FIXME: simplify measuring the memory usage.
+  delete [] t;
+
+  return 0;
+}

Added: compiler-rt/trunk/lib/tsan/benchmarks/vts_many_threads_bench.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/benchmarks/vts_many_threads_bench.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/benchmarks/vts_many_threads_bench.cc (added)
+++ compiler-rt/trunk/lib/tsan/benchmarks/vts_many_threads_bench.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,120 @@
+// Mini-benchmark for tsan VTS worst case performance
+// Idea:
+// 1) Spawn M + N threads (M >> N)
+//    We'll call the 'M' threads as 'garbage threads'.
+// 2) Make sure all threads have created thus no TIDs were reused
+// 3) Join the garbage threads
+// 4) Do many sync operations on the remaining N threads
+//
+// It turns out that due to O(M+N) VTS complexity the (4) is much slower with
+// when N is large.
+//
+// Some numbers:
+// a) clang++ native O1 with n_iterations=200kk takes
+//      5s regardless of M
+//    clang++ tsanv2 O1 with n_iterations=20kk takes
+//      23.5s with M=200
+//      11.5s with M=1
+//    i.e. tsanv2 is ~23x to ~47x slower than native, depends on M.
+// b) g++ native O1 with n_iterations=200kk takes
+//      5.5s regardless of M
+//    g++ tsanv1 O1 with n_iterations=2kk takes
+//      39.5s with M=200
+//      20.5s with M=1
+//    i.e. tsanv1 is ~370x to ~720x slower than native, depends on M.
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+class __attribute__((aligned(64))) Mutex {
+ public:
+  Mutex()  { pthread_mutex_init(&m_, NULL); }
+  ~Mutex() { pthread_mutex_destroy(&m_); }
+  void Lock() { pthread_mutex_lock(&m_); }
+  void Unlock() { pthread_mutex_unlock(&m_); }
+
+ private:
+  pthread_mutex_t m_;
+};
+
+const int kNumMutexes = 1024;
+Mutex mutexes[kNumMutexes];
+
+int n_threads, n_iterations;
+
+pthread_barrier_t all_threads_ready, main_threads_ready;
+
+void* GarbageThread(void *unused) {
+  pthread_barrier_wait(&all_threads_ready);
+  return 0;
+}
+
+void *Thread(void *arg) {
+  long idx = (long)arg;
+  pthread_barrier_wait(&all_threads_ready);
+
+  // Wait for the main thread to join the garbage threads.
+  pthread_barrier_wait(&main_threads_ready);
+
+  printf("Thread %ld go!\n", idx);
+  int offset = idx * kNumMutexes / n_threads;
+  for (int i = 0; i < n_iterations; i++) {
+    mutexes[(offset + i) % kNumMutexes].Lock();
+    mutexes[(offset + i) % kNumMutexes].Unlock();
+  }
+  printf("Thread %ld done\n", idx);
+  return 0;
+}
+
+int main(int argc, char **argv) {
+  int n_garbage_threads;
+  if (argc == 1) {
+    n_threads = 2;
+    n_garbage_threads = 200;
+    n_iterations = 20000000;
+  } else if (argc == 4) {
+    n_threads = atoi(argv[1]);
+    assert(n_threads > 0 && n_threads <= 32);
+    n_garbage_threads = atoi(argv[2]);
+    assert(n_garbage_threads > 0 && n_garbage_threads <= 16000);
+    n_iterations = atoi(argv[3]);
+  } else {
+    printf("Usage: %s n_threads n_garbage_threads n_iterations\n", argv[0]);
+    return 1;
+  }
+  printf("%s: n_threads=%d n_garbage_threads=%d n_iterations=%d\n",
+         __FILE__, n_threads, n_garbage_threads, n_iterations);
+
+  pthread_barrier_init(&all_threads_ready, NULL, n_garbage_threads + n_threads + 1);
+  pthread_barrier_init(&main_threads_ready, NULL, n_threads + 1);
+
+  pthread_t *t = new pthread_t[n_threads];
+  {
+    pthread_t *g_t = new pthread_t[n_garbage_threads];
+    for (int i = 0; i < n_garbage_threads; i++) {
+      int status = pthread_create(&g_t[i], 0, GarbageThread, NULL);
+      assert(status == 0);
+    }
+    for (int i = 0; i < n_threads; i++) {
+      int status = pthread_create(&t[i], 0, Thread, (void*)i);
+      assert(status == 0);
+    }
+    pthread_barrier_wait(&all_threads_ready);
+    printf("All threads started! Killing the garbage threads.\n");
+    for (int i = 0; i < n_garbage_threads; i++) {
+      pthread_join(g_t[i], 0);
+    }
+    delete [] g_t;
+  }
+  printf("Resuming the main threads.\n");
+  pthread_barrier_wait(&main_threads_ready);
+
+
+  for (int i = 0; i < n_threads; i++) {
+    pthread_join(t[i], 0);
+  }
+  delete [] t;
+  return 0;
+}

Added: compiler-rt/trunk/lib/tsan/output_tests/free_race.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/free_race.c?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/free_race.c (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/free_race.c Thu May 10 09:18:22 2012
@@ -0,0 +1,36 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+int *mem;
+pthread_mutex_t mtx;
+
+void *Thread1(void *x) {
+  pthread_mutex_lock(&mtx);
+  free(mem);
+  pthread_mutex_unlock(&mtx);
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  usleep(1000000);
+  pthread_mutex_lock(&mtx);
+  mem[0] = 42;
+  pthread_mutex_unlock(&mtx);
+  return NULL;
+}
+
+int main() {
+  mem = (int*)malloc(100);
+  pthread_mutex_init(&mtx, 0);
+  pthread_t t;
+  pthread_create(&t, NULL, Thread1, NULL);
+  Thread2(0);
+  pthread_join(t, NULL);
+  pthread_mutex_destroy(&mtx);
+  return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race

Added: compiler-rt/trunk/lib/tsan/output_tests/heap_race.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/heap_race.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/heap_race.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/heap_race.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,19 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+
+void *Thread(void *a) {
+  ((int*)a)[0]++;
+  return NULL;
+}
+
+int main() {
+  int *p = new int(42);
+  pthread_t t;
+  pthread_create(&t, NULL, Thread, p);
+  p[0]++;
+  pthread_join(t, NULL);
+  delete p;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race

Added: compiler-rt/trunk/lib/tsan/output_tests/memcpy_race.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/memcpy_race.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/memcpy_race.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/memcpy_race.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,40 @@
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+char *data = new char[10];
+char *data1 = new char[10];
+char *data2 = new char[10];
+
+void *Thread1(void *x) {
+  memcpy(data+5, data1, 1);
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  usleep(500*1000);
+  memcpy(data+3, data2, 4);
+  return NULL;
+}
+
+int main() {
+  fprintf(stderr, "addr=%p\n", &data[5]);
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  return 0;
+}
+
+// CHECK: addr=[[ADDR:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK:   Write of size 1 at [[ADDR]] by thread 2:
+// CHECK:     #0 memcpy
+// CHECK:     #1 Thread2
+// CHECK:   Previous write of size 1 at [[ADDR]] by thread 1:
+// CHECK:     #0 memcpy
+// CHECK:     #1 Thread1
+

Added: compiler-rt/trunk/lib/tsan/output_tests/mop_with_offset.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/mop_with_offset.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/mop_with_offset.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/mop_with_offset.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,35 @@
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void *Thread1(void *x) {
+  int *p = (int*)x;
+  p[0] = 1;
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  usleep(500*1000);
+  char *p = (char*)x;
+  p[2] = 1;
+  return NULL;
+}
+
+int main() {
+  int data = 42;
+  fprintf(stderr, "ptr1=%p\n", &data);
+  fprintf(stderr, "ptr2=%p\n", (char*)&data + 2);
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, &data);
+  pthread_create(&t[1], NULL, Thread2, &data);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+}
+
+// CHECK: ptr1=[[PTR1:0x[0-9,a-f]+]]
+// CHECK: ptr2=[[PTR2:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK:   Write of size 1 at [[PTR2]] by thread 2:
+// CHECK:   Previous write of size 4 at [[PTR1]] by thread 1:
+

Added: compiler-rt/trunk/lib/tsan/output_tests/mop_with_offset2.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/mop_with_offset2.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/mop_with_offset2.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/mop_with_offset2.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,35 @@
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void *Thread1(void *x) {
+  usleep(500*1000);
+  int *p = (int*)x;
+  p[0] = 1;
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  char *p = (char*)x;
+  p[2] = 1;
+  return NULL;
+}
+
+int main() {
+  int data = 42;
+  fprintf(stderr, "ptr1=%p\n", &data);
+  fprintf(stderr, "ptr2=%p\n", (char*)&data + 2);
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, &data);
+  pthread_create(&t[1], NULL, Thread2, &data);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+}
+
+// CHECK: ptr1=[[PTR1:0x[0-9,a-f]+]]
+// CHECK: ptr2=[[PTR2:0x[0-9,a-f]+]]
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK:   Write of size 4 at [[PTR1]] by thread 1:
+// CHECK:   Previous write of size 1 at [[PTR2]] by thread 2:
+

Added: compiler-rt/trunk/lib/tsan/output_tests/race_on_barrier.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/race_on_barrier.c?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/race_on_barrier.c (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/race_on_barrier.c Thu May 10 09:18:22 2012
@@ -0,0 +1,31 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+pthread_barrier_t B;
+int Global;
+
+void *Thread1(void *x) {
+  pthread_barrier_init(&B, 0, 2);
+  pthread_barrier_wait(&B);
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  usleep(1000000);
+  pthread_barrier_wait(&B);
+  return NULL;
+}
+
+int main() {
+  pthread_t t;
+  pthread_create(&t, NULL, Thread1, NULL);
+  Thread2(0);
+  pthread_join(t, NULL);
+  pthread_barrier_destroy(&B);
+  return 0;
+}
+
+// CHECK:      WARNING: ThreadSanitizer: data race
+

Added: compiler-rt/trunk/lib/tsan/output_tests/race_on_barrier2.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/race_on_barrier2.c?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/race_on_barrier2.c (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/race_on_barrier2.c Thu May 10 09:18:22 2012
@@ -0,0 +1,30 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+pthread_barrier_t B;
+int Global;
+
+void *Thread1(void *x) {
+  if (pthread_barrier_wait(&B) == PTHREAD_BARRIER_SERIAL_THREAD)
+    pthread_barrier_destroy(&B);
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  if (pthread_barrier_wait(&B) == PTHREAD_BARRIER_SERIAL_THREAD)
+    pthread_barrier_destroy(&B);
+  return NULL;
+}
+
+int main() {
+  pthread_barrier_init(&B, 0, 2);
+  pthread_t t;
+  pthread_create(&t, NULL, Thread1, NULL);
+  Thread2(0);
+  pthread_join(t, NULL);
+  return 0;
+}
+
+// CHECK:      WARNING: ThreadSanitizer: data race

Added: compiler-rt/trunk/lib/tsan/output_tests/race_on_mutex.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/race_on_mutex.c?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/race_on_mutex.c (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/race_on_mutex.c Thu May 10 09:18:22 2012
@@ -0,0 +1,42 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <unistd.h>
+
+pthread_mutex_t Mtx;
+int Global;
+
+void *Thread1(void *x) {
+  pthread_mutex_init(&Mtx, 0);
+  pthread_mutex_lock(&Mtx);
+  Global = 42;
+  pthread_mutex_unlock(&Mtx);
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  usleep(1000000);
+  pthread_mutex_lock(&Mtx);
+  Global = 43;
+  pthread_mutex_unlock(&Mtx);
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  pthread_mutex_destroy(&Mtx);
+  return 0;
+}
+
+// CHECK:      WARNING: ThreadSanitizer: data race
+// CHECK-NEXT:   Read of size 1 at {{.*}} by thread 2:
+// CHECK-NEXT:     #0 pthread_mutex_lock {{.*}} ({{.*}})
+// CHECK-NEXT:     #1 Thread2 {{.*}}race_on_mutex.c:19 ({{.*}})
+// CHECK-NEXT:   Previous write of size 1 at {{.*}} by thread 1:
+// CHECK-NEXT:     #0 pthread_mutex_init {{.*}} ({{.*}})
+// CHECK-NEXT:     #1 Thread1 {{.*}}race_on_mutex.c:10 ({{.*}})
+

Added: compiler-rt/trunk/lib/tsan/output_tests/race_with_finished_thread.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/race_with_finished_thread.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/race_with_finished_thread.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/race_with_finished_thread.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,43 @@
+#include <pthread.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+// Ensure that we can restore a stack of a finished thread.
+
+int g_data;
+
+void __attribute__((noinline)) foobar(int *p) {
+  *p = 42;
+}
+
+void *Thread1(void *x) {
+  foobar(&g_data);
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  usleep(1000*1000);
+  g_data = 43;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race
+// CHECK:   Write of size 4 at {{.*}} by thread 2:
+// CHECK:   Previous write of size 4 at {{.*}} by thread 1:
+// CHECK:     #0 foobar
+// CHECK:     #1 Thread1
+// CHECK:   Thread 1 (finished) created at:
+// CHECK:     #0 pthread_create
+// CHECK:     #1 main
+

Added: compiler-rt/trunk/lib/tsan/output_tests/simple_race.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/simple_race.c?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/simple_race.c (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/simple_race.c Thu May 10 09:18:22 2012
@@ -0,0 +1,25 @@
+#include <pthread.h>
+#include <stdio.h>
+
+int Global;
+
+void *Thread1(void *x) {
+  Global = 42;
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  Global = 43;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race

Added: compiler-rt/trunk/lib/tsan/output_tests/simple_race.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/simple_race.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/simple_race.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/simple_race.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,24 @@
+#include <pthread.h>
+#include <stdio.h>
+
+int Global;
+
+void *Thread1(void *x) {
+  Global++;
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  Global--;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race

Added: compiler-rt/trunk/lib/tsan/output_tests/simple_stack.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/simple_stack.c?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/simple_stack.c (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/simple_stack.c Thu May 10 09:18:22 2012
@@ -0,0 +1,66 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void __attribute__((noinline)) foo1() {
+  Global = 42;
+}
+
+void __attribute__((noinline)) bar1() {
+  volatile int tmp = 42; (void)tmp;
+  foo1();
+}
+
+void __attribute__((noinline)) foo2() {
+  volatile int v = Global; (void)v;
+}
+
+void __attribute__((noinline)) bar2() {
+  volatile int tmp = 42; (void)tmp;
+  foo2();
+}
+
+void *Thread1(void *x) {
+  usleep(1000000);
+  bar1();
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  bar2();
+  return NULL;
+}
+
+void StartThread(pthread_t *t, void *(*f)(void*)) {
+  pthread_create(t, NULL, f, NULL);
+}
+
+int main() {
+  pthread_t t[2];
+  StartThread(&t[0], Thread1);
+  StartThread(&t[1], Thread2);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  return 0;
+}
+
+// CHECK:      WARNING: ThreadSanitizer: data race
+// CHECK-NEXT:   Write of size 4 at {{.*}} by thread 1:
+// CHECK-NEXT:     #0 foo1 {{.*}}simple_stack.c:8 ({{.*}})
+// CHECK-NEXT:     #1 bar1 {{.*}}simple_stack.c:13 ({{.*}})
+// CHECK-NEXT:     #2 Thread1 {{.*}}simple_stack.c:27 ({{.*}})
+// CHECK-NEXT:   Previous read of size 4 at {{.*}} by thread 2:
+// CHECK-NEXT:     #0 foo2 {{.*}}simple_stack.c:17 ({{.*}})
+// CHECK-NEXT:     #1 bar2 {{.*}}simple_stack.c:22 ({{.*}})
+// CHECK-NEXT:     #2 Thread2 {{.*}}simple_stack.c:32 ({{.*}})
+// CHECK-NEXT:   Thread 1 (running) created at:
+// CHECK-NEXT:     #0 pthread_create {{.*}} ({{.*}})
+// CHECK-NEXT:     #1 StartThread {{.*}}simple_stack.c:37 ({{.*}})
+// CHECK-NEXT:     #2 main {{.*}}simple_stack.c:42 ({{.*}})
+// CHECK-NEXT:   Thread 2 ({{.*}}) created at:
+// CHECK-NEXT:     #0 pthread_create {{.*}} ({{.*}})
+// CHECK-NEXT:     #1 StartThread {{.*}}simple_stack.c:37 ({{.*}})
+// CHECK-NEXT:     #2 main {{.*}}simple_stack.c:43 ({{.*}})
+

Added: compiler-rt/trunk/lib/tsan/output_tests/simple_stack2.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/simple_stack2.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/simple_stack2.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/simple_stack2.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,48 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+
+void __attribute__((noinline)) foo1() {
+  Global = 42;
+}
+
+void __attribute__((noinline)) bar1() {
+  volatile int tmp = 42; (void)tmp;
+  foo1();
+}
+
+void __attribute__((noinline)) foo2() {
+  volatile int v = Global; (void)v;
+}
+
+void __attribute__((noinline)) bar2() {
+  volatile int tmp = 42; (void)tmp;
+  foo2();
+}
+
+void *Thread1(void *x) {
+  usleep(1000000);
+  bar1();
+  return NULL;
+}
+
+int main() {
+  pthread_t t;
+  pthread_create(&t, NULL, Thread1, NULL);
+  bar2();
+  pthread_join(t, NULL);
+}
+
+// CHECK:      WARNING: ThreadSanitizer: data race
+// CHECK-NEXT:   Write of size 4 at {{.*}} by thread 1:
+// CHECK-NEXT:     #0 foo1() {{.*}}simple_stack2.cc:8 ({{.*}})
+// CHECK-NEXT:     #1 bar1() {{.*}}simple_stack2.cc:13 ({{.*}})
+// CHECK-NEXT:     #2 Thread1(void*) {{.*}}simple_stack2.cc:27 ({{.*}})
+// CHECK-NEXT:   Previous read of size 4 at {{.*}} by main thread:
+// CHECK-NEXT:     #0 foo2() {{.*}}simple_stack2.cc:17 ({{.*}})
+// CHECK-NEXT:     #1 bar2() {{.*}}simple_stack2.cc:22 ({{.*}})
+// CHECK-NEXT:     #2 main {{.*}}simple_stack2.cc:34 ({{.*}})
+
+

Added: compiler-rt/trunk/lib/tsan/output_tests/static_init1.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/static_init1.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/static_init1.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/static_init1.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,25 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+struct P {
+  int x;
+  int y;
+};
+
+void *Thread(void *x) {
+  static P p = {rand(), rand()};
+  if (p.x > RAND_MAX || p.y > RAND_MAX)
+    exit(1);
+  return 0;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], 0, Thread, 0);
+  pthread_create(&t[1], 0, Thread, 0);
+  pthread_join(t[0], 0);
+  pthread_join(t[1], 0);
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race

Added: compiler-rt/trunk/lib/tsan/output_tests/static_init2.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/static_init2.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/static_init2.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/static_init2.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,31 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+struct Cache {
+  int x;
+  Cache(int x)
+    : x(x) {
+  }
+};
+
+void foo(Cache *my) {
+  static Cache *c = my ? my : new Cache(rand());
+  if (c->x >= RAND_MAX)
+    exit(1);
+}
+
+void *Thread(void *x) {
+  foo(new Cache(rand()));
+  return 0;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], 0, Thread, 0);
+  pthread_create(&t[1], 0, Thread, 0);
+  pthread_join(t[0], 0);
+  pthread_join(t[1], 0);
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race

Added: compiler-rt/trunk/lib/tsan/output_tests/static_init3.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/static_init3.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/static_init3.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/static_init3.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,46 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sched.h>
+
+struct Cache {
+  int x;
+};
+
+Cache g_cache;
+
+Cache *CreateCache() {
+  g_cache.x = rand();
+  return &g_cache;
+}
+
+_Atomic(Cache*) queue;
+
+void *Thread1(void *x) {
+  static Cache *c = CreateCache();
+  __c11_atomic_store(&queue, c, 0);
+  return 0;
+}
+
+void *Thread2(void *x) {
+  Cache *c = 0;
+  for (;;) {
+    c = __c11_atomic_load(&queue, 0);
+    if (c)
+      break;
+    sched_yield();
+  }
+  if (c->x >= RAND_MAX)
+    exit(1);
+  return 0;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], 0, Thread1, 0);
+  pthread_create(&t[1], 0, Thread2, 0);
+  pthread_join(t[0], 0);
+  pthread_join(t[1], 0);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race

Added: compiler-rt/trunk/lib/tsan/output_tests/static_init4.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/static_init4.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/static_init4.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/static_init4.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,35 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sched.h>
+
+struct Cache {
+  int x;
+  Cache(int x)
+    : x(x) {
+  }
+};
+
+int g_other;
+
+Cache *CreateCache() {
+  g_other = rand();
+  return new Cache(rand());
+}
+
+void *Thread1(void *x) {
+  static Cache *c = CreateCache();
+  if (c->x == g_other)
+    exit(1);
+  return 0;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], 0, Thread1, 0);
+  pthread_create(&t[1], 0, Thread1, 0);
+  pthread_join(t[0], 0);
+  pthread_join(t[1], 0);
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race

Added: compiler-rt/trunk/lib/tsan/output_tests/static_init5.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/static_init5.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/static_init5.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/static_init5.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,40 @@
+#include <pthread.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sched.h>
+
+struct Cache {
+  int x;
+  Cache(int x)
+    : x(x) {
+  }
+};
+
+void *AsyncInit(void *p) {
+  return new Cache((int)(long)p);
+}
+
+Cache *CreateCache() {
+  pthread_t t;
+  pthread_create(&t, 0, AsyncInit, (void*)rand());
+  void *res;
+  pthread_join(t, &res);
+  return (Cache*)res;
+}
+
+void *Thread1(void *x) {
+  static Cache *c = CreateCache();
+  if (c->x >= RAND_MAX)
+    exit(1);
+  return 0;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], 0, Thread1, 0);
+  pthread_create(&t[1], 0, Thread1, 0);
+  pthread_join(t[0], 0);
+  pthread_join(t[1], 0);
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: data race

Added: compiler-rt/trunk/lib/tsan/output_tests/suppress_same_address.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/suppress_same_address.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/suppress_same_address.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/suppress_same_address.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,27 @@
+#include <pthread.h>
+
+int X;
+
+void *Thread1(void *x) {
+  X = 42;
+  X = 66;
+  X = 78;
+  return 0;
+}
+
+void *Thread2(void *x) {
+  X = 11;
+  X = 99;
+  X = 73;
+  return 0;
+}
+
+int main() {
+  pthread_t t;
+  pthread_create(&t, 0, Thread1, 0);
+  Thread2(0);
+  pthread_join(t, 0);
+}
+
+// CHECK: ThreadSanitizer: reported 1 warnings
+

Added: compiler-rt/trunk/lib/tsan/output_tests/suppress_same_stacks.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/suppress_same_stacks.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/suppress_same_stacks.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/suppress_same_stacks.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,27 @@
+#include <pthread.h>
+
+volatile int N;  // Prevent loop unrolling.
+int **data;
+
+void *Thread1(void *x) {
+  for (int i = 0; i < N; i++)
+    data[i][0] = 42;
+  return 0;
+}
+
+int main() {
+  N = 4;
+  data = new int*[N];
+  for (int i = 0; i < N; i++)
+    data[i] = new int;
+  pthread_t t;
+  pthread_create(&t, 0, Thread1, 0);
+  Thread1(0);
+  pthread_join(t, 0);
+  for (int i = 0; i < N; i++)
+    delete data[i];
+  delete[] data;
+}
+
+// CHECK: ThreadSanitizer: reported 1 warnings
+

Added: compiler-rt/trunk/lib/tsan/output_tests/suppress_sequence.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/suppress_sequence.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/suppress_sequence.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/suppress_sequence.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,26 @@
+#include <pthread.h>
+#include <unistd.h>
+
+volatile int g_data1;
+volatile int g_data2;
+volatile int g_data3;
+volatile int g_data4;
+
+void *Thread1(void *x) {
+  if (x)
+    usleep(1000000);
+  g_data1 = 42;
+  g_data2 = 43;
+  g_data3 = 44;
+  g_data4 = 45;
+  return 0;
+}
+
+int main() {
+  pthread_t t;
+  pthread_create(&t, 0, Thread1, (void*)1);
+  Thread1(0);
+  pthread_join(t, 0);
+}
+
+// CHECK: ThreadSanitizer: reported 1 warnings

Added: compiler-rt/trunk/lib/tsan/output_tests/test_output.sh
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/test_output.sh?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/test_output.sh (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/test_output.sh Thu May 10 09:18:22 2012
@@ -0,0 +1,61 @@
+#!/bin/bash
+
+ulimit -s 8192;
+set -e # fail on any error
+
+ROOTDIR=`dirname $0`/..
+
+# Assuming clang is in path.
+CC=clang
+CXX=clang++
+
+# TODO: add testing for all of -O0...-O3
+CFLAGS="-fthread-sanitizer -fPIE -O1 -g -fno-builtin -Wall -Werror=return-type"
+LDFLAGS="-pie -lpthread -ldl $ROOTDIR/tsan/libtsan.a"
+if [ "$LLDB" != "" ]; then
+  LDFLAGS+=" -L$LLDB -llldb"
+fi
+
+strip() {
+  grep -v "$1" test.out > test.out2
+  mv -f test.out2 test.out
+}
+
+test_file() {
+  SRC=$1
+  COMPILER=$2
+  echo ----- TESTING $1
+  OBJ=$SRC.o
+  EXE=$SRC.exe
+  $COMPILER $SRC $CFLAGS -c -o $OBJ
+  # Link with CXX, because lldb and suppressions require C++.
+  $CXX $OBJ $LDFLAGS -o $EXE
+  LD_LIBRARY_PATH=$LLDB TSAN_OPTIONS="atexit_sleep_ms=0" $EXE 2> test.out || echo -n
+  if [ "$3" != "" ]; then
+    cat test.out
+  fi
+  echo >>test.out  # FileCheck fails on empty files
+  FileCheck < test.out $SRC
+  if [ "$3" == "" ]; then
+    rm -f $EXE $OBJ test.out *.tmp *.tmp2
+  fi
+}
+
+if [ "$1" == "" ]; then
+  for c in $ROOTDIR/output_tests/*.c; do
+    if [[ $c == */failing_* ]]; then
+      echo SKIPPING FAILING TEST $c
+      continue
+    fi
+    test_file $c $CC
+  done
+  for c in $ROOTDIR/output_tests/*.cc; do
+    if [[ $c == */failing_* ]]; then
+      echo SKIPPING FAILING TEST $c
+      continue
+    fi
+    test_file $c $CXX
+  done
+else
+  test_file $ROOTDIR/output_tests/$1 $CXX "DUMP"
+fi

Propchange: compiler-rt/trunk/lib/tsan/output_tests/test_output.sh
------------------------------------------------------------------------------
    svn:executable = *

Added: compiler-rt/trunk/lib/tsan/output_tests/thread_leak.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/thread_leak.c?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/thread_leak.c (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/thread_leak.c Thu May 10 09:18:22 2012
@@ -0,0 +1,15 @@
+#include <pthread.h>
+
+void *Thread(void *x) {
+  return 0;
+}
+
+int main() {
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  pthread_join(t, 0);
+  return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
+

Added: compiler-rt/trunk/lib/tsan/output_tests/thread_leak2.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/thread_leak2.c?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/thread_leak2.c (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/thread_leak2.c Thu May 10 09:18:22 2012
@@ -0,0 +1,15 @@
+#include <pthread.h>
+
+void *Thread(void *x) {
+  return 0;
+}
+
+int main() {
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  pthread_detach(t);
+  return 0;
+}
+
+// CHECK-NOT: WARNING: ThreadSanitizer: thread leak
+

Added: compiler-rt/trunk/lib/tsan/output_tests/thread_leak3.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/thread_leak3.c?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/thread_leak3.c (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/thread_leak3.c Thu May 10 09:18:22 2012
@@ -0,0 +1,14 @@
+#include <pthread.h>
+
+void *Thread(void *x) {
+  return 0;
+}
+
+int main() {
+  pthread_t t;
+  pthread_create(&t, 0, Thread, 0);
+  return 0;
+}
+
+// CHECK: WARNING: ThreadSanitizer: thread leak
+

Added: compiler-rt/trunk/lib/tsan/output_tests/vptr_benign_race.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/vptr_benign_race.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/vptr_benign_race.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/vptr_benign_race.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,50 @@
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+
+struct A {
+  A() {
+    sem_init(&sem_, 0, 0);
+  }
+  virtual void F() {
+  }
+  void Done() {
+    sem_post(&sem_);
+  }
+  virtual ~A() {
+  }
+  sem_t sem_;
+};
+
+struct B : A {
+  virtual void F() {
+  }
+  virtual ~B() {
+    sem_wait(&sem_);
+    sem_destroy(&sem_);
+  }
+};
+
+static A *obj = new B;
+
+void *Thread1(void *x) {
+  obj->F();
+  obj->Done();
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  delete obj;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+  fprintf(stderr, "PASS\n");
+}
+// CHECK: PASS
+// CHECK-NOT: WARNING: ThreadSanitizer: data race

Added: compiler-rt/trunk/lib/tsan/output_tests/vptr_harmful_race.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/output_tests/vptr_harmful_race.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/output_tests/vptr_harmful_race.cc (added)
+++ compiler-rt/trunk/lib/tsan/output_tests/vptr_harmful_race.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,48 @@
+#include <pthread.h>
+#include <semaphore.h>
+#include <stdio.h>
+
+struct A {
+  A() {
+    sem_init(&sem_, 0, 0);
+  }
+  virtual void F() {
+  }
+  void Done() {
+    sem_post(&sem_);
+  }
+  virtual ~A() {
+    sem_wait(&sem_);
+    sem_destroy(&sem_);
+  }
+  sem_t sem_;
+};
+
+struct B : A {
+  virtual void F() {
+  }
+  virtual ~B() { }
+};
+
+static A *obj = new B;
+
+void *Thread1(void *x) {
+  obj->F();
+  obj->Done();
+  return NULL;
+}
+
+void *Thread2(void *x) {
+  delete obj;
+  return NULL;
+}
+
+int main() {
+  pthread_t t[2];
+  pthread_create(&t[0], NULL, Thread1, NULL);
+  pthread_create(&t[1], NULL, Thread2, NULL);
+  pthread_join(t[0], NULL);
+  pthread_join(t[1], NULL);
+}
+
+// CHECK: WARNING: ThreadSanitizer: data race

Added: compiler-rt/trunk/lib/tsan/rtl_tests/tsan_bench.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl_tests/tsan_bench.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl_tests/tsan_bench.cc (added)
+++ compiler-rt/trunk/lib/tsan/rtl_tests/tsan_bench.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,105 @@
+//===-- tsan_bench.cc -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_test_util.h"
+#include "tsan_interface.h"
+#include "tsan_defs.h"
+#include "gtest/gtest.h"
+#include <stdint.h>
+
+const int kSize = 128;
+const int kRepeat = 2*1024*1024;
+
+void noinstr(void *p) {}
+
+template<typename T, void(*__tsan_mop)(void *p)>
+static void Benchmark() {
+  volatile T data[kSize];
+  for (int i = 0; i < kRepeat; i++) {
+    for (int j = 0; j < kSize; j++) {
+      __tsan_mop((void*)&data[j]);
+      data[j]++;
+    }
+  }
+}
+
+TEST(DISABLED_BENCH, Mop1) {
+  Benchmark<uint8_t, noinstr>();
+}
+
+TEST(DISABLED_BENCH, Mop1Read) {
+  Benchmark<uint8_t, __tsan_read1>();
+}
+
+TEST(DISABLED_BENCH, Mop1Write) {
+  Benchmark<uint8_t, __tsan_write1>();
+}
+
+TEST(DISABLED_BENCH, Mop2) {
+  Benchmark<uint16_t, noinstr>();
+}
+
+TEST(DISABLED_BENCH, Mop2Read) {
+  Benchmark<uint16_t, __tsan_read2>();
+}
+
+TEST(DISABLED_BENCH, Mop2Write) {
+  Benchmark<uint16_t, __tsan_write2>();
+}
+
+TEST(DISABLED_BENCH, Mop4) {
+  Benchmark<uint32_t, noinstr>();
+}
+
+TEST(DISABLED_BENCH, Mop4Read) {
+  Benchmark<uint32_t, __tsan_read4>();
+}
+
+TEST(DISABLED_BENCH, Mop4Write) {
+  Benchmark<uint32_t, __tsan_write4>();
+}
+
+TEST(DISABLED_BENCH, Mop8) {
+  Benchmark<uint8_t, noinstr>();
+}
+
+TEST(DISABLED_BENCH, Mop8Read) {
+  Benchmark<uint64_t, __tsan_read8>();
+}
+
+TEST(DISABLED_BENCH, Mop8Write) {
+  Benchmark<uint64_t, __tsan_write8>();
+}
+
+TEST(DISABLED_BENCH, FuncCall) {
+  for (int i = 0; i < kRepeat; i++) {
+    for (int j = 0; j < kSize; j++)
+      __tsan_func_entry((void*)(uintptr_t)j);
+    for (int j = 0; j < kSize; j++)
+      __tsan_func_exit();
+  }
+}
+
+TEST(DISABLED_BENCH, MutexLocal) {
+  Mutex m;
+  ScopedThread().Create(m);
+  for (int i = 0; i < 50; i++) {
+    ScopedThread t;
+    t.Lock(m);
+    t.Unlock(m);
+  }
+  for (int i = 0; i < 16*1024*1024; i++) {
+    m.Lock();
+    m.Unlock();
+  }
+  ScopedThread().Destroy(m);
+}

Added: compiler-rt/trunk/lib/tsan/rtl_tests/tsan_mop.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl_tests/tsan_mop.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl_tests/tsan_mop.cc (added)
+++ compiler-rt/trunk/lib/tsan/rtl_tests/tsan_mop.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,231 @@
+//===-- tsan_mop.cc ---------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_interface.h"
+#include "tsan_test_util.h"
+#include "gtest/gtest.h"
+#include <stddef.h>
+#include <stdint.h>
+
+TEST(ThreadSanitizer, SimpleWrite) {
+  ScopedThread t;
+  MemLoc l;
+  t.Write1(l);
+}
+
+TEST(ThreadSanitizer, SimpleWriteWrite) {
+  ScopedThread t1, t2;
+  MemLoc l1, l2;
+  t1.Write1(l1);
+  t2.Write1(l2);
+}
+
+TEST(ThreadSanitizer, WriteWriteRace) {
+  ScopedThread t1, t2;
+  MemLoc l;
+  t1.Write1(l);
+  t2.Write1(l, true);
+}
+
+TEST(ThreadSanitizer, ReadWriteRace) {
+  ScopedThread t1, t2;
+  MemLoc l;
+  t1.Read1(l);
+  t2.Write1(l, true);
+}
+
+TEST(ThreadSanitizer, WriteReadRace) {
+  ScopedThread t1, t2;
+  MemLoc l;
+  t1.Write1(l);
+  t2.Read1(l, true);
+}
+
+TEST(ThreadSanitizer, ReadReadNoRace) {
+  ScopedThread t1, t2;
+  MemLoc l;
+  t1.Read1(l);
+  t2.Read1(l);
+}
+
+TEST(ThreadSanitizer, WriteThenRead) {
+  MemLoc l;
+  ScopedThread t1, t2;
+  t1.Write1(l);
+  t1.Read1(l);
+  t2.Read1(l, true);
+}
+
+TEST(ThreadSanitizer, WriteThenLockedRead) {
+  Mutex m(Mutex::RW);
+  MainThread t0;
+  t0.Create(m);
+  MemLoc l;
+  {
+    ScopedThread t1, t2;
+
+    t1.Write8(l);
+
+    t1.Lock(m);
+    t1.Read8(l);
+    t1.Unlock(m);
+
+    t2.Read8(l, true);
+  }
+  t0.Destroy(m);
+}
+
+TEST(ThreadSanitizer, LockedWriteThenRead) {
+  Mutex m(Mutex::RW);
+  MainThread t0;
+  t0.Create(m);
+  MemLoc l;
+  {
+    ScopedThread t1, t2;
+
+    t1.Lock(m);
+    t1.Write8(l);
+    t1.Unlock(m);
+
+    t1.Read8(l);
+
+    t2.Read8(l, true);
+  }
+  t0.Destroy(m);
+}
+
+
+TEST(ThreadSanitizer, RaceWithOffset) {
+  ScopedThread t1, t2;
+  {
+    MemLoc l;
+    t1.Access(l.loc(), true, 8, false);
+    t2.Access((char*)l.loc() + 4, true, 4, true);
+  }
+  {
+    MemLoc l;
+    t1.Access(l.loc(), true, 8, false);
+    t2.Access((char*)l.loc() + 7, true, 1, true);
+  }
+  {
+    MemLoc l;
+    t1.Access((char*)l.loc() + 4, true, 4, false);
+    t2.Access((char*)l.loc() + 4, true, 2, true);
+  }
+  {
+    MemLoc l;
+    t1.Access((char*)l.loc() + 4, true, 4, false);
+    t2.Access((char*)l.loc() + 6, true, 2, true);
+  }
+  {
+    MemLoc l;
+    t1.Access((char*)l.loc() + 3, true, 2, false);
+    t2.Access((char*)l.loc() + 4, true, 1, true);
+  }
+  {
+    MemLoc l;
+    t1.Access((char*)l.loc() + 1, true, 8, false);
+    t2.Access((char*)l.loc() + 3, true, 1, true);
+  }
+}
+
+TEST(ThreadSanitizer, RaceWithOffset2) {
+  ScopedThread t1, t2;
+  {
+    MemLoc l;
+    t1.Access((char*)l.loc(), true, 4, false);
+    t2.Access((char*)l.loc() + 2, true, 1, true);
+  }
+  {
+    MemLoc l;
+    t1.Access((char*)l.loc() + 2, true, 1, false);
+    t2.Access((char*)l.loc(), true, 4, true);
+  }
+}
+
+TEST(ThreadSanitizer, NoRaceWithOffset) {
+  ScopedThread t1, t2;
+  {
+    MemLoc l;
+    t1.Access(l.loc(), true, 4, false);
+    t2.Access((char*)l.loc() + 4, true, 4, false);
+  }
+  {
+    MemLoc l;
+    t1.Access((char*)l.loc() + 3, true, 2, false);
+    t2.Access((char*)l.loc() + 1, true, 2, false);
+    t2.Access((char*)l.loc() + 5, true, 2, false);
+  }
+}
+
+TEST(ThreadSanitizer, RaceWithDeadThread) {
+  MemLoc l;
+  ScopedThread t;
+  ScopedThread().Write1(l);
+  t.Write1(l, true);
+}
+
+TEST(ThreadSanitizer, BenignRaceOnVptr) {
+  void *vptr_storage;
+  MemLoc vptr(&vptr_storage), val;
+  vptr_storage = val.loc();
+  ScopedThread t1, t2;
+  t1.VptrUpdate(vptr, val);
+  t2.Read8(vptr);
+}
+
+TEST(ThreadSanitizer, HarmfulRaceOnVptr) {
+  void *vptr_storage;
+  MemLoc vptr(&vptr_storage), val1, val2;
+  vptr_storage = val1.loc();
+  ScopedThread t1, t2;
+  t1.VptrUpdate(vptr, val2);
+  t2.Read8(vptr, true);
+}
+
+static void foo() {
+  volatile int x = 42;
+  (void)x;
+}
+
+static void bar() {
+  volatile int x = 43;
+  (void)x;
+}
+
+TEST(ThreadSanitizer, ReportDeadThread) {
+  MemLoc l;
+  ScopedThread t1;
+  {
+    ScopedThread t2;
+    t2.Call(&foo);
+    t2.Call(&bar);
+    t2.Write1(l);
+  }
+  t1.Write1(l, true);
+}
+
+struct ClassWithStatic {
+  static int Data[4];
+};
+
+int ClassWithStatic::Data[4];
+
+static void foobarbaz() {}
+
+TEST(ThreadSanitizer, ReportRace) {
+  ScopedThread t1;
+  MainThread().Access(&ClassWithStatic::Data, true, 4, false);
+  t1.Call(&foobarbaz);
+  t1.Access(&ClassWithStatic::Data, true, 2, true);
+  t1.Return();
+}

Added: compiler-rt/trunk/lib/tsan/rtl_tests/tsan_mutex.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl_tests/tsan_mutex.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl_tests/tsan_mutex.cc (added)
+++ compiler-rt/trunk/lib/tsan/rtl_tests/tsan_mutex.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,221 @@
+//===-- tsan_mutex.cc -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_atomic.h"
+#include "tsan_interface.h"
+#include "tsan_interface_ann.h"
+#include "tsan_test_util.h"
+#include "gtest/gtest.h"
+#include <stdint.h>
+
+namespace __tsan {
+
+TEST(ThreadSanitizer, BasicMutex) {
+  ScopedThread t;
+  Mutex m;
+  t.Create(m);
+
+  t.Lock(m);
+  t.Unlock(m);
+
+  CHECK(t.TryLock(m));
+  t.Unlock(m);
+
+  t.Lock(m);
+  CHECK(!t.TryLock(m));
+  t.Unlock(m);
+
+  t.Destroy(m);
+}
+
+TEST(ThreadSanitizer, BasicSpinMutex) {
+  ScopedThread t;
+  Mutex m(Mutex::Spin);
+  t.Create(m);
+
+  t.Lock(m);
+  t.Unlock(m);
+
+  CHECK(t.TryLock(m));
+  t.Unlock(m);
+
+  t.Lock(m);
+  CHECK(!t.TryLock(m));
+  t.Unlock(m);
+
+  t.Destroy(m);
+}
+
+TEST(ThreadSanitizer, BasicRwMutex) {
+  ScopedThread t;
+  Mutex m(Mutex::RW);
+  t.Create(m);
+
+  t.Lock(m);
+  t.Unlock(m);
+
+  CHECK(t.TryLock(m));
+  t.Unlock(m);
+
+  t.Lock(m);
+  CHECK(!t.TryLock(m));
+  t.Unlock(m);
+
+  t.ReadLock(m);
+  t.ReadUnlock(m);
+
+  CHECK(t.TryReadLock(m));
+  t.ReadUnlock(m);
+
+  t.Lock(m);
+  CHECK(!t.TryReadLock(m));
+  t.Unlock(m);
+
+  t.ReadLock(m);
+  CHECK(!t.TryLock(m));
+  t.ReadUnlock(m);
+
+  t.ReadLock(m);
+  CHECK(t.TryReadLock(m));
+  t.ReadUnlock(m);
+  t.ReadUnlock(m);
+
+  t.Destroy(m);
+}
+
+TEST(ThreadSanitizer, Mutex) {
+  Mutex m;
+  MainThread t0;
+  t0.Create(m);
+
+  ScopedThread t1, t2;
+  MemLoc l;
+  t1.Lock(m);
+  t1.Write1(l);
+  t1.Unlock(m);
+  t2.Lock(m);
+  t2.Write1(l);
+  t2.Unlock(m);
+  t2.Destroy(m);
+}
+
+TEST(ThreadSanitizer, SpinMutex) {
+  Mutex m(Mutex::Spin);
+  MainThread t0;
+  t0.Create(m);
+
+  ScopedThread t1, t2;
+  MemLoc l;
+  t1.Lock(m);
+  t1.Write1(l);
+  t1.Unlock(m);
+  t2.Lock(m);
+  t2.Write1(l);
+  t2.Unlock(m);
+  t2.Destroy(m);
+}
+
+TEST(ThreadSanitizer, RwMutex) {
+  Mutex m(Mutex::RW);
+  MainThread t0;
+  t0.Create(m);
+
+  ScopedThread t1, t2, t3;
+  MemLoc l;
+  t1.Lock(m);
+  t1.Write1(l);
+  t1.Unlock(m);
+  t2.Lock(m);
+  t2.Write1(l);
+  t2.Unlock(m);
+  t1.ReadLock(m);
+  t3.ReadLock(m);
+  t1.Read1(l);
+  t3.Read1(l);
+  t1.ReadUnlock(m);
+  t3.ReadUnlock(m);
+  t2.Lock(m);
+  t2.Write1(l);
+  t2.Unlock(m);
+  t2.Destroy(m);
+}
+
+TEST(ThreadSanitizer, StaticMutex) {
+  // Emulates statically initialized mutex.
+  Mutex m;
+  m.StaticInit();
+  {
+    ScopedThread t1, t2;
+    t1.Lock(m);
+    t1.Unlock(m);
+    t2.Lock(m);
+    t2.Unlock(m);
+  }
+  MainThread().Destroy(m);
+}
+
+static void *singleton_thread(void *param) {
+  atomic_uintptr_t *singleton = (atomic_uintptr_t *)param;
+  for (int i = 0; i < 4*1024*1024; i++) {
+    int *val = (int *)atomic_load(singleton, memory_order_acquire);
+    __tsan_acquire(singleton);
+    __tsan_read4(val);
+    CHECK_EQ(*val, 42);
+  }
+  return 0;
+}
+
+TEST(DISABLED_BENCH_ThreadSanitizer, Singleton) {
+  const int kClockSize = 100;
+  const int kThreadCount = 8;
+
+  // Puff off thread's clock.
+  for (int i = 0; i < kClockSize; i++) {
+    ScopedThread t1;
+    (void)t1;
+  }
+  // Create the singleton.
+  int val = 42;
+  __tsan_write4(&val);
+  atomic_uintptr_t singleton;
+  __tsan_release(&singleton);
+  atomic_store(&singleton, (uintptr_t)&val, memory_order_release);
+  // Create reader threads.
+  pthread_t threads[kThreadCount];
+  for (int t = 0; t < kThreadCount; t++)
+    pthread_create(&threads[t], 0, singleton_thread, &singleton);
+  for (int t = 0; t < kThreadCount; t++)
+    pthread_join(threads[t], 0);
+}
+
+TEST(DISABLED_BENCH_ThreadSanitizer, StopFlag) {
+  const int kClockSize = 100;
+  const int kIters = 16*1024*1024;
+
+  // Puff off thread's clock.
+  for (int i = 0; i < kClockSize; i++) {
+    ScopedThread t1;
+    (void)t1;
+  }
+  // Create the stop flag.
+  atomic_uintptr_t flag;
+  __tsan_release(&flag);
+  atomic_store(&flag, 0, memory_order_release);
+  // Read it a lot.
+  for (int i = 0; i < kIters; i++) {
+    uptr v = atomic_load(&flag, memory_order_acquire);
+    __tsan_acquire(&flag);
+    CHECK_EQ(v, 0);
+  }
+}
+
+}  // namespace __tsan

Added: compiler-rt/trunk/lib/tsan/rtl_tests/tsan_posix.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl_tests/tsan_posix.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl_tests/tsan_posix.cc (added)
+++ compiler-rt/trunk/lib/tsan/rtl_tests/tsan_posix.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,146 @@
+//===-- tsan_posix.cc -------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_interface.h"
+#include "tsan_test_util.h"
+#include "gtest/gtest.h"
+#include <pthread.h>
+
+struct thread_key {
+  pthread_key_t key;
+  pthread_mutex_t *mtx;
+  int val;
+  int *cnt;
+  thread_key(pthread_key_t key, pthread_mutex_t *mtx, int val, int *cnt)
+    : key(key)
+    , mtx(mtx)
+    , val(val)
+    , cnt(cnt) {
+  }
+};
+
+static void thread_secific_dtor(void *v) {
+  thread_key *k = (thread_key *)v;
+  EXPECT_EQ(pthread_mutex_lock(k->mtx), 0);
+  (*k->cnt)++;
+  __tsan_write4(&k->cnt);
+  EXPECT_EQ(pthread_mutex_unlock(k->mtx), 0);
+  if (k->val == 42) {
+    delete k;
+  } else if (k->val == 43 || k->val == 44) {
+    k->val--;
+    EXPECT_EQ(pthread_setspecific(k->key, k), 0);
+  } else {
+    ASSERT_TRUE(false);
+  }
+}
+
+static void *dtors_thread(void *p) {
+  thread_key *k = (thread_key *)p;
+  EXPECT_EQ(pthread_setspecific(k->key, k), 0);
+  return 0;
+}
+
+TEST(Posix, ThreadSpecificDtors) {
+  int cnt = 0;
+  pthread_key_t key;
+  EXPECT_EQ(pthread_key_create(&key, thread_secific_dtor), 0);
+  pthread_mutex_t mtx;
+  EXPECT_EQ(pthread_mutex_init(&mtx, 0), 0);
+  pthread_t th[3];
+  thread_key *k[3];
+  k[0] = new thread_key(key, &mtx, 42, &cnt);
+  k[1] = new thread_key(key, &mtx, 43, &cnt);
+  k[2] = new thread_key(key, &mtx, 44, &cnt);
+  EXPECT_EQ(pthread_create(&th[0], 0, dtors_thread, k[0]), 0);
+  EXPECT_EQ(pthread_create(&th[1], 0, dtors_thread, k[1]), 0);
+  EXPECT_EQ(pthread_join(th[0], 0), 0);
+  EXPECT_EQ(pthread_create(&th[2], 0, dtors_thread, k[2]), 0);
+  EXPECT_EQ(pthread_join(th[1], 0), 0);
+  EXPECT_EQ(pthread_join(th[2], 0), 0);
+  EXPECT_EQ(pthread_key_delete(key), 0);
+  EXPECT_EQ(6, cnt);
+}
+
+static __thread int local_var;
+
+static void *local_thread(void *p) {
+  __tsan_write1(&local_var);
+  __tsan_write1(&p);
+  if (p == 0)
+    return 0;
+  const int kThreads = 4;
+  pthread_t th[kThreads];
+  for (int i = 0; i < kThreads; i++)
+    EXPECT_EQ(pthread_create(&th[i], 0, local_thread,
+              (void*)((long)p - 1)), 0);  // NOLINT
+  for (int i = 0; i < kThreads; i++)
+    EXPECT_EQ(pthread_join(th[i], 0), 0);
+  return 0;
+}
+
+TEST(Posix, ThreadLocalAccesses) {
+  local_thread((void*)2);
+}
+
+struct CondContext {
+  pthread_mutex_t m;
+  pthread_cond_t c;
+  int data;
+};
+
+static void *cond_thread(void *p) {
+  CondContext &ctx = *static_cast<CondContext*>(p);
+
+  EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
+  EXPECT_EQ(ctx.data, 0);
+  ctx.data = 1;
+  EXPECT_EQ(pthread_cond_signal(&ctx.c), 0);
+  EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
+
+  EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
+  while (ctx.data != 2)
+    EXPECT_EQ(pthread_cond_wait(&ctx.c, &ctx.m), 0);
+  EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
+
+  EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
+  ctx.data = 3;
+  EXPECT_EQ(pthread_cond_broadcast(&ctx.c), 0);
+  EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
+
+  return 0;
+}
+
+TEST(Posix, CondBasic) {
+  CondContext ctx;
+  EXPECT_EQ(pthread_mutex_init(&ctx.m, 0), 0);
+  EXPECT_EQ(pthread_cond_init(&ctx.c, 0), 0);
+  ctx.data = 0;
+  pthread_t th;
+  EXPECT_EQ(pthread_create(&th, 0, cond_thread, &ctx), 0);
+
+  EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
+  while (ctx.data != 1)
+    EXPECT_EQ(pthread_cond_wait(&ctx.c, &ctx.m), 0);
+  ctx.data = 2;
+  EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
+  EXPECT_EQ(pthread_cond_broadcast(&ctx.c), 0);
+
+  EXPECT_EQ(pthread_mutex_lock(&ctx.m), 0);
+  while (ctx.data != 3)
+    EXPECT_EQ(pthread_cond_wait(&ctx.c, &ctx.m), 0);
+  EXPECT_EQ(pthread_mutex_unlock(&ctx.m), 0);
+
+  EXPECT_EQ(pthread_join(th, 0), 0);
+  EXPECT_EQ(pthread_cond_destroy(&ctx.c), 0);
+  EXPECT_EQ(pthread_mutex_destroy(&ctx.m), 0);
+}

Added: compiler-rt/trunk/lib/tsan/rtl_tests/tsan_string.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl_tests/tsan_string.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl_tests/tsan_string.cc (added)
+++ compiler-rt/trunk/lib/tsan/rtl_tests/tsan_string.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,82 @@
+//===-- tsan_string.cc ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_test_util.h"
+#include "gtest/gtest.h"
+#include <string.h>
+
+namespace __tsan {
+
+TEST(ThreadSanitizer, Memcpy) {
+  char data0[7] = {1, 2, 3, 4, 5, 6, 7};
+  char data[7] = {42, 42, 42, 42, 42, 42, 42};
+  MainThread().Memcpy(data+1, data0+1, 5);
+  EXPECT_EQ(data[0], 42);
+  EXPECT_EQ(data[1], 2);
+  EXPECT_EQ(data[2], 3);
+  EXPECT_EQ(data[3], 4);
+  EXPECT_EQ(data[4], 5);
+  EXPECT_EQ(data[5], 6);
+  EXPECT_EQ(data[6], 42);
+  MainThread().Memset(data+1, 13, 5);
+  EXPECT_EQ(data[0], 42);
+  EXPECT_EQ(data[1], 13);
+  EXPECT_EQ(data[2], 13);
+  EXPECT_EQ(data[3], 13);
+  EXPECT_EQ(data[4], 13);
+  EXPECT_EQ(data[5], 13);
+  EXPECT_EQ(data[6], 42);
+}
+
+TEST(ThreadSanitizer, MemcpyRace1) {
+  char *data = new char[10];
+  char *data1 = new char[10];
+  char *data2 = new char[10];
+  ScopedThread t1, t2;
+  t1.Memcpy(data, data1, 10);
+  t2.Memcpy(data, data2, 10, true);
+}
+
+TEST(ThreadSanitizer, MemcpyRace2) {
+  char *data = new char[10];
+  char *data1 = new char[10];
+  char *data2 = new char[10];
+  ScopedThread t1, t2;
+  t1.Memcpy(data+5, data1, 1);
+  t2.Memcpy(data+3, data2, 4, true);
+}
+
+TEST(ThreadSanitizer, MemcpyRace3) {
+  char *data = new char[10];
+  char *data1 = new char[10];
+  char *data2 = new char[10];
+  ScopedThread t1, t2;
+  t1.Memcpy(data, data1, 10);
+  t2.Memcpy(data1, data2, 10, true);
+}
+
+TEST(ThreadSanitizer, MemcpyStack) {
+  char *data = new char[10];
+  char *data1 = new char[10];
+  ScopedThread t1, t2;
+  t1.Memcpy(data, data1, 10);
+  t2.Memcpy(data, data1, 10, true);
+}
+
+TEST(ThreadSanitizer, MemsetRace1) {
+  char *data = new char[10];
+  ScopedThread t1, t2;
+  t1.Memset(data, 1, 10);
+  t2.Memset(data, 2, 10, true);
+}
+
+}  // namespace __tsan

Added: compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test.cc (added)
+++ compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,43 @@
+//===-- tsan_test.cc --------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_interface.h"
+#include "tsan_test_util.h"
+#include "gtest/gtest.h"
+
+static void foo() {}
+static void bar() {}
+
+TEST(ThreadSanitizer, FuncCall) {
+  ScopedThread t1, t2;
+  MemLoc l;
+  t1.Write1(l);
+  t2.Call(foo);
+  t2.Call(bar);
+  t2.Write1(l, true);
+  t2.Return();
+  t2.Return();
+}
+
+int main(int argc, char **argv) {
+  TestMutexBeforeInit();  // Mutexes must be usable before __tsan_init();
+  __tsan_init();
+  __tsan_func_entry(__builtin_return_address(0));
+  __tsan_func_entry((char*)&main + 1);
+
+  testing::InitGoogleTest(&argc, argv);
+  int res = RUN_ALL_TESTS();
+
+  __tsan_func_exit();
+  __tsan_func_exit();
+  return res;
+}

Added: compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test_util.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test_util.h?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test_util.h (added)
+++ compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test_util.h Thu May 10 09:18:22 2012
@@ -0,0 +1,122 @@
+//===-- tsan_test_util.h ----------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+// Test utils.
+//===----------------------------------------------------------------------===//
+#ifndef TSAN_TEST_UTIL_H
+#define TSAN_TEST_UTIL_H
+
+void TestMutexBeforeInit();
+
+// A location of memory on which a race may be detected.
+class MemLoc {
+ public:
+  explicit MemLoc(int offset_from_aligned = 0);
+  explicit MemLoc(void *const real_addr) : loc_(real_addr) { }
+  ~MemLoc();
+  void *loc() const { return loc_; }
+ private:
+  void *const loc_;
+  MemLoc(const MemLoc&);
+  void operator = (const MemLoc&);
+};
+
+class Mutex {
+ public:
+  enum Type { Normal, Spin, RW };
+
+  explicit Mutex(Type type = Normal);
+  ~Mutex();
+
+  void Init();
+  void StaticInit();  // Emulates static initalization (tsan invisible).
+  void Destroy();
+  void Lock();
+  bool TryLock();
+  void Unlock();
+  void ReadLock();
+  bool TryReadLock();
+  void ReadUnlock();
+
+ private:
+  // Placeholder for pthread_mutex_t, CRITICAL_SECTION or whatever.
+  void *mtx_[128];
+  bool alive_;
+  const Type type_;
+
+  Mutex(const Mutex&);
+  void operator = (const Mutex&);
+};
+
+// A thread is started in CTOR and joined in DTOR.
+class ScopedThread {
+ public:
+  explicit ScopedThread(bool detached = false, bool main = false);
+  ~ScopedThread();
+  void Detach();
+
+  void Access(void *addr, bool is_write, int size, bool expect_race);
+  void Read(const MemLoc &ml, int size, bool expect_race = false) {
+    Access(ml.loc(), false, size, expect_race);
+  }
+  void Write(const MemLoc &ml, int size, bool expect_race = false) {
+    Access(ml.loc(), true, size, expect_race);
+  }
+  void Read1(const MemLoc &ml, bool expect_race = false) {
+    Read(ml, 1, expect_race); }
+  void Read2(const MemLoc &ml, bool expect_race = false) {
+    Read(ml, 2, expect_race); }
+  void Read4(const MemLoc &ml, bool expect_race = false) {
+    Read(ml, 4, expect_race); }
+  void Read8(const MemLoc &ml, bool expect_race = false) {
+    Read(ml, 8, expect_race); }
+  void Write1(const MemLoc &ml, bool expect_race = false) {
+    Write(ml, 1, expect_race); }
+  void Write2(const MemLoc &ml, bool expect_race = false) {
+    Write(ml, 2, expect_race); }
+  void Write4(const MemLoc &ml, bool expect_race = false) {
+    Write(ml, 4, expect_race); }
+  void Write8(const MemLoc &ml, bool expect_race = false) {
+    Write(ml, 8, expect_race); }
+
+  void VptrUpdate(const MemLoc &vptr, const MemLoc &new_val,
+                  bool expect_race = false);
+
+  void Call(void(*pc)());
+  void Return();
+
+  void Create(const Mutex &m);
+  void Destroy(const Mutex &m);
+  void Lock(const Mutex &m);
+  bool TryLock(const Mutex &m);
+  void Unlock(const Mutex &m);
+  void ReadLock(const Mutex &m);
+  bool TryReadLock(const Mutex &m);
+  void ReadUnlock(const Mutex &m);
+
+  void Memcpy(void *dst, const void *src, int size, bool expect_race = false);
+  void Memset(void *dst, int val, int size, bool expect_race = false);
+
+ private:
+  struct Impl;
+  Impl *impl_;
+  ScopedThread(const ScopedThread&);  // Not implemented.
+  void operator = (const ScopedThread&);  // Not implemented.
+};
+
+class MainThread : public ScopedThread {
+ public:
+  MainThread()
+    : ScopedThread(false, true) {
+  }
+};
+
+#endif  // #ifndef TSAN_TEST_UTIL_H

Added: compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test_util_linux.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test_util_linux.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test_util_linux.cc (added)
+++ compiler-rt/trunk/lib/tsan/rtl_tests/tsan_test_util_linux.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,460 @@
+//===-- tsan_test_util_linux.cc ---------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+// Test utils, linux implementation.
+//===----------------------------------------------------------------------===//
+
+#include "tsan_interface.h"
+#include "tsan_test_util.h"
+#include "tsan_atomic.h"
+#include "tsan_report.h"
+
+#include "gtest/gtest.h"
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+using namespace __tsan;  // NOLINT
+
+static __thread bool expect_report;
+static __thread bool expect_report_reported;
+static __thread ReportType expect_report_type;
+
+static void *BeforeInitThread(void *param) {
+  (void)param;
+  return 0;
+}
+
+static void AtExit() {
+}
+
+void TestMutexBeforeInit() {
+  // Mutexes must be usable before __tsan_init();
+  pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
+  pthread_mutex_lock(&mtx);
+  pthread_mutex_unlock(&mtx);
+  pthread_mutex_destroy(&mtx);
+  pthread_t thr;
+  pthread_create(&thr, 0, BeforeInitThread, 0);
+  pthread_join(thr, 0);
+  atexit(AtExit);
+}
+
+namespace __tsan {
+bool OnReport(const ReportDesc *rep, bool suppressed) {
+  if (expect_report) {
+    if (rep->typ != expect_report_type) {
+      printf("Expected report of type %d, got type %d\n",
+             (int)expect_report_type, (int)rep->typ);
+      EXPECT_FALSE("Wrong report type");
+      return false;
+    }
+  } else {
+    EXPECT_FALSE("Unexpected report");
+    return false;
+  }
+  expect_report_reported = true;
+  return true;
+}
+}
+
+static void* allocate_addr(int size, int offset_from_aligned = 0) {
+  static uintptr_t foo;
+  static atomic_uintptr_t uniq = {(uintptr_t)&foo};  // Some real address.
+  const int kAlign = 16;
+  CHECK(offset_from_aligned < kAlign);
+  size = (size + 2 * kAlign) & ~(kAlign - 1);
+  uintptr_t addr = atomic_fetch_add(&uniq, size, memory_order_relaxed);
+  return (void*)(addr + offset_from_aligned);
+}
+
+MemLoc::MemLoc(int offset_from_aligned)
+  : loc_(allocate_addr(16, offset_from_aligned)) {
+}
+
+MemLoc::~MemLoc() {
+}
+
+Mutex::Mutex(Type type)
+  : alive_()
+  , type_(type) {
+}
+
+Mutex::~Mutex() {
+  CHECK(!alive_);
+}
+
+void Mutex::Init() {
+  CHECK(!alive_);
+  alive_ = true;
+  if (type_ == Normal)
+    CHECK_EQ(pthread_mutex_init((pthread_mutex_t*)mtx_, 0), 0);
+  else if (type_ == Spin)
+    CHECK_EQ(pthread_spin_init((pthread_spinlock_t*)mtx_, 0), 0);
+  else if (type_ == RW)
+    CHECK_EQ(pthread_rwlock_init((pthread_rwlock_t*)mtx_, 0), 0);
+  else
+    CHECK(0);
+}
+
+void Mutex::StaticInit() {
+  CHECK(!alive_);
+  CHECK(type_ == Normal);
+  alive_ = true;
+  pthread_mutex_t tmp = PTHREAD_MUTEX_INITIALIZER;
+  memcpy(mtx_, &tmp, sizeof(tmp));
+}
+
+void Mutex::Destroy() {
+  CHECK(alive_);
+  alive_ = false;
+  if (type_ == Normal)
+    CHECK_EQ(pthread_mutex_destroy((pthread_mutex_t*)mtx_), 0);
+  else if (type_ == Spin)
+    CHECK_EQ(pthread_spin_destroy((pthread_spinlock_t*)mtx_), 0);
+  else if (type_ == RW)
+    CHECK_EQ(pthread_rwlock_destroy((pthread_rwlock_t*)mtx_), 0);
+}
+
+void Mutex::Lock() {
+  CHECK(alive_);
+  if (type_ == Normal)
+    CHECK_EQ(pthread_mutex_lock((pthread_mutex_t*)mtx_), 0);
+  else if (type_ == Spin)
+    CHECK_EQ(pthread_spin_lock((pthread_spinlock_t*)mtx_), 0);
+  else if (type_ == RW)
+    CHECK_EQ(pthread_rwlock_wrlock((pthread_rwlock_t*)mtx_), 0);
+}
+
+bool Mutex::TryLock() {
+  CHECK(alive_);
+  if (type_ == Normal)
+    return pthread_mutex_trylock((pthread_mutex_t*)mtx_) == 0;
+  else if (type_ == Spin)
+    return pthread_spin_trylock((pthread_spinlock_t*)mtx_) == 0;
+  else if (type_ == RW)
+    return pthread_rwlock_trywrlock((pthread_rwlock_t*)mtx_) == 0;
+  return false;
+}
+
+void Mutex::Unlock() {
+  CHECK(alive_);
+  if (type_ == Normal)
+    CHECK_EQ(pthread_mutex_unlock((pthread_mutex_t*)mtx_), 0);
+  else if (type_ == Spin)
+    CHECK_EQ(pthread_spin_unlock((pthread_spinlock_t*)mtx_), 0);
+  else if (type_ == RW)
+    CHECK_EQ(pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
+}
+
+void Mutex::ReadLock() {
+  CHECK(alive_);
+  CHECK(type_ == RW);
+  CHECK_EQ(pthread_rwlock_rdlock((pthread_rwlock_t*)mtx_), 0);
+}
+
+bool Mutex::TryReadLock() {
+  CHECK(alive_);
+  CHECK(type_ == RW);
+  return pthread_rwlock_tryrdlock((pthread_rwlock_t*)mtx_) ==  0;
+}
+
+void Mutex::ReadUnlock() {
+  CHECK(alive_);
+  CHECK(type_ == RW);
+  CHECK_EQ(pthread_rwlock_unlock((pthread_rwlock_t*)mtx_), 0);
+}
+
+struct Event {
+  enum Type {
+    SHUTDOWN,
+    READ,
+    WRITE,
+    VPTR_UPDATE,
+    CALL,
+    RETURN,
+    MUTEX_CREATE,
+    MUTEX_DESTROY,
+    MUTEX_LOCK,
+    MUTEX_TRYLOCK,
+    MUTEX_UNLOCK,
+    MUTEX_READLOCK,
+    MUTEX_TRYREADLOCK,
+    MUTEX_READUNLOCK,
+    MEMCPY,
+    MEMSET
+  };
+  Type type;
+  void *ptr;
+  uptr arg;
+  uptr arg2;
+  bool res;
+  bool expect_report;
+  ReportType report_type;
+
+  Event(Type type, const void *ptr = 0, uptr arg = 0, uptr arg2 = 0)
+    : type(type)
+    , ptr(const_cast<void*>(ptr))
+    , arg(arg)
+    , arg2(arg2)
+    , res()
+    , expect_report()
+    , report_type() {
+  }
+
+  void ExpectReport(ReportType type) {
+    expect_report = true;
+    report_type = type;
+  }
+};
+
+struct ScopedThread::Impl {
+  pthread_t thread;
+  bool main;
+  bool detached;
+  atomic_uintptr_t event;  // Event*
+
+  static void *ScopedThreadCallback(void *arg);
+  void send(Event *ev);
+  void HandleEvent(Event *ev);
+};
+
+void ScopedThread::Impl::HandleEvent(Event *ev) {
+  CHECK_EQ(expect_report, false);
+  expect_report = ev->expect_report;
+  expect_report_reported = false;
+  expect_report_type = ev->report_type;
+  switch (ev->type) {
+  case Event::READ:
+  case Event::WRITE: {
+    void (*tsan_mop)(void *addr) = 0;
+    if (ev->type == Event::READ) {
+      switch (ev->arg /*size*/) {
+        case 1: tsan_mop = __tsan_read1; break;
+        case 2: tsan_mop = __tsan_read2; break;
+        case 4: tsan_mop = __tsan_read4; break;
+        case 8: tsan_mop = __tsan_read8; break;
+        case 16: tsan_mop = __tsan_read16; break;
+      }
+    } else {
+      switch (ev->arg /*size*/) {
+        case 1: tsan_mop = __tsan_write1; break;
+        case 2: tsan_mop = __tsan_write2; break;
+        case 4: tsan_mop = __tsan_write4; break;
+        case 8: tsan_mop = __tsan_write8; break;
+        case 16: tsan_mop = __tsan_write16; break;
+      }
+    }
+    CHECK_NE(tsan_mop, 0);
+    errno = ECHRNG;
+    tsan_mop(ev->ptr);
+    CHECK_EQ(errno, ECHRNG);  // In no case must errno be changed.
+    break;
+  }
+  case Event::VPTR_UPDATE:
+    __tsan_vptr_update((void**)ev->ptr, (void*)ev->arg);
+    break;
+  case Event::CALL:
+    __tsan_func_entry((void*)((uptr)ev->ptr));
+    break;
+  case Event::RETURN:
+    __tsan_func_exit();
+    break;
+  case Event::MUTEX_CREATE:
+    static_cast<Mutex*>(ev->ptr)->Init();
+    break;
+  case Event::MUTEX_DESTROY:
+    static_cast<Mutex*>(ev->ptr)->Destroy();
+    break;
+  case Event::MUTEX_LOCK:
+    static_cast<Mutex*>(ev->ptr)->Lock();
+    break;
+  case Event::MUTEX_TRYLOCK:
+    ev->res = static_cast<Mutex*>(ev->ptr)->TryLock();
+    break;
+  case Event::MUTEX_UNLOCK:
+    static_cast<Mutex*>(ev->ptr)->Unlock();
+    break;
+  case Event::MUTEX_READLOCK:
+    static_cast<Mutex*>(ev->ptr)->ReadLock();
+    break;
+  case Event::MUTEX_TRYREADLOCK:
+    ev->res = static_cast<Mutex*>(ev->ptr)->TryReadLock();
+    break;
+  case Event::MUTEX_READUNLOCK:
+    static_cast<Mutex*>(ev->ptr)->ReadUnlock();
+    break;
+  case Event::MEMCPY:
+    memcpy(ev->ptr, (void*)ev->arg, ev->arg2);
+    break;
+  case Event::MEMSET:
+    memset(ev->ptr, ev->arg, ev->arg2);
+    break;
+  default: CHECK(0);
+  }
+  if (expect_report && !expect_report_reported) {
+    printf("Missed expected report of type %d\n", (int)ev->report_type);
+    EXPECT_FALSE("Missed expected race");
+  }
+  expect_report = false;
+}
+
+void *ScopedThread::Impl::ScopedThreadCallback(void *arg) {
+  __tsan_func_entry(__builtin_return_address(0));
+  Impl *impl = (Impl*)arg;
+  for (;;) {
+    Event* ev = (Event*)atomic_load(&impl->event, memory_order_acquire);
+    if (ev == 0) {
+      pthread_yield();
+      continue;
+    }
+    if (ev->type == Event::SHUTDOWN) {
+      atomic_store(&impl->event, 0, memory_order_release);
+      break;
+    }
+    impl->HandleEvent(ev);
+    atomic_store(&impl->event, 0, memory_order_release);
+  }
+  __tsan_func_exit();
+  return 0;
+}
+
+void ScopedThread::Impl::send(Event *e) {
+  if (main) {
+    HandleEvent(e);
+  } else {
+    CHECK_EQ(atomic_load(&event, memory_order_relaxed), 0);
+    atomic_store(&event, (uintptr_t)e, memory_order_release);
+    while (atomic_load(&event, memory_order_acquire) != 0)
+      pthread_yield();
+  }
+}
+
+ScopedThread::ScopedThread(bool detached, bool main) {
+  impl_ = new Impl;
+  impl_->main = main;
+  impl_->detached = detached;
+  atomic_store(&impl_->event, 0, memory_order_relaxed);
+  if (!main) {
+    pthread_attr_t attr;
+    pthread_attr_init(&attr);
+    pthread_attr_setdetachstate(&attr, detached);
+    pthread_create(&impl_->thread, &attr,
+        ScopedThread::Impl::ScopedThreadCallback, impl_);
+  }
+}
+
+ScopedThread::~ScopedThread() {
+  if (!impl_->main) {
+    Event event(Event::SHUTDOWN);
+    impl_->send(&event);
+    if (!impl_->detached)
+      pthread_join(impl_->thread, 0);
+  }
+  delete impl_;
+}
+
+void ScopedThread::Detach() {
+  CHECK(!impl_->main);
+  CHECK(!impl_->detached);
+  impl_->detached = true;
+  pthread_detach(impl_->thread);
+}
+
+void ScopedThread::Access(void *addr, bool is_write,
+                          int size, bool expect_race) {
+  Event event(is_write ? Event::WRITE : Event::READ, addr, size);
+  if (expect_race)
+    event.ExpectReport(ReportTypeRace);
+  impl_->send(&event);
+}
+
+void ScopedThread::VptrUpdate(const MemLoc &vptr,
+                              const MemLoc &new_val,
+                              bool expect_race) {
+  Event event(Event::VPTR_UPDATE, vptr.loc(), (uptr)new_val.loc());
+  if (expect_race)
+    event.ExpectReport(ReportTypeRace);
+  impl_->send(&event);
+}
+
+void ScopedThread::Call(void(*pc)()) {
+  Event event(Event::CALL, (void*)pc);
+  impl_->send(&event);
+}
+
+void ScopedThread::Return() {
+  Event event(Event::RETURN);
+  impl_->send(&event);
+}
+
+void ScopedThread::Create(const Mutex &m) {
+  Event event(Event::MUTEX_CREATE, &m);
+  impl_->send(&event);
+}
+
+void ScopedThread::Destroy(const Mutex &m) {
+  Event event(Event::MUTEX_DESTROY, &m);
+  impl_->send(&event);
+}
+
+void ScopedThread::Lock(const Mutex &m) {
+  Event event(Event::MUTEX_LOCK, &m);
+  impl_->send(&event);
+}
+
+bool ScopedThread::TryLock(const Mutex &m) {
+  Event event(Event::MUTEX_TRYLOCK, &m);
+  impl_->send(&event);
+  return event.res;
+}
+
+void ScopedThread::Unlock(const Mutex &m) {
+  Event event(Event::MUTEX_UNLOCK, &m);
+  impl_->send(&event);
+}
+
+void ScopedThread::ReadLock(const Mutex &m) {
+  Event event(Event::MUTEX_READLOCK, &m);
+  impl_->send(&event);
+}
+
+bool ScopedThread::TryReadLock(const Mutex &m) {
+  Event event(Event::MUTEX_TRYREADLOCK, &m);
+  impl_->send(&event);
+  return event.res;
+}
+
+void ScopedThread::ReadUnlock(const Mutex &m) {
+  Event event(Event::MUTEX_READUNLOCK, &m);
+  impl_->send(&event);
+}
+
+void ScopedThread::Memcpy(void *dst, const void *src, int size,
+                          bool expect_race) {
+  Event event(Event::MEMCPY, dst, (uptr)src, size);
+  if (expect_race)
+    event.ExpectReport(ReportTypeRace);
+  impl_->send(&event);
+}
+
+void ScopedThread::Memset(void *dst, int val, int size,
+                          bool expect_race) {
+  Event event(Event::MEMSET, dst, val, size);
+  if (expect_race)
+    event.ExpectReport(ReportTypeRace);
+  impl_->send(&event);
+}

Added: compiler-rt/trunk/lib/tsan/rtl_tests/tsan_thread.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/rtl_tests/tsan_thread.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/rtl_tests/tsan_thread.cc (added)
+++ compiler-rt/trunk/lib/tsan/rtl_tests/tsan_thread.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,59 @@
+//===-- tsan_thread.cc ------------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_test_util.h"
+#include "gtest/gtest.h"
+
+TEST(ThreadSanitizer, ThreadSync) {
+  MainThread t0;
+  MemLoc l;
+  t0.Write1(l);
+  {
+    ScopedThread t1;
+    t1.Write1(l);
+  }
+  t0.Write1(l);
+}
+
+TEST(ThreadSanitizer, ThreadDetach1) {
+  ScopedThread t1(true);
+  MemLoc l;
+  t1.Write1(l);
+}
+
+TEST(ThreadSanitizer, ThreadDetach2) {
+  ScopedThread t1;
+  MemLoc l;
+  t1.Write1(l);
+  t1.Detach();
+}
+
+static void *thread_alot_func(void *arg) {
+  (void)arg;
+  int usleep(unsigned);
+  usleep(50);
+  return 0;
+}
+
+TEST(DISABLED_SLOW_ThreadSanitizer, ThreadALot) {
+  const int kThreads = 70000;
+  const int kAlive = 1000;
+  pthread_t threads[kAlive] = {};
+  for (int i = 0; i < kThreads; i++) {
+    if (threads[i % kAlive])
+      pthread_join(threads[i % kAlive], 0);
+    pthread_create(&threads[i % kAlive], 0, thread_alot_func, 0);
+  }
+  for (int i = 0; i < kAlive; i++) {
+    pthread_join(threads[i], 0);
+  }
+}

Added: compiler-rt/trunk/lib/tsan/unit_tests/tsan_allocator_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/unit_tests/tsan_allocator_test.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/unit_tests/tsan_allocator_test.cc (added)
+++ compiler-rt/trunk/lib/tsan/unit_tests/tsan_allocator_test.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,56 @@
+//===-- tsan_allocator_test.c------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_allocator.h"
+#include "gtest/gtest.h"
+#include <stdlib.h>
+
+namespace __tsan {
+
+TEST(Allocator, Basic) {
+  char *p = (char*)Alloc(10);
+  EXPECT_NE(p, (char*)0);
+  char *p2 = (char*)Alloc(20);
+  EXPECT_NE(p2, (char*)0);
+  EXPECT_NE(p2, p);
+  for (int i = 0; i < 10; i++) {
+    p[i] = 42;
+    EXPECT_EQ(p, AllocBlock(p + i));
+  }
+  for (int i = 0; i < 20; i++) {
+    ((char*)p2)[i] = 42;
+    EXPECT_EQ(p2, AllocBlock(p2 + i));
+  }
+  Free(p);
+  Free(p2);
+}
+
+TEST(Allocator, Stress) {
+  const int kCount = 1000;
+  char *ptrs[kCount];
+  unsigned rnd = 42;
+  for (int i = 0; i < kCount; i++) {
+    uptr sz = rand_r(&rnd) % 1000;
+    char *p = (char*)Alloc(sz);
+    EXPECT_NE(p, (char*)0);
+    for (uptr j = 0; j < sz; j++) {
+      p[j] = 42;
+      EXPECT_EQ(p, AllocBlock(p + j));
+    }
+    ptrs[i] = p;
+  }
+  for (int i = 0; i < kCount; i++) {
+    Free(ptrs[i]);
+  }
+}
+
+}  // namespace __tsan

Added: compiler-rt/trunk/lib/tsan/unit_tests/tsan_clock_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/unit_tests/tsan_clock_test.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/unit_tests/tsan_clock_test.cc (added)
+++ compiler-rt/trunk/lib/tsan/unit_tests/tsan_clock_test.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,123 @@
+//===-- tsan_clock_test.cc --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_clock.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+TEST(Clock, VectorBasic) {
+  ScopedInRtl in_rtl;
+  ThreadClock clk;
+  CHECK_EQ(clk.size(), 0);
+  clk.tick(0);
+  CHECK_EQ(clk.size(), 1);
+  CHECK_EQ(clk.get(0), 1);
+  clk.tick(3);
+  CHECK_EQ(clk.size(), 4);
+  CHECK_EQ(clk.get(0), 1);
+  CHECK_EQ(clk.get(1), 0);
+  CHECK_EQ(clk.get(2), 0);
+  CHECK_EQ(clk.get(3), 1);
+  clk.tick(3);
+  CHECK_EQ(clk.get(3), 2);
+}
+
+TEST(Clock, ChunkedBasic) {
+  ScopedInRtl in_rtl;
+  ThreadClock vector;
+  SyncClock chunked;
+  CHECK_EQ(vector.size(), 0);
+  CHECK_EQ(chunked.size(), 0);
+  vector.acquire(&chunked);
+  CHECK_EQ(vector.size(), 0);
+  CHECK_EQ(chunked.size(), 0);
+  vector.release(&chunked);
+  CHECK_EQ(vector.size(), 0);
+  CHECK_EQ(chunked.size(), 0);
+  vector.acq_rel(&chunked);
+  CHECK_EQ(vector.size(), 0);
+  CHECK_EQ(chunked.size(), 0);
+}
+
+TEST(Clock, AcquireRelease) {
+  ScopedInRtl in_rtl;
+  ThreadClock vector1;
+  vector1.tick(100);
+  SyncClock chunked;
+  vector1.release(&chunked);
+  CHECK_EQ(chunked.size(), 101);
+  ThreadClock vector2;
+  vector2.acquire(&chunked);
+  CHECK_EQ(vector2.size(), 101);
+  CHECK_EQ(vector2.get(0), 0);
+  CHECK_EQ(vector2.get(1), 0);
+  CHECK_EQ(vector2.get(99), 0);
+  CHECK_EQ(vector2.get(100), 1);
+}
+
+TEST(Clock, ManyThreads) {
+  ScopedInRtl in_rtl;
+  SyncClock chunked;
+  for (int i = 0; i < 100; i++) {
+    ThreadClock vector;
+    vector.tick(i);
+    vector.release(&chunked);
+    CHECK_EQ(chunked.size(), i + 1);
+    vector.acquire(&chunked);
+    CHECK_EQ(vector.size(), i + 1);
+  }
+  ThreadClock vector;
+  vector.acquire(&chunked);
+  CHECK_EQ(vector.size(), 100);
+  for (int i = 0; i < 100; i++)
+    CHECK_EQ(vector.get(i), 1);
+}
+
+TEST(Clock, DifferentSizes) {
+  ScopedInRtl in_rtl;
+  {
+    ThreadClock vector1;
+    vector1.tick(10);
+    ThreadClock vector2;
+    vector2.tick(20);
+    {
+      SyncClock chunked;
+      vector1.release(&chunked);
+      CHECK_EQ(chunked.size(), 11);
+      vector2.release(&chunked);
+      CHECK_EQ(chunked.size(), 21);
+    }
+    {
+      SyncClock chunked;
+      vector2.release(&chunked);
+      CHECK_EQ(chunked.size(), 21);
+      vector1.release(&chunked);
+      CHECK_EQ(chunked.size(), 21);
+    }
+    {
+      SyncClock chunked;
+      vector1.release(&chunked);
+      vector2.acquire(&chunked);
+      CHECK_EQ(vector2.size(), 21);
+    }
+    {
+      SyncClock chunked;
+      vector2.release(&chunked);
+      vector1.acquire(&chunked);
+      CHECK_EQ(vector1.size(), 21);
+    }
+  }
+}
+
+}  // namespace __tsan

Added: compiler-rt/trunk/lib/tsan/unit_tests/tsan_flags_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/unit_tests/tsan_flags_test.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/unit_tests/tsan_flags_test.cc (added)
+++ compiler-rt/trunk/lib/tsan/unit_tests/tsan_flags_test.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,107 @@
+//===-- tsan_flags_test.cc --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_flags.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+TEST(Flags, Basic) {
+  ScopedInRtl in_rtl;
+  // At least should not crash.
+  Flags f = {};
+  InitializeFlags(&f, 0);
+  InitializeFlags(&f, "");
+}
+
+TEST(Flags, ParseBool) {
+  ScopedInRtl in_rtl;
+  Flags f = {};
+
+  f.enable_annotations = false;
+  InitializeFlags(&f, "enable_annotations");
+  EXPECT_EQ(f.enable_annotations, true);
+
+  f.enable_annotations = false;
+  InitializeFlags(&f, "--enable_annotations");
+  EXPECT_EQ(f.enable_annotations, true);
+
+  f.enable_annotations = false;
+  InitializeFlags(&f, "--enable_annotations=1");
+  EXPECT_EQ(f.enable_annotations, true);
+
+  // This flag is false by default.
+  f.force_seq_cst_atomics = false;
+  InitializeFlags(&f, "--force_seq_cst_atomics=1");
+  EXPECT_EQ(f.force_seq_cst_atomics, true);
+
+  f.enable_annotations = true;
+  InitializeFlags(&f, "asdas enable_annotations=0 asdasd");
+  EXPECT_EQ(f.enable_annotations, false);
+
+  f.enable_annotations = true;
+  InitializeFlags(&f, "   --enable_annotations=0   ");
+  EXPECT_EQ(f.enable_annotations, false);
+}
+
+TEST(Flags, ParseInt) {
+  ScopedInRtl in_rtl;
+  Flags f = {};
+
+  f.exitcode = -11;
+  InitializeFlags(&f, "exitcode");
+  EXPECT_EQ(f.exitcode, 0);
+
+  f.exitcode = -11;
+  InitializeFlags(&f, "--exitcode=");
+  EXPECT_EQ(f.exitcode, 0);
+
+  f.exitcode = -11;
+  InitializeFlags(&f, "--exitcode=42");
+  EXPECT_EQ(f.exitcode, 42);
+
+  f.exitcode = -11;
+  InitializeFlags(&f, "--exitcode=-42");
+  EXPECT_EQ(f.exitcode, -42);
+}
+
+TEST(Flags, ParseStr) {
+  ScopedInRtl in_rtl;
+  Flags f = {};
+
+  InitializeFlags(&f, 0);
+  EXPECT_EQ(0, strcmp(f.strip_path_prefix, ""));
+  FinalizeFlags(&f);
+
+  InitializeFlags(&f, "strip_path_prefix");
+  EXPECT_EQ(0, strcmp(f.strip_path_prefix, ""));
+  FinalizeFlags(&f);
+
+  InitializeFlags(&f, "--strip_path_prefix=");
+  EXPECT_EQ(0, strcmp(f.strip_path_prefix, ""));
+  FinalizeFlags(&f);
+
+  InitializeFlags(&f, "--strip_path_prefix=abc");
+  EXPECT_EQ(0, strcmp(f.strip_path_prefix, "abc"));
+  FinalizeFlags(&f);
+
+  InitializeFlags(&f, "--strip_path_prefix='abc zxc'");
+  EXPECT_EQ(0, strcmp(f.strip_path_prefix, "abc zxc"));
+  FinalizeFlags(&f);
+
+  InitializeFlags(&f, "--strip_path_prefix=\"abc zxc\"");
+  EXPECT_EQ(0, strcmp(f.strip_path_prefix, "abc zxc"));
+  FinalizeFlags(&f);
+}
+
+}  // namespace __tsan

Added: compiler-rt/trunk/lib/tsan/unit_tests/tsan_mman_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/unit_tests/tsan_mman_test.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/unit_tests/tsan_mman_test.cc (added)
+++ compiler-rt/trunk/lib/tsan/unit_tests/tsan_mman_test.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,109 @@
+//===-- tsan_mman_test.cc ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_mman.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+TEST(Mman, Internal) {
+  ScopedInRtl in_rtl;
+  char *p = (char*)internal_alloc(MBlockScopedBuf, 10);
+  EXPECT_NE(p, (char*)0);
+  char *p2 = (char*)internal_alloc(MBlockScopedBuf, 20);
+  EXPECT_NE(p2, (char*)0);
+  EXPECT_NE(p2, p);
+  for (int i = 0; i < 10; i++) {
+    p[i] = 42;
+  }
+  for (int i = 0; i < 20; i++) {
+    ((char*)p2)[i] = 42;
+  }
+  internal_free(p);
+  internal_free(p2);
+}
+
+TEST(Mman, User) {
+  ScopedInRtl in_rtl;
+  ThreadState *thr = cur_thread();
+  uptr pc = 0;
+  char *p = (char*)user_alloc(thr, pc, 10);
+  EXPECT_NE(p, (char*)0);
+  char *p2 = (char*)user_alloc(thr, pc, 20);
+  EXPECT_NE(p2, (char*)0);
+  EXPECT_NE(p2, p);
+  MBlock *b = user_mblock(thr, p);
+  EXPECT_NE(b, (MBlock*)0);
+  EXPECT_EQ(b->size, (uptr)10);
+  MBlock *b2 = user_mblock(thr, p2);
+  EXPECT_NE(b2, (MBlock*)0);
+  EXPECT_EQ(b2->size, (uptr)20);
+  for (int i = 0; i < 10; i++) {
+    p[i] = 42;
+    EXPECT_EQ(b, user_mblock(thr, p + i));
+  }
+  for (int i = 0; i < 20; i++) {
+    ((char*)p2)[i] = 42;
+    EXPECT_EQ(b2, user_mblock(thr, p2 + i));
+  }
+  user_free(thr, pc, p);
+  user_free(thr, pc, p2);
+}
+
+TEST(Mman, UserRealloc) {
+  ScopedInRtl in_rtl;
+  ThreadState *thr = cur_thread();
+  uptr pc = 0;
+  {
+    void *p = user_realloc(thr, pc, 0, 0);
+    // Strictly saying this is incorrect, realloc(NULL, N) is equivalent to
+    // malloc(N), thus must return non-NULL pointer.
+    EXPECT_EQ(p, (void*)0);
+  }
+  {
+    void *p = user_realloc(thr, pc, 0, 100);
+    EXPECT_NE(p, (void*)0);
+    memset(p, 0xde, 100);
+    user_free(thr, pc, p);
+  }
+  {
+    void *p = user_alloc(thr, pc, 100);
+    EXPECT_NE(p, (void*)0);
+    memset(p, 0xde, 100);
+    void *p2 = user_realloc(thr, pc, p, 0);
+    EXPECT_EQ(p2, (void*)0);
+  }
+  {
+    void *p = user_realloc(thr, pc, 0, 100);
+    EXPECT_NE(p, (void*)0);
+    memset(p, 0xde, 100);
+    void *p2 = user_realloc(thr, pc, p, 10000);
+    EXPECT_NE(p2, (void*)0);
+    for (int i = 0; i < 100; i++)
+      EXPECT_EQ(((char*)p2)[i], (char)0xde);
+    memset(p2, 0xde, 10000);
+    user_free(thr, pc, p2);
+  }
+  {
+    void *p = user_realloc(thr, pc, 0, 10000);
+    EXPECT_NE(p, (void*)0);
+    memset(p, 0xde, 10000);
+    void *p2 = user_realloc(thr, pc, p, 10);
+    EXPECT_NE(p2, (void*)0);
+    for (int i = 0; i < 10; i++)
+      EXPECT_EQ(((char*)p2)[i], (char)0xde);
+    user_free(thr, pc, p2);
+  }
+}
+
+}  // namespace __tsan

Added: compiler-rt/trunk/lib/tsan/unit_tests/tsan_mutex_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/unit_tests/tsan_mutex_test.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/unit_tests/tsan_mutex_test.cc (added)
+++ compiler-rt/trunk/lib/tsan/unit_tests/tsan_mutex_test.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,101 @@
+//===-- tsan_mutex_test.cc --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_atomic.h"
+#include "tsan_mutex.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+class TestData {
+ public:
+  TestData()
+    : mtx_(MutexTypeAnnotations, StatMtxAnnotations) {
+    for (int i = 0; i < kSize; i++)
+      data_[i] = 0;
+  }
+
+  void Write() {
+    Lock l(&mtx_);
+    T v0 = data_[0];
+    for (int i = 0; i < kSize; i++) {
+      CHECK_EQ(data_[i], v0);
+      data_[i]++;
+    }
+  }
+
+  void Read() {
+    ReadLock l(&mtx_);
+    T v0 = data_[0];
+    for (int i = 0; i < kSize; i++) {
+      CHECK_EQ(data_[i], v0);
+    }
+  }
+
+ private:
+  static const int kSize = 64;
+  typedef u64 T;
+  Mutex mtx_;
+  char pad_[kCacheLineSize];
+  T data_[kSize];
+};
+
+const int kThreads = 8;
+const int kWriteRate = 1024;
+#if TSAN_DEBUG
+const int kIters = 16*1024;
+#else
+const int kIters = 64*1024;
+#endif
+
+static void *write_mutex_thread(void *param) {
+  TestData *data = (TestData *)param;
+  TestData local;
+  for (int i = 0; i < kIters; i++) {
+    data->Write();
+    local.Write();
+  }
+  return 0;
+}
+
+static void *read_mutex_thread(void *param) {
+  TestData *data = (TestData *)param;
+  TestData local;
+  for (int i = 0; i < kIters; i++) {
+    if ((i % kWriteRate) == 0)
+      data->Write();
+    else
+      data->Read();
+    local.Write();
+  }
+  return 0;
+}
+
+TEST(Mutex, Write) {
+  TestData data;
+  pthread_t threads[kThreads];
+  for (int i = 0; i < kThreads; i++)
+    pthread_create(&threads[i], 0, write_mutex_thread, &data);
+  for (int i = 0; i < kThreads; i++)
+    pthread_join(threads[i], 0);
+}
+
+TEST(Mutex, ReadWrite) {
+  TestData data;
+  pthread_t threads[kThreads];
+  for (int i = 0; i < kThreads; i++)
+    pthread_create(&threads[i], 0, read_mutex_thread, &data);
+  for (int i = 0; i < kThreads; i++)
+    pthread_join(threads[i], 0);
+}
+
+}  // namespace __tsan

Added: compiler-rt/trunk/lib/tsan/unit_tests/tsan_platform_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/unit_tests/tsan_platform_test.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/unit_tests/tsan_platform_test.cc (added)
+++ compiler-rt/trunk/lib/tsan/unit_tests/tsan_platform_test.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,83 @@
+//===-- tsan_platform_test.cc -----------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_platform.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+static void *TestThreadInfo(void *arg) {
+  ScopedInRtl in_rtl;
+  uptr stk_addr = 0;
+  uptr stk_size = 0;
+  uptr tls_addr = 0;
+  uptr tls_size = 0;
+  GetThreadStackAndTls(&stk_addr, &stk_size, &tls_addr, &tls_size);
+  // Printf("stk=%lx-%lx(%lu)\n", stk_addr, stk_addr + stk_size, stk_size);
+  // Printf("tls=%lx-%lx(%lu)\n", tls_addr, tls_addr + tls_size, tls_size);
+
+  int stack_var;
+  EXPECT_NE(stk_addr, (uptr)0);
+  EXPECT_NE(stk_size, (uptr)0);
+  EXPECT_GT((uptr)&stack_var, stk_addr);
+  EXPECT_LT((uptr)&stack_var, stk_addr + stk_size);
+
+  static __thread int thread_var;
+  EXPECT_NE(tls_addr, (uptr)0);
+  EXPECT_NE(tls_size, (uptr)0);
+  EXPECT_GT((uptr)&thread_var, tls_addr);
+  EXPECT_LT((uptr)&thread_var, tls_addr + tls_size);
+
+  // Ensure that tls and stack do not intersect.
+  uptr tls_end = tls_addr + tls_size;
+  EXPECT_TRUE(tls_addr < stk_addr || tls_addr >= stk_addr + stk_size);
+  EXPECT_TRUE(tls_end  < stk_addr || tls_end  >=  stk_addr + stk_size);
+  EXPECT_TRUE((tls_addr < stk_addr) == (tls_end  < stk_addr));
+  return 0;
+}
+
+TEST(Platform, ThreadInfoMain) {
+  TestThreadInfo(0);
+}
+
+TEST(Platform, ThreadInfoWorker) {
+  pthread_t t;
+  pthread_create(&t, 0, TestThreadInfo, 0);
+  pthread_join(t, 0);
+}
+
+TEST(Platform, FileOps) {
+  const char *str1 = "qwerty";
+  uptr len1 = internal_strlen(str1);
+  const char *str2 = "zxcv";
+  uptr len2 = internal_strlen(str2);
+
+  fd_t fd = internal_open("./tsan_test.tmp", true);
+  EXPECT_NE(fd, kInvalidFd);
+  EXPECT_EQ(len1, internal_write(fd, str1, len1));
+  EXPECT_EQ(len2, internal_write(fd, str2, len2));
+  internal_close(fd);
+  
+  fd = internal_open("./tsan_test.tmp", false);
+  EXPECT_NE(fd, kInvalidFd);
+  EXPECT_EQ(len1 + len2, internal_filesize(fd));
+  char buf[64] = {};
+  EXPECT_EQ(len1, internal_read(fd, buf, len1));
+  EXPECT_EQ(0, internal_memcmp(buf, str1, len1));
+  EXPECT_EQ((char)0, buf[len1 + 1]);
+  internal_memset(buf, 0, len1);
+  EXPECT_EQ(len2, internal_read(fd, buf, len2));
+  EXPECT_EQ(0, internal_memcmp(buf, str2, len2));
+  internal_close(fd);
+}
+
+}  // namespace __tsan

Added: compiler-rt/trunk/lib/tsan/unit_tests/tsan_printf_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/unit_tests/tsan_printf_test.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/unit_tests/tsan_printf_test.cc (added)
+++ compiler-rt/trunk/lib/tsan/unit_tests/tsan_printf_test.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,109 @@
+//===-- tsan_printf_test.cc -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+
+#include <string.h>
+#include <limits.h>
+
+namespace __tsan {
+
+TEST(Printf, Basic) {
+  char buf[1024];
+  uptr len = Snprintf(buf, sizeof(buf),
+      "a%db%ldc%lldd%ue%luf%llug%xh%lxq%llxw%pe%sr",
+      (int)-1, (long)-2, (long long)-3,  // NOLINT
+      (unsigned)-4, (unsigned long)5, (unsigned long long)6,  // NOLINT
+      (unsigned)10, (unsigned long)11, (unsigned long long)12,  // NOLINT
+      (void*)0x123, "_string_");
+  EXPECT_EQ(len, strlen(buf));
+  EXPECT_EQ(0, strcmp(buf, "a-1b-2c-3d4294967292e5f6gahbqcw"
+                           "0x000000000123e_string_r"));
+}
+
+TEST(Printf, OverflowStr) {
+  char buf[] = "123456789";
+  uptr len = Snprintf(buf, 4, "%s", "abcdef");
+  EXPECT_EQ(len, (uptr)6);
+  EXPECT_EQ(0, strcmp(buf, "abc"));
+  EXPECT_EQ(buf[3], 0);
+  EXPECT_EQ(buf[4], '5');
+  EXPECT_EQ(buf[5], '6');
+  EXPECT_EQ(buf[6], '7');
+  EXPECT_EQ(buf[7], '8');
+  EXPECT_EQ(buf[8], '9');
+  EXPECT_EQ(buf[9], 0);
+}
+
+TEST(Printf, OverflowInt) {
+  char buf[] = "123456789";
+  Snprintf(buf, 4, "%d", -123456789);
+  EXPECT_EQ(0, strcmp(buf, "-12"));
+  EXPECT_EQ(buf[3], 0);
+  EXPECT_EQ(buf[4], '5');
+  EXPECT_EQ(buf[5], '6');
+  EXPECT_EQ(buf[6], '7');
+  EXPECT_EQ(buf[7], '8');
+  EXPECT_EQ(buf[8], '9');
+  EXPECT_EQ(buf[9], 0);
+}
+
+TEST(Printf, OverflowUint) {
+  char buf[] = "123456789";
+  Snprintf(buf, 4, "a%llx", (long long)0x123456789);  // NOLINT
+  EXPECT_EQ(0, strcmp(buf, "a12"));
+  EXPECT_EQ(buf[3], 0);
+  EXPECT_EQ(buf[4], '5');
+  EXPECT_EQ(buf[5], '6');
+  EXPECT_EQ(buf[6], '7');
+  EXPECT_EQ(buf[7], '8');
+  EXPECT_EQ(buf[8], '9');
+  EXPECT_EQ(buf[9], 0);
+}
+
+TEST(Printf, OverflowPtr) {
+  char buf[] = "123456789";
+  Snprintf(buf, 4, "%p", (void*)0x123456789);
+  EXPECT_EQ(0, strcmp(buf, "0x0"));
+  EXPECT_EQ(buf[3], 0);
+  EXPECT_EQ(buf[4], '5');
+  EXPECT_EQ(buf[5], '6');
+  EXPECT_EQ(buf[6], '7');
+  EXPECT_EQ(buf[7], '8');
+  EXPECT_EQ(buf[8], '9');
+  EXPECT_EQ(buf[9], 0);
+}
+
+template<typename T>
+static void TestMinMax(const char *fmt, T min, T max) {
+  char buf[1024];
+  uptr len = Snprintf(buf, sizeof(buf), fmt, min, max);
+  char buf2[1024];
+  snprintf(buf2, sizeof(buf2), fmt, min, max);
+  EXPECT_EQ(len, strlen(buf));
+  EXPECT_EQ(0, strcmp(buf, buf2));
+}
+
+TEST(Printf, MinMax) {
+  TestMinMax<int>("%d-%d", INT_MIN, INT_MAX);  // NOLINT
+  TestMinMax<long>("%ld-%ld", LONG_MIN, LONG_MAX);  // NOLINT
+  TestMinMax<long long>("%lld-%lld", LLONG_MIN, LLONG_MAX);  // NOLINT
+  TestMinMax<unsigned>("%u-%u", 0, UINT_MAX);  // NOLINT
+  TestMinMax<unsigned long>("%lu-%lu", 0, ULONG_MAX);  // NOLINT
+  TestMinMax<unsigned long long>("%llu-%llu", 0, ULLONG_MAX);  // NOLINT
+  TestMinMax<unsigned>("%x-%x", 0, UINT_MAX);  // NOLINT
+  TestMinMax<unsigned long>("%lx-%lx", 0, ULONG_MAX);  // NOLINT
+  TestMinMax<unsigned long long>("%llx-%llx", 0, ULLONG_MAX);  // NOLINT
+}
+
+}  // namespace __tsan

Added: compiler-rt/trunk/lib/tsan/unit_tests/tsan_shadow_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/unit_tests/tsan_shadow_test.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/unit_tests/tsan_shadow_test.cc (added)
+++ compiler-rt/trunk/lib/tsan/unit_tests/tsan_shadow_test.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,47 @@
+//===-- tsan_shadow_test.cc -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_platform.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+TEST(Shadow, Mapping) {
+  static int global;
+  int stack;
+  void *heap = malloc(0);
+  free(heap);
+
+  CHECK(IsAppMem((uptr)&global));
+  CHECK(IsAppMem((uptr)&stack));
+  CHECK(IsAppMem((uptr)heap));
+
+  CHECK(IsShadowMem(MemToShadow((uptr)&global)));
+  CHECK(IsShadowMem(MemToShadow((uptr)&stack)));
+  CHECK(IsShadowMem(MemToShadow((uptr)heap)));
+}
+
+TEST(Shadow, Celling) {
+  u64 aligned_data[4];
+  char *data = (char*)aligned_data;
+  CHECK_EQ((uptr)data % kShadowSize, 0);
+  uptr s0 = MemToShadow((uptr)&data[0]);
+  CHECK_EQ(s0 % kShadowSize, 0);
+  for (unsigned i = 1; i < kShadowCell; i++)
+    CHECK_EQ(s0, MemToShadow((uptr)&data[i]));
+  for (unsigned i = kShadowCell; i < 2*kShadowCell; i++)
+    CHECK_EQ(s0 + kShadowSize*kShadowCnt, MemToShadow((uptr)&data[i]));
+  for (unsigned i = 2*kShadowCell; i < 3*kShadowCell; i++)
+    CHECK_EQ(s0 + 2*kShadowSize*kShadowCnt, MemToShadow((uptr)&data[i]));
+}
+
+}  // namespace __tsan

Added: compiler-rt/trunk/lib/tsan/unit_tests/tsan_suppressions_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/unit_tests/tsan_suppressions_test.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/unit_tests/tsan_suppressions_test.cc (added)
+++ compiler-rt/trunk/lib/tsan/unit_tests/tsan_suppressions_test.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,132 @@
+//===-- tsan_suppressions_test.cc -------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_suppressions.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+
+#include <string.h>
+
+namespace __tsan {
+
+TEST(Suppressions, Parse) {
+  ScopedInRtl in_rtl;
+  Suppression *supp0 = SuppressionParse(
+    "race:foo\n"
+    " 	race:bar\n"  // NOLINT
+    "race:baz	 \n"  // NOLINT
+    "# a comment\n"
+    "race:quz\n"
+  );  // NOLINT
+  Suppression *supp = supp0;
+  EXPECT_EQ(supp->type, SuppressionRace);
+  EXPECT_EQ(0, strcmp(supp->func, "quz"));
+  supp = supp->next;
+  EXPECT_EQ(supp->type, SuppressionRace);
+  EXPECT_EQ(0, strcmp(supp->func, "baz"));
+  supp = supp->next;
+  EXPECT_EQ(supp->type, SuppressionRace);
+  EXPECT_EQ(0, strcmp(supp->func, "bar"));
+  supp = supp->next;
+  EXPECT_EQ(supp->type, SuppressionRace);
+  EXPECT_EQ(0, strcmp(supp->func, "foo"));
+  supp = supp->next;
+  EXPECT_EQ((Suppression*)0, supp);
+  SuppressionFree(supp0);
+}
+
+TEST(Suppressions, Parse2) {
+  ScopedInRtl in_rtl;
+  Suppression *supp0 = SuppressionParse(
+    "  	# first line comment\n"  // NOLINT
+    " 	race:bar 	\n"  // NOLINT
+    "race:baz* *baz\n"
+    "# a comment\n"
+    "# last line comment\n"
+  );  // NOLINT
+  Suppression *supp = supp0;
+  EXPECT_EQ(supp->type, SuppressionRace);
+  EXPECT_EQ(0, strcmp(supp->func, "baz* *baz"));
+  supp = supp->next;
+  EXPECT_EQ(supp->type, SuppressionRace);
+  EXPECT_EQ(0, strcmp(supp->func, "bar"));
+  supp = supp->next;
+  EXPECT_EQ((Suppression*)0, supp);
+  SuppressionFree(supp0);
+}
+
+TEST(Suppressions, Parse3) {
+  ScopedInRtl in_rtl;
+  Suppression *supp0 = SuppressionParse(
+    "# last suppression w/o line-feed\n"
+    "race:foo\n"
+    "race:bar"
+  );  // NOLINT
+  Suppression *supp = supp0;
+  EXPECT_EQ(supp->type, SuppressionRace);
+  EXPECT_EQ(0, strcmp(supp->func, "bar"));
+  supp = supp->next;
+  EXPECT_EQ(supp->type, SuppressionRace);
+  EXPECT_EQ(0, strcmp(supp->func, "foo"));
+  supp = supp->next;
+  EXPECT_EQ((Suppression*)0, supp);
+  SuppressionFree(supp0);
+}
+
+TEST(Suppressions, ParseType) {
+  ScopedInRtl in_rtl;
+  Suppression *supp0 = SuppressionParse(
+    "race:foo\n"
+    "thread:bar\n"
+    "mutex:baz\n"
+    "signal:quz\n"
+  );  // NOLINT
+  Suppression *supp = supp0;
+  EXPECT_EQ(supp->type, SuppressionSignal);
+  EXPECT_EQ(0, strcmp(supp->func, "quz"));
+  supp = supp->next;
+  EXPECT_EQ(supp->type, SuppressionMutex);
+  EXPECT_EQ(0, strcmp(supp->func, "baz"));
+  supp = supp->next;
+  EXPECT_EQ(supp->type, SuppressionThread);
+  EXPECT_EQ(0, strcmp(supp->func, "bar"));
+  supp = supp->next;
+  EXPECT_EQ(supp->type, SuppressionRace);
+  EXPECT_EQ(0, strcmp(supp->func, "foo"));
+  supp = supp->next;
+  EXPECT_EQ((Suppression*)0, supp);
+  SuppressionFree(supp0);
+}
+
+static bool MyMatch(const char *templ, const char *func) {
+  char tmp[1024];
+  strcpy(tmp, templ);  // NOLINT
+  return SuppressionMatch(tmp, func);
+}
+
+TEST(Suppressions, Match) {
+  EXPECT_TRUE(MyMatch("foobar", "foobar"));
+  EXPECT_TRUE(MyMatch("foobar", "prefix_foobar_postfix"));
+  EXPECT_TRUE(MyMatch("*foobar*", "prefix_foobar_postfix"));
+  EXPECT_TRUE(MyMatch("foo*bar", "foo_middle_bar"));
+  EXPECT_TRUE(MyMatch("foo*bar", "foobar"));
+  EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_bar_another_baz"));
+  EXPECT_TRUE(MyMatch("foo*bar*baz", "foo_middle_barbaz"));
+
+  EXPECT_FALSE(MyMatch("foo", "baz"));
+  EXPECT_FALSE(MyMatch("foobarbaz", "foobar"));
+  EXPECT_FALSE(MyMatch("foobarbaz", "barbaz"));
+  EXPECT_FALSE(MyMatch("foo*bar", "foobaz"));
+  EXPECT_FALSE(MyMatch("foo*bar", "foo_baz"));
+}
+
+}  // namespace __tsan

Added: compiler-rt/trunk/lib/tsan/unit_tests/tsan_sync_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/unit_tests/tsan_sync_test.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/unit_tests/tsan_sync_test.cc (added)
+++ compiler-rt/trunk/lib/tsan/unit_tests/tsan_sync_test.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,65 @@
+//===-- tsan_sync_test.cc ---------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_sync.h"
+#include "tsan_rtl.h"
+#include "tsan_mman.h"
+#include "gtest/gtest.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <map>
+
+namespace __tsan {
+
+TEST(Sync, Table) {
+  const uintptr_t kIters = 512*1024;
+  const uintptr_t kRange = 10000;
+
+  ScopedInRtl in_rtl;
+  ThreadState *thr = cur_thread();
+  uptr pc = 0;
+
+  SyncTab tab;
+  SyncVar *golden[kRange] = {};
+  unsigned seed = 0;
+  for (uintptr_t i = 0; i < kIters; i++) {
+    uintptr_t addr = rand_r(&seed) % (kRange - 1) + 1;
+    if (rand_r(&seed) % 2) {
+      // Get or add.
+      SyncVar *v = tab.GetAndLock(thr, pc, addr, true);
+      EXPECT_TRUE(golden[addr] == 0 || golden[addr] == v);
+      EXPECT_EQ(v->addr, addr);
+      golden[addr] = v;
+      v->mtx.Unlock();
+    } else {
+      // Remove.
+      SyncVar *v = tab.GetAndRemove(thr, pc, addr);
+      EXPECT_EQ(golden[addr], v);
+      if (v) {
+        EXPECT_EQ(v->addr, addr);
+        golden[addr] = 0;
+        DestroyAndFree(v);
+      }
+    }
+  }
+  for (uintptr_t addr = 0; addr < kRange; addr++) {
+    if (golden[addr] == 0)
+      continue;
+    SyncVar *v = tab.GetAndRemove(thr, pc, addr);
+    EXPECT_EQ(v, golden[addr]);
+    EXPECT_EQ(v->addr, addr);
+    DestroyAndFree(v);
+  }
+}
+
+}  // namespace __tsan

Added: compiler-rt/trunk/lib/tsan/unit_tests/tsan_vector_test.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/tsan/unit_tests/tsan_vector_test.cc?rev=156545&view=auto
==============================================================================
--- compiler-rt/trunk/lib/tsan/unit_tests/tsan_vector_test.cc (added)
+++ compiler-rt/trunk/lib/tsan/unit_tests/tsan_vector_test.cc Thu May 10 09:18:22 2012
@@ -0,0 +1,45 @@
+//===-- tsan_vector_test.cc -------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_vector.h"
+#include "tsan_rtl.h"
+#include "gtest/gtest.h"
+
+namespace __tsan {
+
+TEST(Vector, Basic) {
+  ScopedInRtl in_rtl;
+  Vector<int> v(MBlockScopedBuf);
+  EXPECT_EQ(v.Size(), (uptr)0);
+  v.PushBack(42);
+  EXPECT_EQ(v.Size(), (uptr)1);
+  EXPECT_EQ(v[0], 42);
+  v.PushBack(43);
+  EXPECT_EQ(v.Size(), (uptr)2);
+  EXPECT_EQ(v[0], 42);
+  EXPECT_EQ(v[1], 43);
+}
+
+TEST(Vector, Stride) {
+  ScopedInRtl in_rtl;
+  Vector<int> v(MBlockScopedBuf);
+  for (int i = 0; i < 1000; i++) {
+    v.PushBack(i);
+    EXPECT_EQ(v.Size(), (uptr)(i + 1));
+    EXPECT_EQ(v[i], i);
+  }
+  for (int i = 0; i < 1000; i++) {
+    EXPECT_EQ(v[i], i);
+  }
+}
+
+}  // namespace __tsan





More information about the llvm-commits mailing list