145
|
1 //===-- tsan_interface_ann.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 // This file is a part of ThreadSanitizer (TSan), a race detector.
|
|
10 //
|
|
11 //===----------------------------------------------------------------------===//
|
|
12 #include "sanitizer_common/sanitizer_libc.h"
|
|
13 #include "sanitizer_common/sanitizer_internal_defs.h"
|
|
14 #include "sanitizer_common/sanitizer_placement_new.h"
|
|
15 #include "sanitizer_common/sanitizer_stacktrace.h"
|
|
16 #include "sanitizer_common/sanitizer_vector.h"
|
|
17 #include "tsan_interface_ann.h"
|
|
18 #include "tsan_mutex.h"
|
|
19 #include "tsan_report.h"
|
|
20 #include "tsan_rtl.h"
|
|
21 #include "tsan_mman.h"
|
|
22 #include "tsan_flags.h"
|
|
23 #include "tsan_platform.h"
|
|
24
|
|
25 #define CALLERPC ((uptr)__builtin_return_address(0))
|
|
26
|
|
27 using namespace __tsan;
|
|
28
|
|
29 namespace __tsan {
|
|
30
|
|
31 class ScopedAnnotation {
|
|
32 public:
|
|
33 ScopedAnnotation(ThreadState *thr, const char *aname, uptr pc)
|
|
34 : thr_(thr) {
|
|
35 FuncEntry(thr_, pc);
|
|
36 DPrintf("#%d: annotation %s()\n", thr_->tid, aname);
|
|
37 }
|
|
38
|
|
39 ~ScopedAnnotation() {
|
|
40 FuncExit(thr_);
|
|
41 CheckNoLocks(thr_);
|
|
42 }
|
|
43 private:
|
|
44 ThreadState *const thr_;
|
|
45 };
|
|
46
|
|
47 #define SCOPED_ANNOTATION_RET(typ, ret) \
|
|
48 if (!flags()->enable_annotations) \
|
|
49 return ret; \
|
|
50 ThreadState *thr = cur_thread(); \
|
|
51 const uptr caller_pc = (uptr)__builtin_return_address(0); \
|
|
52 StatInc(thr, StatAnnotation); \
|
|
53 StatInc(thr, Stat##typ); \
|
|
54 ScopedAnnotation sa(thr, __func__, caller_pc); \
|
|
55 const uptr pc = StackTrace::GetCurrentPc(); \
|
|
56 (void)pc; \
|
|
57 /**/
|
|
58
|
|
59 #define SCOPED_ANNOTATION(typ) SCOPED_ANNOTATION_RET(typ, )
|
|
60
|
|
61 static const int kMaxDescLen = 128;
|
|
62
|
|
63 struct ExpectRace {
|
|
64 ExpectRace *next;
|
|
65 ExpectRace *prev;
|
|
66 atomic_uintptr_t hitcount;
|
|
67 atomic_uintptr_t addcount;
|
|
68 uptr addr;
|
|
69 uptr size;
|
|
70 char *file;
|
|
71 int line;
|
|
72 char desc[kMaxDescLen];
|
|
73 };
|
|
74
|
|
75 struct DynamicAnnContext {
|
|
76 Mutex mtx;
|
|
77 ExpectRace expect;
|
|
78 ExpectRace benign;
|
|
79
|
|
80 DynamicAnnContext()
|
|
81 : mtx(MutexTypeAnnotations, StatMtxAnnotations) {
|
|
82 }
|
|
83 };
|
|
84
|
|
85 static DynamicAnnContext *dyn_ann_ctx;
|
|
86 static char dyn_ann_ctx_placeholder[sizeof(DynamicAnnContext)] ALIGNED(64);
|
|
87
|
|
88 static void AddExpectRace(ExpectRace *list,
|
|
89 char *f, int l, uptr addr, uptr size, char *desc) {
|
|
90 ExpectRace *race = list->next;
|
|
91 for (; race != list; race = race->next) {
|
|
92 if (race->addr == addr && race->size == size) {
|
|
93 atomic_store_relaxed(&race->addcount,
|
|
94 atomic_load_relaxed(&race->addcount) + 1);
|
|
95 return;
|
|
96 }
|
|
97 }
|
|
98 race = (ExpectRace*)internal_alloc(MBlockExpectRace, sizeof(ExpectRace));
|
|
99 race->addr = addr;
|
|
100 race->size = size;
|
|
101 race->file = f;
|
|
102 race->line = l;
|
|
103 race->desc[0] = 0;
|
|
104 atomic_store_relaxed(&race->hitcount, 0);
|
|
105 atomic_store_relaxed(&race->addcount, 1);
|
|
106 if (desc) {
|
|
107 int i = 0;
|
|
108 for (; i < kMaxDescLen - 1 && desc[i]; i++)
|
|
109 race->desc[i] = desc[i];
|
|
110 race->desc[i] = 0;
|
|
111 }
|
|
112 race->prev = list;
|
|
113 race->next = list->next;
|
|
114 race->next->prev = race;
|
|
115 list->next = race;
|
|
116 }
|
|
117
|
|
118 static ExpectRace *FindRace(ExpectRace *list, uptr addr, uptr size) {
|
|
119 for (ExpectRace *race = list->next; race != list; race = race->next) {
|
|
120 uptr maxbegin = max(race->addr, addr);
|
|
121 uptr minend = min(race->addr + race->size, addr + size);
|
|
122 if (maxbegin < minend)
|
|
123 return race;
|
|
124 }
|
|
125 return 0;
|
|
126 }
|
|
127
|
|
128 static bool CheckContains(ExpectRace *list, uptr addr, uptr size) {
|
|
129 ExpectRace *race = FindRace(list, addr, size);
|
|
130 if (race == 0)
|
|
131 return false;
|
|
132 DPrintf("Hit expected/benign race: %s addr=%zx:%d %s:%d\n",
|
|
133 race->desc, race->addr, (int)race->size, race->file, race->line);
|
|
134 atomic_fetch_add(&race->hitcount, 1, memory_order_relaxed);
|
|
135 return true;
|
|
136 }
|
|
137
|
|
138 static void InitList(ExpectRace *list) {
|
|
139 list->next = list;
|
|
140 list->prev = list;
|
|
141 }
|
|
142
|
|
143 void InitializeDynamicAnnotations() {
|
|
144 dyn_ann_ctx = new(dyn_ann_ctx_placeholder) DynamicAnnContext;
|
|
145 InitList(&dyn_ann_ctx->expect);
|
|
146 InitList(&dyn_ann_ctx->benign);
|
|
147 }
|
|
148
|
|
149 bool IsExpectedReport(uptr addr, uptr size) {
|
|
150 ReadLock lock(&dyn_ann_ctx->mtx);
|
|
151 if (CheckContains(&dyn_ann_ctx->expect, addr, size))
|
|
152 return true;
|
|
153 if (CheckContains(&dyn_ann_ctx->benign, addr, size))
|
|
154 return true;
|
|
155 return false;
|
|
156 }
|
|
157
|
|
158 static void CollectMatchedBenignRaces(Vector<ExpectRace> *matched,
|
|
159 int *unique_count, int *hit_count, atomic_uintptr_t ExpectRace::*counter) {
|
|
160 ExpectRace *list = &dyn_ann_ctx->benign;
|
|
161 for (ExpectRace *race = list->next; race != list; race = race->next) {
|
|
162 (*unique_count)++;
|
|
163 const uptr cnt = atomic_load_relaxed(&(race->*counter));
|
|
164 if (cnt == 0)
|
|
165 continue;
|
|
166 *hit_count += cnt;
|
|
167 uptr i = 0;
|
|
168 for (; i < matched->Size(); i++) {
|
|
169 ExpectRace *race0 = &(*matched)[i];
|
|
170 if (race->line == race0->line
|
|
171 && internal_strcmp(race->file, race0->file) == 0
|
|
172 && internal_strcmp(race->desc, race0->desc) == 0) {
|
|
173 atomic_fetch_add(&(race0->*counter), cnt, memory_order_relaxed);
|
|
174 break;
|
|
175 }
|
|
176 }
|
|
177 if (i == matched->Size())
|
|
178 matched->PushBack(*race);
|
|
179 }
|
|
180 }
|
|
181
|
|
182 void PrintMatchedBenignRaces() {
|
|
183 Lock lock(&dyn_ann_ctx->mtx);
|
|
184 int unique_count = 0;
|
|
185 int hit_count = 0;
|
|
186 int add_count = 0;
|
|
187 Vector<ExpectRace> hit_matched;
|
|
188 CollectMatchedBenignRaces(&hit_matched, &unique_count, &hit_count,
|
|
189 &ExpectRace::hitcount);
|
|
190 Vector<ExpectRace> add_matched;
|
|
191 CollectMatchedBenignRaces(&add_matched, &unique_count, &add_count,
|
|
192 &ExpectRace::addcount);
|
|
193 if (hit_matched.Size()) {
|
|
194 Printf("ThreadSanitizer: Matched %d \"benign\" races (pid=%d):\n",
|
|
195 hit_count, (int)internal_getpid());
|
|
196 for (uptr i = 0; i < hit_matched.Size(); i++) {
|
|
197 Printf("%d %s:%d %s\n",
|
|
198 atomic_load_relaxed(&hit_matched[i].hitcount),
|
|
199 hit_matched[i].file, hit_matched[i].line, hit_matched[i].desc);
|
|
200 }
|
|
201 }
|
|
202 if (hit_matched.Size()) {
|
|
203 Printf("ThreadSanitizer: Annotated %d \"benign\" races, %d unique"
|
|
204 " (pid=%d):\n",
|
|
205 add_count, unique_count, (int)internal_getpid());
|
|
206 for (uptr i = 0; i < add_matched.Size(); i++) {
|
|
207 Printf("%d %s:%d %s\n",
|
|
208 atomic_load_relaxed(&add_matched[i].addcount),
|
|
209 add_matched[i].file, add_matched[i].line, add_matched[i].desc);
|
|
210 }
|
|
211 }
|
|
212 }
|
|
213
|
|
214 static void ReportMissedExpectedRace(ExpectRace *race) {
|
|
215 Printf("==================\n");
|
|
216 Printf("WARNING: ThreadSanitizer: missed expected data race\n");
|
|
217 Printf(" %s addr=%zx %s:%d\n",
|
|
218 race->desc, race->addr, race->file, race->line);
|
|
219 Printf("==================\n");
|
|
220 }
|
|
221 } // namespace __tsan
|
|
222
|
|
223 using namespace __tsan;
|
|
224
|
|
225 extern "C" {
|
|
226 void INTERFACE_ATTRIBUTE AnnotateHappensBefore(char *f, int l, uptr addr) {
|
|
227 SCOPED_ANNOTATION(AnnotateHappensBefore);
|
|
228 Release(thr, pc, addr);
|
|
229 }
|
|
230
|
|
231 void INTERFACE_ATTRIBUTE AnnotateHappensAfter(char *f, int l, uptr addr) {
|
|
232 SCOPED_ANNOTATION(AnnotateHappensAfter);
|
|
233 Acquire(thr, pc, addr);
|
|
234 }
|
|
235
|
|
236 void INTERFACE_ATTRIBUTE AnnotateCondVarSignal(char *f, int l, uptr cv) {
|
|
237 SCOPED_ANNOTATION(AnnotateCondVarSignal);
|
|
238 }
|
|
239
|
|
240 void INTERFACE_ATTRIBUTE AnnotateCondVarSignalAll(char *f, int l, uptr cv) {
|
|
241 SCOPED_ANNOTATION(AnnotateCondVarSignalAll);
|
|
242 }
|
|
243
|
|
244 void INTERFACE_ATTRIBUTE AnnotateMutexIsNotPHB(char *f, int l, uptr mu) {
|
|
245 SCOPED_ANNOTATION(AnnotateMutexIsNotPHB);
|
|
246 }
|
|
247
|
|
248 void INTERFACE_ATTRIBUTE AnnotateCondVarWait(char *f, int l, uptr cv,
|
|
249 uptr lock) {
|
|
250 SCOPED_ANNOTATION(AnnotateCondVarWait);
|
|
251 }
|
|
252
|
|
253 void INTERFACE_ATTRIBUTE AnnotateRWLockCreate(char *f, int l, uptr m) {
|
|
254 SCOPED_ANNOTATION(AnnotateRWLockCreate);
|
|
255 MutexCreate(thr, pc, m, MutexFlagWriteReentrant);
|
|
256 }
|
|
257
|
|
258 void INTERFACE_ATTRIBUTE AnnotateRWLockCreateStatic(char *f, int l, uptr m) {
|
|
259 SCOPED_ANNOTATION(AnnotateRWLockCreateStatic);
|
|
260 MutexCreate(thr, pc, m, MutexFlagWriteReentrant | MutexFlagLinkerInit);
|
|
261 }
|
|
262
|
|
263 void INTERFACE_ATTRIBUTE AnnotateRWLockDestroy(char *f, int l, uptr m) {
|
|
264 SCOPED_ANNOTATION(AnnotateRWLockDestroy);
|
|
265 MutexDestroy(thr, pc, m);
|
|
266 }
|
|
267
|
|
268 void INTERFACE_ATTRIBUTE AnnotateRWLockAcquired(char *f, int l, uptr m,
|
|
269 uptr is_w) {
|
|
270 SCOPED_ANNOTATION(AnnotateRWLockAcquired);
|
|
271 if (is_w)
|
|
272 MutexPostLock(thr, pc, m, MutexFlagDoPreLockOnPostLock);
|
|
273 else
|
|
274 MutexPostReadLock(thr, pc, m, MutexFlagDoPreLockOnPostLock);
|
|
275 }
|
|
276
|
|
277 void INTERFACE_ATTRIBUTE AnnotateRWLockReleased(char *f, int l, uptr m,
|
|
278 uptr is_w) {
|
|
279 SCOPED_ANNOTATION(AnnotateRWLockReleased);
|
|
280 if (is_w)
|
|
281 MutexUnlock(thr, pc, m);
|
|
282 else
|
|
283 MutexReadUnlock(thr, pc, m);
|
|
284 }
|
|
285
|
|
286 void INTERFACE_ATTRIBUTE AnnotateTraceMemory(char *f, int l, uptr mem) {
|
|
287 SCOPED_ANNOTATION(AnnotateTraceMemory);
|
|
288 }
|
|
289
|
|
290 void INTERFACE_ATTRIBUTE AnnotateFlushState(char *f, int l) {
|
|
291 SCOPED_ANNOTATION(AnnotateFlushState);
|
|
292 }
|
|
293
|
|
294 void INTERFACE_ATTRIBUTE AnnotateNewMemory(char *f, int l, uptr mem,
|
|
295 uptr size) {
|
|
296 SCOPED_ANNOTATION(AnnotateNewMemory);
|
|
297 }
|
|
298
|
|
299 void INTERFACE_ATTRIBUTE AnnotateNoOp(char *f, int l, uptr mem) {
|
|
300 SCOPED_ANNOTATION(AnnotateNoOp);
|
|
301 }
|
|
302
|
|
303 void INTERFACE_ATTRIBUTE AnnotateFlushExpectedRaces(char *f, int l) {
|
|
304 SCOPED_ANNOTATION(AnnotateFlushExpectedRaces);
|
|
305 Lock lock(&dyn_ann_ctx->mtx);
|
|
306 while (dyn_ann_ctx->expect.next != &dyn_ann_ctx->expect) {
|
|
307 ExpectRace *race = dyn_ann_ctx->expect.next;
|
|
308 if (atomic_load_relaxed(&race->hitcount) == 0) {
|
|
309 ctx->nmissed_expected++;
|
|
310 ReportMissedExpectedRace(race);
|
|
311 }
|
|
312 race->prev->next = race->next;
|
|
313 race->next->prev = race->prev;
|
|
314 internal_free(race);
|
|
315 }
|
|
316 }
|
|
317
|
|
318 void INTERFACE_ATTRIBUTE AnnotateEnableRaceDetection(
|
|
319 char *f, int l, int enable) {
|
|
320 SCOPED_ANNOTATION(AnnotateEnableRaceDetection);
|
|
321 // FIXME: Reconsider this functionality later. It may be irrelevant.
|
|
322 }
|
|
323
|
|
324 void INTERFACE_ATTRIBUTE AnnotateMutexIsUsedAsCondVar(
|
|
325 char *f, int l, uptr mu) {
|
|
326 SCOPED_ANNOTATION(AnnotateMutexIsUsedAsCondVar);
|
|
327 }
|
|
328
|
|
329 void INTERFACE_ATTRIBUTE AnnotatePCQGet(
|
|
330 char *f, int l, uptr pcq) {
|
|
331 SCOPED_ANNOTATION(AnnotatePCQGet);
|
|
332 }
|
|
333
|
|
334 void INTERFACE_ATTRIBUTE AnnotatePCQPut(
|
|
335 char *f, int l, uptr pcq) {
|
|
336 SCOPED_ANNOTATION(AnnotatePCQPut);
|
|
337 }
|
|
338
|
|
339 void INTERFACE_ATTRIBUTE AnnotatePCQDestroy(
|
|
340 char *f, int l, uptr pcq) {
|
|
341 SCOPED_ANNOTATION(AnnotatePCQDestroy);
|
|
342 }
|
|
343
|
|
344 void INTERFACE_ATTRIBUTE AnnotatePCQCreate(
|
|
345 char *f, int l, uptr pcq) {
|
|
346 SCOPED_ANNOTATION(AnnotatePCQCreate);
|
|
347 }
|
|
348
|
|
349 void INTERFACE_ATTRIBUTE AnnotateExpectRace(
|
|
350 char *f, int l, uptr mem, char *desc) {
|
|
351 SCOPED_ANNOTATION(AnnotateExpectRace);
|
|
352 Lock lock(&dyn_ann_ctx->mtx);
|
|
353 AddExpectRace(&dyn_ann_ctx->expect,
|
|
354 f, l, mem, 1, desc);
|
|
355 DPrintf("Add expected race: %s addr=%zx %s:%d\n", desc, mem, f, l);
|
|
356 }
|
|
357
|
|
358 static void BenignRaceImpl(
|
|
359 char *f, int l, uptr mem, uptr size, char *desc) {
|
|
360 Lock lock(&dyn_ann_ctx->mtx);
|
|
361 AddExpectRace(&dyn_ann_ctx->benign,
|
|
362 f, l, mem, size, desc);
|
|
363 DPrintf("Add benign race: %s addr=%zx %s:%d\n", desc, mem, f, l);
|
|
364 }
|
|
365
|
|
366 // FIXME: Turn it off later. WTF is benign race?1?? Go talk to Hans Boehm.
|
|
367 void INTERFACE_ATTRIBUTE AnnotateBenignRaceSized(
|
|
368 char *f, int l, uptr mem, uptr size, char *desc) {
|
|
369 SCOPED_ANNOTATION(AnnotateBenignRaceSized);
|
|
370 BenignRaceImpl(f, l, mem, size, desc);
|
|
371 }
|
|
372
|
|
373 void INTERFACE_ATTRIBUTE AnnotateBenignRace(
|
|
374 char *f, int l, uptr mem, char *desc) {
|
|
375 SCOPED_ANNOTATION(AnnotateBenignRace);
|
|
376 BenignRaceImpl(f, l, mem, 1, desc);
|
|
377 }
|
|
378
|
|
379 void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsBegin(char *f, int l) {
|
|
380 SCOPED_ANNOTATION(AnnotateIgnoreReadsBegin);
|
|
381 ThreadIgnoreBegin(thr, pc);
|
|
382 }
|
|
383
|
|
384 void INTERFACE_ATTRIBUTE AnnotateIgnoreReadsEnd(char *f, int l) {
|
|
385 SCOPED_ANNOTATION(AnnotateIgnoreReadsEnd);
|
|
386 ThreadIgnoreEnd(thr, pc);
|
|
387 }
|
|
388
|
|
389 void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesBegin(char *f, int l) {
|
|
390 SCOPED_ANNOTATION(AnnotateIgnoreWritesBegin);
|
|
391 ThreadIgnoreBegin(thr, pc);
|
|
392 }
|
|
393
|
|
394 void INTERFACE_ATTRIBUTE AnnotateIgnoreWritesEnd(char *f, int l) {
|
|
395 SCOPED_ANNOTATION(AnnotateIgnoreWritesEnd);
|
|
396 ThreadIgnoreEnd(thr, pc);
|
|
397 }
|
|
398
|
|
399 void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncBegin(char *f, int l) {
|
|
400 SCOPED_ANNOTATION(AnnotateIgnoreSyncBegin);
|
|
401 ThreadIgnoreSyncBegin(thr, pc);
|
|
402 }
|
|
403
|
|
404 void INTERFACE_ATTRIBUTE AnnotateIgnoreSyncEnd(char *f, int l) {
|
|
405 SCOPED_ANNOTATION(AnnotateIgnoreSyncEnd);
|
|
406 ThreadIgnoreSyncEnd(thr, pc);
|
|
407 }
|
|
408
|
|
409 void INTERFACE_ATTRIBUTE AnnotatePublishMemoryRange(
|
|
410 char *f, int l, uptr addr, uptr size) {
|
|
411 SCOPED_ANNOTATION(AnnotatePublishMemoryRange);
|
|
412 }
|
|
413
|
|
414 void INTERFACE_ATTRIBUTE AnnotateUnpublishMemoryRange(
|
|
415 char *f, int l, uptr addr, uptr size) {
|
|
416 SCOPED_ANNOTATION(AnnotateUnpublishMemoryRange);
|
|
417 }
|
|
418
|
|
419 void INTERFACE_ATTRIBUTE AnnotateThreadName(
|
|
420 char *f, int l, char *name) {
|
|
421 SCOPED_ANNOTATION(AnnotateThreadName);
|
|
422 ThreadSetName(thr, name);
|
|
423 }
|
|
424
|
|
425 // We deliberately omit the implementation of WTFAnnotateHappensBefore() and
|
|
426 // WTFAnnotateHappensAfter(). Those are being used by Webkit to annotate
|
|
427 // atomic operations, which should be handled by ThreadSanitizer correctly.
|
|
428 void INTERFACE_ATTRIBUTE WTFAnnotateHappensBefore(char *f, int l, uptr addr) {
|
|
429 SCOPED_ANNOTATION(AnnotateHappensBefore);
|
|
430 }
|
|
431
|
|
432 void INTERFACE_ATTRIBUTE WTFAnnotateHappensAfter(char *f, int l, uptr addr) {
|
|
433 SCOPED_ANNOTATION(AnnotateHappensAfter);
|
|
434 }
|
|
435
|
|
436 void INTERFACE_ATTRIBUTE WTFAnnotateBenignRaceSized(
|
|
437 char *f, int l, uptr mem, uptr sz, char *desc) {
|
|
438 SCOPED_ANNOTATION(AnnotateBenignRaceSized);
|
|
439 BenignRaceImpl(f, l, mem, sz, desc);
|
|
440 }
|
|
441
|
|
442 int INTERFACE_ATTRIBUTE RunningOnValgrind() {
|
|
443 return flags()->running_on_valgrind;
|
|
444 }
|
|
445
|
|
446 double __attribute__((weak)) INTERFACE_ATTRIBUTE ValgrindSlowdown(void) {
|
|
447 return 10.0;
|
|
448 }
|
|
449
|
|
450 const char INTERFACE_ATTRIBUTE* ThreadSanitizerQuery(const char *query) {
|
|
451 if (internal_strcmp(query, "pure_happens_before") == 0)
|
|
452 return "1";
|
|
453 else
|
|
454 return "0";
|
|
455 }
|
|
456
|
|
457 void INTERFACE_ATTRIBUTE
|
|
458 AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {}
|
|
459 void INTERFACE_ATTRIBUTE
|
|
460 AnnotateMemoryIsUninitialized(char *f, int l, uptr mem, uptr sz) {}
|
|
461
|
|
462 // Note: the parameter is called flagz, because flags is already taken
|
|
463 // by the global function that returns flags.
|
|
464 INTERFACE_ATTRIBUTE
|
|
465 void __tsan_mutex_create(void *m, unsigned flagz) {
|
|
466 SCOPED_ANNOTATION(__tsan_mutex_create);
|
|
467 MutexCreate(thr, pc, (uptr)m, flagz & MutexCreationFlagMask);
|
|
468 }
|
|
469
|
|
470 INTERFACE_ATTRIBUTE
|
|
471 void __tsan_mutex_destroy(void *m, unsigned flagz) {
|
|
472 SCOPED_ANNOTATION(__tsan_mutex_destroy);
|
|
473 MutexDestroy(thr, pc, (uptr)m, flagz);
|
|
474 }
|
|
475
|
|
476 INTERFACE_ATTRIBUTE
|
|
477 void __tsan_mutex_pre_lock(void *m, unsigned flagz) {
|
|
478 SCOPED_ANNOTATION(__tsan_mutex_pre_lock);
|
|
479 if (!(flagz & MutexFlagTryLock)) {
|
|
480 if (flagz & MutexFlagReadLock)
|
|
481 MutexPreReadLock(thr, pc, (uptr)m);
|
|
482 else
|
|
483 MutexPreLock(thr, pc, (uptr)m);
|
|
484 }
|
|
485 ThreadIgnoreBegin(thr, pc, /*save_stack=*/false);
|
|
486 ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false);
|
|
487 }
|
|
488
|
|
489 INTERFACE_ATTRIBUTE
|
|
490 void __tsan_mutex_post_lock(void *m, unsigned flagz, int rec) {
|
|
491 SCOPED_ANNOTATION(__tsan_mutex_post_lock);
|
|
492 ThreadIgnoreSyncEnd(thr, pc);
|
|
493 ThreadIgnoreEnd(thr, pc);
|
|
494 if (!(flagz & MutexFlagTryLockFailed)) {
|
|
495 if (flagz & MutexFlagReadLock)
|
|
496 MutexPostReadLock(thr, pc, (uptr)m, flagz);
|
|
497 else
|
|
498 MutexPostLock(thr, pc, (uptr)m, flagz, rec);
|
|
499 }
|
|
500 }
|
|
501
|
|
502 INTERFACE_ATTRIBUTE
|
|
503 int __tsan_mutex_pre_unlock(void *m, unsigned flagz) {
|
|
504 SCOPED_ANNOTATION_RET(__tsan_mutex_pre_unlock, 0);
|
|
505 int ret = 0;
|
|
506 if (flagz & MutexFlagReadLock) {
|
|
507 CHECK(!(flagz & MutexFlagRecursiveUnlock));
|
|
508 MutexReadUnlock(thr, pc, (uptr)m);
|
|
509 } else {
|
|
510 ret = MutexUnlock(thr, pc, (uptr)m, flagz);
|
|
511 }
|
|
512 ThreadIgnoreBegin(thr, pc, /*save_stack=*/false);
|
|
513 ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false);
|
|
514 return ret;
|
|
515 }
|
|
516
|
|
517 INTERFACE_ATTRIBUTE
|
|
518 void __tsan_mutex_post_unlock(void *m, unsigned flagz) {
|
|
519 SCOPED_ANNOTATION(__tsan_mutex_post_unlock);
|
|
520 ThreadIgnoreSyncEnd(thr, pc);
|
|
521 ThreadIgnoreEnd(thr, pc);
|
|
522 }
|
|
523
|
|
524 INTERFACE_ATTRIBUTE
|
|
525 void __tsan_mutex_pre_signal(void *addr, unsigned flagz) {
|
|
526 SCOPED_ANNOTATION(__tsan_mutex_pre_signal);
|
|
527 ThreadIgnoreBegin(thr, pc, /*save_stack=*/false);
|
|
528 ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false);
|
|
529 }
|
|
530
|
|
531 INTERFACE_ATTRIBUTE
|
|
532 void __tsan_mutex_post_signal(void *addr, unsigned flagz) {
|
|
533 SCOPED_ANNOTATION(__tsan_mutex_post_signal);
|
|
534 ThreadIgnoreSyncEnd(thr, pc);
|
|
535 ThreadIgnoreEnd(thr, pc);
|
|
536 }
|
|
537
|
|
538 INTERFACE_ATTRIBUTE
|
|
539 void __tsan_mutex_pre_divert(void *addr, unsigned flagz) {
|
|
540 SCOPED_ANNOTATION(__tsan_mutex_pre_divert);
|
|
541 // Exit from ignore region started in __tsan_mutex_pre_lock/unlock/signal.
|
|
542 ThreadIgnoreSyncEnd(thr, pc);
|
|
543 ThreadIgnoreEnd(thr, pc);
|
|
544 }
|
|
545
|
|
546 INTERFACE_ATTRIBUTE
|
|
547 void __tsan_mutex_post_divert(void *addr, unsigned flagz) {
|
|
548 SCOPED_ANNOTATION(__tsan_mutex_post_divert);
|
|
549 ThreadIgnoreBegin(thr, pc, /*save_stack=*/false);
|
|
550 ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false);
|
|
551 }
|
|
552 } // extern "C"
|