aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/testsuite/ChangeLog19
-rw-r--r--gcc/testsuite/c-c++-common/tsan/atomic_stack.c32
-rw-r--r--gcc/testsuite/c-c++-common/tsan/fd_pipe_race.c37
-rw-r--r--gcc/testsuite/c-c++-common/tsan/free_race.c28
-rw-r--r--gcc/testsuite/c-c++-common/tsan/mutexset1.c41
-rw-r--r--gcc/testsuite/c-c++-common/tsan/race_on_barrier.c33
-rw-r--r--gcc/testsuite/c-c++-common/tsan/sleep_sync.c31
-rw-r--r--gcc/testsuite/c-c++-common/tsan/thread_leak.c18
-rw-r--r--gcc/testsuite/c-c++-common/tsan/thread_leak1.c19
-rw-r--r--gcc/testsuite/c-c++-common/tsan/thread_leak2.c23
-rw-r--r--gcc/testsuite/c-c++-common/tsan/tiny_race.c23
-rw-r--r--gcc/testsuite/c-c++-common/tsan/tls_race.c21
-rw-r--r--gcc/testsuite/c-c++-common/tsan/write_in_reader_lock.c37
-rw-r--r--gcc/testsuite/g++.dg/dg.exp1
-rw-r--r--gcc/testsuite/g++.dg/tsan/tsan.exp40
-rw-r--r--gcc/testsuite/gcc.dg/tsan/tsan.exp40
-rw-r--r--gcc/testsuite/lib/tsan-dg.exp114
17 files changed, 557 insertions, 0 deletions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 699ff7e..2ede528 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,22 @@
+2013-12-05 Max Ostapenko <m.ostapenko@partner.samsung.com>
+
+ * c-c++-common/tsan/atomic_stack.c: New test.
+ * c-c++-common/tsan/fd_pipe_race.c: New test.
+ * c-c++-common/tsan/free_race.c: New test.
+ * c-c++-common/tsan/mutexset1.c: New test.
+ * c-c++-common/tsan/race_on_barrier.c: New test.
+ * c-c++-common/tsan/sleep_sync.c: New test.
+ * c-c++-common/tsan/thread_leak.c: New test.
+ * c-c++-common/tsan/thread_leak1.c: New test.
+ * c-c++-common/tsan/thread_leak2.c: New test.
+ * c-c++-common/tsan/tiny_race.c: New test.
+ * c-c++-common/tsan/tls_race.c: New test.
+ * c-c++-common/tsan/write_in_reader_lock.c: New test.
+ * lib/tsan-dg.exp: New file.
+ * gcc.dg/tsan/tsan.exp: New file.
+ * g++.dg/tsan/tsan.exp: New file.
+ * g++.dg/dg.exp: Prune tsan subdirectory.
+
2013-12-05 Kirill Yukhin <kirill.yukhin@intel.com>
* gcc.target/i386/readeflags-1.c: New.
diff --git a/gcc/testsuite/c-c++-common/tsan/atomic_stack.c b/gcc/testsuite/c-c++-common/tsan/atomic_stack.c
new file mode 100644
index 0000000..eac71b8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/atomic_stack.c
@@ -0,0 +1,32 @@
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <unistd.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ sleep(1);
+ __atomic_fetch_add(&Global, 1, __ATOMIC_RELAXED);
+ 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);
+ return 0;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
+/* { dg-output " Atomic write of size 4.*" } */
+/* { dg-output " #0 __tsan_atomic32_fetch_add.*" } */
+/* { dg-output " #1 Thread1.*" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/fd_pipe_race.c b/gcc/testsuite/c-c++-common/tsan/fd_pipe_race.c
new file mode 100644
index 0000000..fc76cbf
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/fd_pipe_race.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int fds[2];
+
+void *Thread1(void *x) {
+ write(fds[1], "a", 1);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ sleep(1);
+ close(fds[0]);
+ close(fds[1]);
+ return NULL;
+}
+
+int main() {
+ pipe(fds);
+ 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);
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*\n" } */
+/* { dg-output " Write of size 8.*\n" } */
+/* { dg-output " #0 close.*\n" } */
+/* { dg-output " #1 Thread2.*\n" } */
+/* { dg-output " Previous read of size 8.*\n" } */
+/* { dg-output " #0 write.*\n" } */
+/* { dg-output " #1 Thread1.*\n" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/free_race.c b/gcc/testsuite/c-c++-common/tsan/free_race.c
new file mode 100644
index 0000000..362c92b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/free_race.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <stdlib.h>
+
+void __attribute__((noinline)) foo(int *mem) {
+ free(mem);
+}
+
+void __attribute__((noinline)) bar(int *mem) {
+ mem[0] = 42;
+}
+
+int main() {
+ int *mem =(int*)malloc (100);
+ foo(mem);
+ bar(mem);
+ return 0;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: heap-use-after-free.*(\n|\r\n|\r)" } */
+/* { dg-output " Write of size 4 at.* by main thread:(\n|\r\n|\r)" } */
+/* { dg-output " #0 bar.*(\n|\r\n|\r)" } */
+/* { dg-output " #1 main.*(\n|\r\n|\r)" } */
+/* { dg-output " Previous write of size 8 at.* by main thread:(\n|\r\n|\r)" } */
+/* { dg-output " #0 free.*(\n|\r\n|\r)" } */
+/* { dg-output " #\(1|2\) foo.*(\n|\r\n|\r)" } */
+/* { dg-output " #\(2|3\) main.*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/mutexset1.c b/gcc/testsuite/c-c++-common/tsan/mutexset1.c
new file mode 100644
index 0000000..783f262
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/mutexset1.c
@@ -0,0 +1,41 @@
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int Global;
+pthread_mutex_t mtx;
+
+void *Thread1(void *x) {
+ sleep(1);
+ pthread_mutex_lock(&mtx);
+ Global++;
+ pthread_mutex_unlock(&mtx);
+ return NULL;
+}
+
+void *Thread2(void *x) {
+ Global--;
+ return NULL;/* { dg-output ".*" } */
+
+}
+
+int main() {
+ pthread_mutex_init(&mtx, 0);
+ 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;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
+/* { dg-output " Read of size 4 at 0x\[0-9a-f\]+ by thread T1 \\(mutexes: write M\[0-9\]\\):.*" } */
+/* { dg-output " Previous write of size 4 at 0x\[0-9a-f\]+ by thread T2:.*" } */
+/* { dg-output " Mutex M\[0-9\] created at:.*" } */
+/* { dg-output " #0 pthread_mutex_init.*" } */
+/* { dg-output " #1 main (.*mutexset1.c|\\?{2}):\[0-9]+.*" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/race_on_barrier.c b/gcc/testsuite/c-c++-common/tsan/race_on_barrier.c
new file mode 100644
index 0000000..407c712
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/race_on_barrier.c
@@ -0,0 +1,33 @@
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#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) {
+ sleep(1);
+ 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;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/sleep_sync.c b/gcc/testsuite/c-c++-common/tsan/sleep_sync.c
new file mode 100644
index 0000000..8203d54
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/sleep_sync.c
@@ -0,0 +1,31 @@
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <unistd.h>
+
+int X = 0;
+
+void MySleep() {
+ sleep(1);
+}
+
+void *Thread(void *p) {
+ MySleep(); // Assume the main thread has done the write.
+ X = 42;
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ X = 43;
+ pthread_join(t, 0);
+ return 0;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r).*} */
+/* { dg-output " As if synchronized via sleep:(\n|\r\n|\r)} */
+/* { dg-output " #0 sleep.*"*} */
+/* { dg-output " #1 MySleep.*"*} */
+/* { dg-output " #2 Thread.*"*} */
diff --git a/gcc/testsuite/c-c++-common/tsan/thread_leak.c b/gcc/testsuite/c-c++-common/tsan/thread_leak.c
new file mode 100644
index 0000000..416ef77
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/thread_leak.c
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+
+#include <pthread.h>
+#include <stdio.h>
+
+void *Thread(void *x) {
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_join(t, 0);
+ printf("PASS\n");
+ return 0;
+}
+
+/* { dg-prune-output "WARNING: ThreadSanitizer: thread leak.*" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/thread_leak1.c b/gcc/testsuite/c-c++-common/tsan/thread_leak1.c
new file mode 100644
index 0000000..18bcf2a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/thread_leak1.c
@@ -0,0 +1,19 @@
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *x) {
+ return 0;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ sleep(1);
+ return 0;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: thread leak.*(\n|\r\n|\r)" } */
+/* { dg-output "SUMMARY: ThreadSanitizer: thread leak.*main.*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/thread_leak2.c b/gcc/testsuite/c-c++-common/tsan/thread_leak2.c
new file mode 100644
index 0000000..12ac734
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/thread_leak2.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+/* { dg-skip-if "" { *-*-* } { "-O3 -funroll-loops" "-O3 -funroll-all-loops" } { "" } } */
+
+#include <pthread.h>
+#include <unistd.h>
+
+void *Thread(void *x) {
+ return 0;
+}
+
+int main() {
+ int i;
+ for (i = 0; i < 5; i++) {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ }
+ sleep(1);
+ return 0;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: thread leak.*(\n|\r\n|\r)" } */
+/* { dg-output " And 4 more similar thread leaks.*" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/tiny_race.c b/gcc/testsuite/c-c++-common/tsan/tiny_race.c
new file mode 100644
index 0000000..0356183
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/tiny_race.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <unistd.h>
+
+int Global;
+
+void *Thread1(void *x) {
+ sleep(1);
+ Global = 42;
+ return x;
+}
+
+int main() {
+ pthread_t t;
+ pthread_create(&t, 0, Thread1, 0);
+ Global = 43;
+ pthread_join(t, 0);
+ return Global;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/tls_race.c b/gcc/testsuite/c-c++-common/tsan/tls_race.c
new file mode 100644
index 0000000..041e9af
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/tls_race.c
@@ -0,0 +1,21 @@
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <stddef.h>
+
+void *Thread(void *a) {
+ *(int*)a = 43;
+ return 0;
+}
+
+int main() {
+ static __thread int Var = 42;
+ pthread_t t;
+ pthread_create(&t, 0, Thread, &Var);
+ Var = 43;
+ pthread_join(t, 0);
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r).*" } */
+/* { dg-output " Location is TLS of main thread.(\n|\r\n|\r).*" } */
diff --git a/gcc/testsuite/c-c++-common/tsan/write_in_reader_lock.c b/gcc/testsuite/c-c++-common/tsan/write_in_reader_lock.c
new file mode 100644
index 0000000..c6a0bee
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/tsan/write_in_reader_lock.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+/* { dg-shouldfail "tsan" } */
+
+#include <pthread.h>
+#include <unistd.h>
+
+pthread_rwlock_t rwlock;
+int GLOB;
+
+void *Thread1(void *p) {
+ (void)p;
+ pthread_rwlock_rdlock(&rwlock);
+ // Write under reader lock.
+ sleep(1);
+ GLOB++;
+ pthread_rwlock_unlock(&rwlock);
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ pthread_rwlock_init(&rwlock, NULL);
+ pthread_rwlock_rdlock(&rwlock);
+ pthread_t t;
+ pthread_create(&t, 0, Thread1, 0);
+ volatile int x = GLOB;
+ (void)x;
+ pthread_rwlock_unlock(&rwlock);
+ pthread_join(t, 0);
+ pthread_rwlock_destroy(&rwlock);
+ return 0;
+}
+
+/* { dg-output "WARNING: ThreadSanitizer: data race.*(\n|\r\n|\r)" } */
+/* { dg-output " Write of size 4 at 0x\[0-9a-f\]+ by thread T1.*:(\n|\r\n|\r).*" } */
+/* { dg-output " #0 Thread1.*\(write_in_reader_lock.c|\\?{2}\):\[0-9\]+ .*" } */
+/* { dg-output " Previous read of size 4 at.* by main thread.*:(\n|\r\n|\r).*" } */
+/* { dg-output " #0 main.*\(write_in_reader_lock.c|\\?{2}\):\[0-9\]+.*" } */
diff --git a/gcc/testsuite/g++.dg/dg.exp b/gcc/testsuite/g++.dg/dg.exp
index d107dfe..c90a7e6 100644
--- a/gcc/testsuite/g++.dg/dg.exp
+++ b/gcc/testsuite/g++.dg/dg.exp
@@ -54,6 +54,7 @@ set tests [prune $tests $srcdir/$subdir/guality/*]
set tests [prune $tests $srcdir/$subdir/simulate-thread/*]
set tests [prune $tests $srcdir/$subdir/asan/*]
set tests [prune $tests $srcdir/$subdir/ubsan/*]
+set tests [prune $tests $srcdir/$subdir/tsan/*]
# Main loop.
g++-dg-runtest $tests $DEFAULT_CXXFLAGS
diff --git a/gcc/testsuite/g++.dg/tsan/tsan.exp b/gcc/testsuite/g++.dg/tsan/tsan.exp
new file mode 100644
index 0000000..164a92e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tsan/tsan.exp
@@ -0,0 +1,40 @@
+# Copyright (C) 2013 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib g++-dg.exp
+load_lib tsan-dg.exp
+
+if ![check_effective_target_fthread_sanitizer] {
+ return
+}
+
+# Initialize `dg'.
+dg-init
+if [tsan_init] {
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/tsan/*.c]] ""
+
+}
+
+# All done.
+tsan_finish
+dg-finish
diff --git a/gcc/testsuite/gcc.dg/tsan/tsan.exp b/gcc/testsuite/gcc.dg/tsan/tsan.exp
new file mode 100644
index 0000000..248cfb1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tsan/tsan.exp
@@ -0,0 +1,40 @@
+# Copyright (C) 2013 Free Software Foundation, Inc.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# GCC testsuite that uses the `dg.exp' driver.
+
+# Load support procs.
+load_lib gcc-dg.exp
+load_lib tsan-dg.exp
+
+if ![check_effective_target_fthread_sanitizer] {
+ return
+}
+
+# Initialize `dg'.
+dg-init
+if [tsan_init] {
+
+# Main loop.
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c $srcdir/c-c++-common/tsan/*.c]] ""
+
+}
+
+# All done.
+tsan_finish
+dg-finish
diff --git a/gcc/testsuite/lib/tsan-dg.exp b/gcc/testsuite/lib/tsan-dg.exp
new file mode 100644
index 0000000..f39d8b5
--- /dev/null
+++ b/gcc/testsuite/lib/tsan-dg.exp
@@ -0,0 +1,114 @@
+# Copyright (C) 2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Return 1 if compilation with -fsanitize=thread is error-free for trivial
+# code, 0 otherwise.
+
+proc check_effective_target_fthread_sanitizer {} {
+ return [check_no_compiler_messages faddress_sanitizer object {
+ void foo (void) { }
+ } "-fPIE -pie -fsanitize=thread"]
+}
+
+#
+# tsan_link_flags -- compute library path and flags to find libtsan.
+# (originally from g++.exp)
+#
+
+proc tsan_link_flags { paths } {
+ global srcdir
+ global ld_library_path
+ global shlib_ext
+
+ set gccpath ${paths}
+ set flags ""
+
+ set shlib_ext [get_shlib_extension]
+
+ if { $gccpath != "" } {
+ if { [file exists "${gccpath}/libsanitizer/tsan/.libs/libtsan.a"]
+ || [file exists "${gccpath}/libsanitizer/tsan/.libs/libtsan.${shlib_ext}"] } {
+ append flags " -B${gccpath}/libsanitizer/tsan/ "
+ append flags " -L${gccpath}/libsanitizer/tsan/.libs "
+ append ld_library_path ":${gccpath}/libsanitizer/tsan/.libs"
+ }
+ } else {
+ global tool_root_dir
+
+ set libtsan [lookfor_file ${tool_root_dir} libtsan]
+ if { $libtsan != "" } {
+ append flags "-L${libtsan} "
+ append ld_library_path ":${libtsan}"
+ }
+ }
+
+ set_ld_library_path_env_vars
+
+ return "$flags"
+}
+
+#
+# tsan_init -- called at the start of each subdir of tests
+#
+
+proc tsan_init { args } {
+ global TEST_ALWAYS_FLAGS
+ global ALWAYS_CXXFLAGS
+ global TOOL_OPTIONS
+ global tsan_saved_TEST_ALWAYS_FLAGS
+
+ set link_flags ""
+ if ![is_remote host] {
+ if [info exists TOOL_OPTIONS] {
+ set link_flags "[tsan_link_flags [get_multilibs ${TOOL_OPTIONS}]]"
+ } else {
+ set link_flags "[tsan_link_flags [get_multilibs]]"
+ }
+ }
+
+ if [info exists TEST_ALWAYS_FLAGS] {
+ set tsan_saved_TEST_ALWAYS_FLAGS $TEST_ALWAYS_FLAGS
+ }
+ if [info exists ALWAYS_CXXFLAGS] {
+ set ALWAYS_CXXFLAGS [concat "{ldflags=$link_flags}" $ALWAYS_CXXFLAGS]
+ set ALWAYS_CXXFLAGS [concat "{additional_flags=-fPIE -pie -fsanitize=thread -g}" $ALWAYS_CXXFLAGS]
+ } else {
+ if [info exists TEST_ALWAYS_FLAGS] {
+ set TEST_ALWAYS_FLAGS "$link_flags -fPIE -pie -fsanitize=thread -g $TEST_ALWAYS_FLAGS"
+ } else {
+ set TEST_ALWAYS_FLAGS "$link_flags -fPIE -pie -fsanitize=thread -g"
+ }
+ }
+ if { $link_flags != "" } {
+ return 1
+ }
+ return 0
+}
+
+#
+# tsan_finish -- called at the start of each subdir of tests
+#
+
+proc tsan_finish { args } {
+ global TEST_ALWAYS_FLAGS
+ global tsan_saved_TEST_ALWAYS_FLAGS
+
+ if [info exists tsan_saved_TEST_ALWAYS_FLAGS] {
+ set TEST_ALWAYS_FLAGS $tsan_saved_TEST_ALWAYS_FLAGS
+ } else {
+ unset TEST_ALWAYS_FLAGS
+ }
+}