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