| Dmitry Vyukov | 3ab6b23 | 2015-01-21 13:50:02 +0000 | [diff] [blame] | 1 | #include <pthread.h> |
| 2 | #include <stdlib.h> |
| 3 | #include <stdio.h> |
| 4 | #include <unistd.h> |
| 5 | #include <dlfcn.h> |
| 6 | #include <stddef.h> |
| 7 | |
| 8 | // TSan-invisible barrier. |
| 9 | // Tests use it to establish necessary execution order in a way that does not |
| 10 | // interfere with tsan (does not establish synchronization between threads). |
| Dmitry Vyukov | 4cd631c | 2015-11-06 11:52:24 +0000 | [diff] [blame^] | 11 | // 8 lsb is thread count, the remaining are count of entered threads. |
| 12 | typedef unsigned long long invisible_barrier_t; |
| Dmitry Vyukov | 3ab6b23 | 2015-01-21 13:50:02 +0000 | [diff] [blame] | 13 | |
| Dmitry Vyukov | 4cd631c | 2015-11-06 11:52:24 +0000 | [diff] [blame^] | 14 | void barrier_init(invisible_barrier_t *barrier, unsigned count) { |
| 15 | if (count >= (1 << 8)) |
| 16 | exit(fprintf(stderr, "barrier_init: count is too large (%d)\n", count)); |
| 17 | *barrier = count; |
| 18 | } |
| Viktor Kutuzov | 281347a | 2015-03-13 14:08:55 +0000 | [diff] [blame] | 19 | |
| Dmitry Vyukov | 4cd631c | 2015-11-06 11:52:24 +0000 | [diff] [blame^] | 20 | void barrier_wait(invisible_barrier_t *barrier) { |
| 21 | unsigned old = __atomic_fetch_add(barrier, 1 << 8, __ATOMIC_RELAXED); |
| 22 | unsigned old_epoch = (old >> 8) / (old & 0xff); |
| 23 | for (;;) { |
| 24 | unsigned cur = __atomic_load_n(barrier, __ATOMIC_RELAXED); |
| 25 | unsigned cur_epoch = (cur >> 8) / (cur & 0xff); |
| 26 | if (cur_epoch != old_epoch) |
| 27 | return; |
| 28 | usleep(1000); |
| Dmitry Vyukov | 3ab6b23 | 2015-01-21 13:50:02 +0000 | [diff] [blame] | 29 | } |
| Dmitry Vyukov | 3ab6b23 | 2015-01-21 13:50:02 +0000 | [diff] [blame] | 30 | } |
| 31 | |
| 32 | // Default instance of the barrier, but a test can declare more manually. |
| Dmitry Vyukov | 4cd631c | 2015-11-06 11:52:24 +0000 | [diff] [blame^] | 33 | invisible_barrier_t barrier; |
| Dmitry Vyukov | 3ab6b23 | 2015-01-21 13:50:02 +0000 | [diff] [blame] | 34 | |
| Mohit K. Bhakkad | 846de99 | 2015-02-20 09:32:45 +0000 | [diff] [blame] | 35 | void print_address(void *address) { |
| 36 | // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not match |
| 37 | // to the format used in the diagnotic message. |
| 38 | #ifdef __x86_64__ |
| 39 | fprintf(stderr, "0x%012lx", (unsigned long) address); |
| Adhemerval Zanella | 15db6dc | 2015-08-28 20:40:50 +0000 | [diff] [blame] | 40 | #elif defined(__mips64) |
| Mohit K. Bhakkad | 846de99 | 2015-02-20 09:32:45 +0000 | [diff] [blame] | 41 | fprintf(stderr, "0x%010lx", (unsigned long) address); |
| Adhemerval Zanella | 15db6dc | 2015-08-28 20:40:50 +0000 | [diff] [blame] | 42 | #elif defined(__aarch64__) |
| 43 | // AArch64 currently has 3 different VMA (39, 42, and 48 bits) and it requires |
| 44 | // different pointer size to match the diagnostic message. |
| 45 | const char *format = 0; |
| 46 | unsigned long vma = (unsigned long)__builtin_frame_address(0); |
| 47 | vma = 64 - __builtin_clzll(vma); |
| 48 | if (vma == 39) |
| 49 | format = "0x%010lx"; |
| 50 | else if (vma == 42) |
| 51 | format = "0x%011lx"; |
| 52 | else { |
| 53 | fprintf(stderr, "unsupported vma: %ul\n", vma); |
| 54 | exit(1); |
| 55 | } |
| 56 | |
| 57 | fprintf(stderr, format, (unsigned long) address); |
| Mohit K. Bhakkad | 846de99 | 2015-02-20 09:32:45 +0000 | [diff] [blame] | 58 | #endif |
| 59 | } |