aboutsummaryrefslogtreecommitdiff
path: root/contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc')
-rw-r--r--contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc151
1 files changed, 151 insertions, 0 deletions
diff --git a/contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc b/contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc
new file mode 100644
index 000000000000..41b75bf755b8
--- /dev/null
+++ b/contrib/compiler-rt/lib/tsan/dd/dd_rtl.cc
@@ -0,0 +1,151 @@
+//===-- dd_rtl.cc ---------------------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "dd_rtl.h"
+#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_flags.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
+namespace __dsan {
+
+static Context *ctx;
+
+static u32 CurrentStackTrace(Thread *thr, uptr skip) {
+ BufferedStackTrace stack;
+ thr->ignore_interceptors = true;
+ stack.Unwind(1000, 0, 0, 0, 0, 0, false);
+ thr->ignore_interceptors = false;
+ if (stack.size <= skip)
+ return 0;
+ return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip));
+}
+
+static void PrintStackTrace(Thread *thr, u32 stk) {
+ StackTrace stack = StackDepotGet(stk);
+ thr->ignore_interceptors = true;
+ stack.Print();
+ thr->ignore_interceptors = false;
+}
+
+static void ReportDeadlock(Thread *thr, DDReport *rep) {
+ if (rep == 0)
+ return;
+ BlockingMutexLock lock(&ctx->report_mutex);
+ Printf("==============================\n");
+ Printf("WARNING: lock-order-inversion (potential deadlock)\n");
+ for (int i = 0; i < rep->n; i++) {
+ Printf("Thread %d locks mutex %llu while holding mutex %llu:\n",
+ rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
+ PrintStackTrace(thr, rep->loop[i].stk[1]);
+ if (rep->loop[i].stk[0]) {
+ Printf("Mutex %llu was acquired here:\n",
+ rep->loop[i].mtx_ctx0);
+ PrintStackTrace(thr, rep->loop[i].stk[0]);
+ }
+ }
+ Printf("==============================\n");
+}
+
+Callback::Callback(Thread *thr)
+ : thr(thr) {
+ lt = thr->dd_lt;
+ pt = thr->dd_pt;
+}
+
+u32 Callback::Unwind() {
+ return CurrentStackTrace(thr, 3);
+}
+
+void InitializeFlags(Flags *f, const char *env) {
+ internal_memset(f, 0, sizeof(*f));
+
+ // Default values.
+ f->second_deadlock_stack = false;
+
+ CommonFlags *cf = common_flags();
+ SetCommonFlagsDefaults(cf);
+ // Override some common flags defaults.
+ cf->allow_addr2line = true;
+
+ // Override from command line.
+ ParseFlag(env, &f->second_deadlock_stack, "second_deadlock_stack", "");
+ ParseCommonFlagsFromString(cf, env);
+}
+
+void Initialize() {
+ static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
+ ctx = new(ctx_mem) Context();
+
+ InitializeInterceptors();
+ InitializeFlags(flags(), GetEnv("DSAN_OPTIONS"));
+ ctx->dd = DDetector::Create(flags());
+}
+
+void ThreadInit(Thread *thr) {
+ static atomic_uintptr_t id_gen;
+ uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
+ thr->dd_pt = ctx->dd->CreatePhysicalThread();
+ thr->dd_lt = ctx->dd->CreateLogicalThread(id);
+}
+
+void ThreadDestroy(Thread *thr) {
+ ctx->dd->DestroyPhysicalThread(thr->dd_pt);
+ ctx->dd->DestroyLogicalThread(thr->dd_lt);
+}
+
+void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
+ if (thr->ignore_interceptors)
+ return;
+ Callback cb(thr);
+ {
+ MutexHashMap::Handle h(&ctx->mutex_map, m);
+ if (h.created())
+ ctx->dd->MutexInit(&cb, &h->dd);
+ ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
+ }
+ ReportDeadlock(thr, ctx->dd->GetReport(&cb));
+}
+
+void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
+ if (thr->ignore_interceptors)
+ return;
+ Callback cb(thr);
+ {
+ MutexHashMap::Handle h(&ctx->mutex_map, m);
+ if (h.created())
+ ctx->dd->MutexInit(&cb, &h->dd);
+ ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
+ }
+ ReportDeadlock(thr, ctx->dd->GetReport(&cb));
+}
+
+void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
+ if (thr->ignore_interceptors)
+ return;
+ Callback cb(thr);
+ {
+ MutexHashMap::Handle h(&ctx->mutex_map, m);
+ ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
+ }
+ ReportDeadlock(thr, ctx->dd->GetReport(&cb));
+}
+
+void MutexDestroy(Thread *thr, uptr m) {
+ if (thr->ignore_interceptors)
+ return;
+ Callback cb(thr);
+ MutexHashMap::Handle h(&ctx->mutex_map, m, true);
+ if (!h.exists())
+ return;
+ ctx->dd->MutexDestroy(&cb, &h->dd);
+}
+
+} // namespace __dsan