Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/compiler-rt/lib/tsan/dd/dd_rtl.cpp
35269 views
1
//===-- dd_rtl.cpp --------------------------------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "dd_rtl.h"
10
#include "sanitizer_common/sanitizer_common.h"
11
#include "sanitizer_common/sanitizer_placement_new.h"
12
#include "sanitizer_common/sanitizer_flags.h"
13
#include "sanitizer_common/sanitizer_flag_parser.h"
14
#include "sanitizer_common/sanitizer_stacktrace.h"
15
#include "sanitizer_common/sanitizer_stackdepot.h"
16
17
namespace __dsan {
18
19
static Context *ctx;
20
21
static u32 CurrentStackTrace(Thread *thr, uptr skip) {
22
BufferedStackTrace stack;
23
thr->ignore_interceptors = true;
24
stack.Unwind(1000, 0, 0, 0, 0, 0, false);
25
thr->ignore_interceptors = false;
26
if (stack.size <= skip)
27
return 0;
28
return StackDepotPut(StackTrace(stack.trace + skip, stack.size - skip));
29
}
30
31
static void PrintStackTrace(Thread *thr, u32 stk) {
32
StackTrace stack = StackDepotGet(stk);
33
thr->ignore_interceptors = true;
34
stack.Print();
35
thr->ignore_interceptors = false;
36
}
37
38
static void ReportDeadlock(Thread *thr, DDReport *rep) {
39
if (rep == 0)
40
return;
41
Lock lock(&ctx->report_mutex);
42
Printf("==============================\n");
43
Printf("WARNING: lock-order-inversion (potential deadlock)\n");
44
for (int i = 0; i < rep->n; i++) {
45
Printf("Thread %lld locks mutex %llu while holding mutex %llu:\n",
46
rep->loop[i].thr_ctx, rep->loop[i].mtx_ctx1, rep->loop[i].mtx_ctx0);
47
PrintStackTrace(thr, rep->loop[i].stk[1]);
48
if (rep->loop[i].stk[0]) {
49
Printf("Mutex %llu was acquired here:\n",
50
rep->loop[i].mtx_ctx0);
51
PrintStackTrace(thr, rep->loop[i].stk[0]);
52
}
53
}
54
Printf("==============================\n");
55
}
56
57
Callback::Callback(Thread *thr)
58
: thr(thr) {
59
lt = thr->dd_lt;
60
pt = thr->dd_pt;
61
}
62
63
u32 Callback::Unwind() {
64
return CurrentStackTrace(thr, 3);
65
}
66
67
static void InitializeFlags() {
68
Flags *f = flags();
69
70
// Default values.
71
f->second_deadlock_stack = false;
72
73
SetCommonFlagsDefaults();
74
{
75
// Override some common flags defaults.
76
CommonFlags cf;
77
cf.CopyFrom(*common_flags());
78
cf.allow_addr2line = true;
79
OverrideCommonFlags(cf);
80
}
81
82
// Override from command line.
83
FlagParser parser;
84
RegisterFlag(&parser, "second_deadlock_stack", "", &f->second_deadlock_stack);
85
RegisterCommonFlags(&parser);
86
parser.ParseStringFromEnv("DSAN_OPTIONS");
87
SetVerbosity(common_flags()->verbosity);
88
}
89
90
void Initialize() {
91
static u64 ctx_mem[sizeof(Context) / sizeof(u64) + 1];
92
ctx = new(ctx_mem) Context();
93
94
InitializeInterceptors();
95
InitializeFlags();
96
ctx->dd = DDetector::Create(flags());
97
}
98
99
void ThreadInit(Thread *thr) {
100
static atomic_uintptr_t id_gen;
101
uptr id = atomic_fetch_add(&id_gen, 1, memory_order_relaxed);
102
thr->dd_pt = ctx->dd->CreatePhysicalThread();
103
thr->dd_lt = ctx->dd->CreateLogicalThread(id);
104
}
105
106
void ThreadDestroy(Thread *thr) {
107
ctx->dd->DestroyPhysicalThread(thr->dd_pt);
108
ctx->dd->DestroyLogicalThread(thr->dd_lt);
109
}
110
111
void MutexBeforeLock(Thread *thr, uptr m, bool writelock) {
112
if (thr->ignore_interceptors)
113
return;
114
Callback cb(thr);
115
{
116
MutexHashMap::Handle h(&ctx->mutex_map, m);
117
if (h.created())
118
ctx->dd->MutexInit(&cb, &h->dd);
119
ctx->dd->MutexBeforeLock(&cb, &h->dd, writelock);
120
}
121
ReportDeadlock(thr, ctx->dd->GetReport(&cb));
122
}
123
124
void MutexAfterLock(Thread *thr, uptr m, bool writelock, bool trylock) {
125
if (thr->ignore_interceptors)
126
return;
127
Callback cb(thr);
128
{
129
MutexHashMap::Handle h(&ctx->mutex_map, m);
130
if (h.created())
131
ctx->dd->MutexInit(&cb, &h->dd);
132
ctx->dd->MutexAfterLock(&cb, &h->dd, writelock, trylock);
133
}
134
ReportDeadlock(thr, ctx->dd->GetReport(&cb));
135
}
136
137
void MutexBeforeUnlock(Thread *thr, uptr m, bool writelock) {
138
if (thr->ignore_interceptors)
139
return;
140
Callback cb(thr);
141
{
142
MutexHashMap::Handle h(&ctx->mutex_map, m);
143
ctx->dd->MutexBeforeUnlock(&cb, &h->dd, writelock);
144
}
145
ReportDeadlock(thr, ctx->dd->GetReport(&cb));
146
}
147
148
void MutexDestroy(Thread *thr, uptr m) {
149
if (thr->ignore_interceptors)
150
return;
151
Callback cb(thr);
152
MutexHashMap::Handle h(&ctx->mutex_map, m, true);
153
if (!h.exists())
154
return;
155
ctx->dd->MutexDestroy(&cb, &h->dd);
156
}
157
158
} // namespace __dsan
159
160