2016-10-21 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / libsanitizer / tsan / tsan_libdispatch_mac.cc
blob5b39665d5d20b8eec7fb9af3209f607c93c0f629
1 //===-- tsan_libdispatch_mac.cc -------------------------------------------===//
2 //
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
9 //
10 // Mac-specific libdispatch (GCD) support.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_platform.h"
14 #if SANITIZER_MAC
16 #include "sanitizer_common/sanitizer_common.h"
17 #include "interception/interception.h"
18 #include "tsan_interceptors.h"
19 #include "tsan_platform.h"
20 #include "tsan_rtl.h"
22 #include <dispatch/dispatch.h>
23 #include <pthread.h>
25 namespace __tsan {
27 // GCD's dispatch_once implementation has a fast path that contains a racy read
28 // and it's inlined into user's code. Furthermore, this fast path doesn't
29 // establish a proper happens-before relations between the initialization and
30 // code following the call to dispatch_once. We could deal with this in
31 // instrumented code, but there's not much we can do about it in system
32 // libraries. Let's disable the fast path (by never storing the value ~0 to
33 // predicate), so the interceptor is always called, and let's add proper release
34 // and acquire semantics. Since TSan does not see its own atomic stores, the
35 // race on predicate won't be reported - the only accesses to it that TSan sees
36 // are the loads on the fast path. Loads don't race. Secondly, dispatch_once is
37 // both a macro and a real function, we want to intercept the function, so we
38 // need to undefine the macro.
39 #undef dispatch_once
40 TSAN_INTERCEPTOR(void, dispatch_once, dispatch_once_t *predicate,
41 dispatch_block_t block) {
42 SCOPED_TSAN_INTERCEPTOR(dispatch_once, predicate, block);
43 atomic_uint32_t *a = reinterpret_cast<atomic_uint32_t *>(predicate);
44 u32 v = atomic_load(a, memory_order_acquire);
45 if (v == 0 &&
46 atomic_compare_exchange_strong(a, &v, 1, memory_order_relaxed)) {
47 block();
48 Release(thr, pc, (uptr)a);
49 atomic_store(a, 2, memory_order_release);
50 } else {
51 while (v != 2) {
52 internal_sched_yield();
53 v = atomic_load(a, memory_order_acquire);
55 Acquire(thr, pc, (uptr)a);
59 #undef dispatch_once_f
60 TSAN_INTERCEPTOR(void, dispatch_once_f, dispatch_once_t *predicate,
61 void *context, dispatch_function_t function) {
62 SCOPED_TSAN_INTERCEPTOR(dispatch_once_f, predicate, context, function);
63 WRAP(dispatch_once)(predicate, ^(void) {
64 function(context);
65 });
68 } // namespace __tsan
70 #endif // SANITIZER_MAC