summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2015-06-30 17:23:29 +0000
committerDmitry Vyukov <dvyukov@google.com>2015-06-30 17:23:29 +0000
commit3c960d3fe7494f7889eb1e304705218a51a4d40e (patch)
treeafc059f2c1608d76b5b078ed2c3d55e21d372cd9
parentddbca29d883ef1ccdaa4acb7803d69cc2dba0e01 (diff)
downloadcompiler-rt-3c960d3fe7494f7889eb1e304705218a51a4d40e.tar.gz
tsan: fix handling of condition variable destruction
POSIX states that "It shall be safe to destroy an initialized condition variable upon which no threads are currently blocked", and later clarifies "A condition variable can be destroyed immediately after all the threads that are blocked on it are awakened) (in examples section). Tsan reported such destruction as a data race. Fixes https://llvm.org/bugs/show_bug.cgi?id=23616 Reviewed in http://reviews.llvm.org/D10693 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@241082 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/tsan/rtl/tsan_interceptors.cc4
-rw-r--r--test/tsan/cond_destruction.cc53
2 files changed, 55 insertions, 2 deletions
diff --git a/lib/tsan/rtl/tsan_interceptors.cc b/lib/tsan/rtl/tsan_interceptors.cc
index d3bef355d..7b5c50e2a 100644
--- a/lib/tsan/rtl/tsan_interceptors.cc
+++ b/lib/tsan/rtl/tsan_interceptors.cc
@@ -992,8 +992,8 @@ INTERCEPTOR(int, pthread_cond_init, void *c, void *a) {
INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
void *cond = init_cond(c);
SCOPED_TSAN_INTERCEPTOR(pthread_cond_wait, cond, m);
- MutexUnlock(thr, pc, (uptr)m);
MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+ MutexUnlock(thr, pc, (uptr)m);
CondMutexUnlockCtx arg = {&si, thr, pc, m};
int res = 0;
// This ensures that we handle mutex lock even in case of pthread_cancel.
@@ -1014,8 +1014,8 @@ INTERCEPTOR(int, pthread_cond_wait, void *c, void *m) {
INTERCEPTOR(int, pthread_cond_timedwait, void *c, void *m, void *abstime) {
void *cond = init_cond(c);
SCOPED_TSAN_INTERCEPTOR(pthread_cond_timedwait, cond, m, abstime);
- MutexUnlock(thr, pc, (uptr)m);
MemoryAccessRange(thr, pc, (uptr)c, sizeof(uptr), false);
+ MutexUnlock(thr, pc, (uptr)m);
CondMutexUnlockCtx arg = {&si, thr, pc, m};
int res = 0;
// This ensures that we handle mutex lock even in case of pthread_cancel.
diff --git a/test/tsan/cond_destruction.cc b/test/tsan/cond_destruction.cc
new file mode 100644
index 000000000..f56b30c4f
--- /dev/null
+++ b/test/tsan/cond_destruction.cc
@@ -0,0 +1,53 @@
+// RUN: %clangxx_tsan -O1 %s -o %t
+// RUN: %run %t 2>&1 | FileCheck %s
+// RUN: %run %t arg 2>&1 | FileCheck %s
+// RUN: %run %t arg arg 2>&1 | FileCheck %s
+#include "test.h"
+
+// Test for destruction of pthread_cond_t.
+// POSIX states that it is safe to destroy a condition variable upon which no
+// threads are currently blocked. That is, it is not necessary to wait untill
+// other threads return from pthread_cond_wait, they just need to be unblocked.
+
+pthread_mutex_t m;
+pthread_cond_t c;
+bool done1, done2;
+
+void *thr(void *p) {
+ pthread_mutex_lock(&m);
+ done1 = true;
+ pthread_cond_signal(&c);
+ while (!done2)
+ pthread_cond_wait(&c, &m);
+ pthread_mutex_unlock(&m);
+ return 0;
+}
+
+int main(int argc, char **argv) {
+ pthread_t th;
+ pthread_mutex_init(&m, 0);
+ pthread_cond_init(&c, 0);
+ pthread_create(&th, 0, thr, 0);
+ pthread_mutex_lock(&m);
+ while (!done1)
+ pthread_cond_wait(&c, &m);
+ done2 = true;
+ // Any of these sequences is legal.
+ if (argc == 1) {
+ pthread_cond_signal(&c);
+ pthread_mutex_unlock(&m);
+ pthread_cond_destroy(&c);
+ } else if (argc == 2) {
+ pthread_mutex_unlock(&m);
+ pthread_cond_signal(&c);
+ pthread_cond_destroy(&c);
+ } else {
+ pthread_cond_signal(&c);
+ pthread_cond_destroy(&c);
+ pthread_mutex_unlock(&m);
+ }
+ pthread_join(th, 0);
+ fprintf(stderr, "DONE\n");
+}
+
+// CHECK-NOT: ThreadSanitizer: data race