1 // RUN: %clangxx_tsan -O1 %s %link_libcxx_tsan -o %t && %run %t 2>&1 | FileCheck %s
13 const int kThreads
= 4;
14 const int kMutexes
= 16 << 10;
15 const int kIters
= 400 << 10;
16 const int kMaxPerThread
= 10;
18 const int kStateInited
= 0;
19 const int kStateNotInited
= -1;
20 const int kStateLocked
= -2;
31 printf("SOMETHING HAS FAILED\n");
36 bool cas(int *a
, int oldval
, int newval
) {
37 return __atomic_compare_exchange_n(a
, &oldval
, newval
, false,
38 __ATOMIC_ACQ_REL
, __ATOMIC_RELAXED
);
41 void *Thread(void *seed
) {
42 unsigned rnd
= (unsigned)(unsigned long)seed
;
44 std::vector
<int> locked
;
45 for (int i
= 0; i
< kIters
; i
++) {
46 int what
= rand_r(&rnd
) % 10;
47 if (what
< 4 && locked
.size() < kMaxPerThread
) {
50 if (!locked
.empty()) {
51 max_locked
= *std::max_element(locked
.begin(), locked
.end());
52 if (max_locked
== kMutexes
- 1) {
57 int id
= (rand_r(&rnd
) % (kMutexes
- max_locked
- 1)) + max_locked
+ 1;
59 // init the mutex if necessary or acquire a reference
61 int old
= __atomic_load_n(&m
->state
, __ATOMIC_RELAXED
);
62 if (old
== kStateLocked
) {
67 if (old
== kStateNotInited
)
69 if (cas(&m
->state
, old
, newv
)) {
70 if (old
== kStateNotInited
) {
71 if ((err
= pthread_rwlock_init(&m
->m
, 0))) {
72 fprintf(stderr
, "pthread_rwlock_init failed with %d\n", err
);
75 if (!cas(&m
->state
, kStateLocked
, 1)) {
76 fprintf(stderr
, "init commit failed\n");
83 // now we have an inited and referenced mutex, choose what to do
85 switch (rand_r(&rnd
) % 4) {
87 if ((err
= pthread_rwlock_wrlock(&m
->m
))) {
88 fprintf(stderr
, "pthread_rwlock_wrlock failed with %d\n", err
);
93 if ((err
= pthread_rwlock_rdlock(&m
->m
))) {
94 fprintf(stderr
, "pthread_rwlock_rdlock failed with %d\n", err
);
99 err
= pthread_rwlock_trywrlock(&m
->m
);
100 if (err
!= 0 && err
!= EBUSY
) {
101 fprintf(stderr
, "pthread_rwlock_trywrlock failed with %d\n", err
);
104 failed
= err
== EBUSY
;
107 err
= pthread_rwlock_tryrdlock(&m
->m
);
108 if (err
!= 0 && err
!= EBUSY
) {
109 fprintf(stderr
, "pthread_rwlock_tryrdlock failed with %d\n", err
);
112 failed
= err
== EBUSY
;
116 if (__atomic_fetch_sub(&m
->state
, 1, __ATOMIC_ACQ_REL
) <= 0) {
117 fprintf(stderr
, "failed to unref after failed trylock\n");
122 locked
.push_back(id
);
123 } else if (what
< 9 && !locked
.empty()) {
125 int pos
= rand_r(&rnd
) % locked
.size();
126 int id
= locked
[pos
];
127 locked
[pos
] = locked
[locked
.size() - 1];
130 if ((err
= pthread_rwlock_unlock(&m
->m
))) {
131 fprintf(stderr
, "pthread_rwlock_unlock failed with %d\n", err
);
134 if (__atomic_fetch_sub(&m
->state
, 1, __ATOMIC_ACQ_REL
) <= 0) {
135 fprintf(stderr
, "failed to unref after unlock\n");
139 // Destroy a random mutex.
140 int id
= rand_r(&rnd
) % kMutexes
;
142 if (!cas(&m
->state
, kStateInited
, kStateLocked
)) {
146 if ((err
= pthread_rwlock_destroy(&m
->m
))) {
147 fprintf(stderr
, "pthread_rwlock_destroy failed with %d\n", err
);
150 if (!cas(&m
->state
, kStateLocked
, kStateNotInited
)) {
151 fprintf(stderr
, "destroy commit failed\n");
156 // Unlock all previously locked mutexes, otherwise other threads can deadlock.
157 for (int i
= 0; i
< locked
.size(); i
++) {
160 if ((err
= pthread_rwlock_unlock(&m
->m
))) {
161 fprintf(stderr
, "pthread_rwlock_unlock failed with %d\n", err
);
170 gettimeofday(&tv
, NULL
);
171 unsigned s
= tv
.tv_sec
+ tv
.tv_usec
;
172 fprintf(stderr
, "seed %d\n", s
);
174 for (int i
= 0; i
< kMutexes
; i
++)
175 mtx
[i
].state
= kStateNotInited
;
176 pthread_t t
[kThreads
];
177 for (int i
= 0; i
< kThreads
; i
++)
178 pthread_create(&t
[i
], 0, Thread
, (void*)(unsigned long)rand());
179 for (int i
= 0; i
< kThreads
; i
++)
180 pthread_join(t
[i
], 0);
181 fprintf(stderr
, "DONE\n");
185 // CHECK-NOT: WARNING: ThreadSanitizer