1 //===-- tsan_libdispatch_mac.cc -------------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer (TSan), a race detector.
10 // Mac-specific libdispatch (GCD) support.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_common/sanitizer_platform.h"
16 #include "sanitizer_common/sanitizer_common.h"
17 #include "interception/interception.h"
18 #include "tsan_interceptors.h"
19 #include "tsan_platform.h"
22 #include <dispatch/dispatch.h>
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.
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
);
46 atomic_compare_exchange_strong(a
, &v
, 1, memory_order_relaxed
)) {
48 Release(thr
, pc
, (uptr
)a
);
49 atomic_store(a
, 2, memory_order_release
);
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) {
70 #endif // SANITIZER_MAC