| // This run stresses global reset happenning concurrently with everything else. |
| // RUN: %clangxx_tsan -O1 %s -o %t && %env_tsan_opts=flush_memory_ms=1:flush_symbolizer_ms=1:memory_limit_mb=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NORACE |
| // This run stresses race reporting happenning concurrently with everything else. |
| // RUN: %clangxx_tsan -O1 %s -DRACE=1 -o %t && %env_tsan_opts=suppress_equal_stacks=0 %deflake %run %t | FileCheck %s --check-prefix=CHECK-RACE |
| #include "test.h" |
| #include <fcntl.h> |
| #include <string.h> |
| |
| volatile long stop; |
| long atomic, read_only, racy; |
| int fds[2]; |
| |
| __attribute__((noinline)) void *SecondaryThread(void *x) { |
| __atomic_fetch_add(&atomic, 1, __ATOMIC_ACQ_REL); |
| return NULL; |
| } |
| |
| void *Thread(void *x) { |
| const int me = (long)x; |
| volatile long sink = 0; |
| int fd = -1; |
| while (!stop) { |
| // If me == 0, we do all of the following, |
| // otherwise only 1 type of action. |
| if (me == 0 || me == 1) { |
| // just read the stop variable |
| } |
| if (me == 0 || me == 2) { |
| __atomic_store_n(&atomic, sink, __ATOMIC_RELEASE); |
| } |
| if (me == 0 || me == 3) { |
| sink += __atomic_fetch_add(&atomic, 1, __ATOMIC_ACQ_REL); |
| } |
| if (me == 0 || me == 4) { |
| SecondaryThread(NULL); |
| } |
| if (me == 0 || me == 5) { |
| write(fds[1], fds, 1); |
| } |
| if (me == 0 || me == 6) { |
| char buf[2]; |
| read(fds[0], &buf, sizeof(buf)); |
| } |
| if (me == 0 || me == 7) { |
| pthread_t th; |
| pthread_create(&th, NULL, SecondaryThread, NULL); |
| pthread_join(th, NULL); |
| } |
| if (me == 0 || me == 8) { |
| long buf; |
| memcpy(&buf, &read_only, sizeof(buf)); |
| sink += buf; |
| } |
| if (me == 0 || me == 9) { |
| #if RACE |
| sink += racy++; |
| #else |
| sink += racy; |
| #endif |
| } |
| if (me == 0 || me == 10) { |
| fd = open("/dev/null", O_RDONLY); |
| if (fd != -1) { |
| close(fd); |
| fd = -1; |
| } |
| } |
| // If you add more actions, update kActions in main. |
| } |
| return NULL; |
| } |
| |
| int main() { |
| ANNOTATE_BENIGN_RACE(stop); |
| if (pipe(fds)) |
| exit((perror("pipe"), 1)); |
| if (fcntl(fds[0], F_SETFL, O_NONBLOCK)) |
| exit((perror("fcntl"), 1)); |
| if (fcntl(fds[1], F_SETFL, O_NONBLOCK)) |
| exit((perror("fcntl"), 1)); |
| const int kActions = 11; |
| #if RACE |
| const int kMultiplier = 1; |
| #else |
| const int kMultiplier = 4; |
| #endif |
| pthread_t t[kActions * kMultiplier]; |
| for (int i = 0; i < kActions * kMultiplier; i++) |
| pthread_create(&t[i], NULL, Thread, (void *)(long)(i % kActions)); |
| sleep(5); |
| stop = 1; |
| for (int i = 0; i < kActions * kMultiplier; i++) |
| pthread_join(t[i], NULL); |
| fprintf(stderr, "DONE\n"); |
| return 0; |
| } |
| |
| // CHECK-NORACE-NOT: ThreadSanitizer: |
| // CHECK-NORACE: DONE |
| // CHECK-NORACE-NOT: ThreadSanitizer: |
| // CHECK-RACE: ThreadSanitizer: data race |
| // CHECK-RACE: DONE |