Home | History | Annotate | Line # | Download | only in tsan
      1  1.1  mrg //===-- tsan_interceptors_libdispatch.cpp ---------------------------------===//
      2  1.1  mrg //
      3  1.1  mrg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
      4  1.1  mrg // See https://llvm.org/LICENSE.txt for license information.
      5  1.1  mrg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
      6  1.1  mrg //
      7  1.1  mrg //===----------------------------------------------------------------------===//
      8  1.1  mrg //
      9  1.1  mrg // This file is a part of ThreadSanitizer (TSan), a race detector.
     10  1.1  mrg //
     11  1.1  mrg // Support for intercepting libdispatch (GCD).
     12  1.1  mrg //===----------------------------------------------------------------------===//
     13  1.1  mrg 
     14  1.1  mrg #include "sanitizer_common/sanitizer_common.h"
     15  1.1  mrg #include "interception/interception.h"
     16  1.1  mrg #include "tsan_interceptors.h"
     17  1.1  mrg #include "tsan_rtl.h"
     18  1.1  mrg 
     19  1.1  mrg #include "BlocksRuntime/Block.h"
     20  1.1  mrg #include "tsan_dispatch_defs.h"
     21  1.1  mrg 
     22  1.4  mrg #if SANITIZER_APPLE
     23  1.3  mrg # include <Availability.h>
     24  1.3  mrg #endif
     25  1.3  mrg 
     26  1.1  mrg namespace __tsan {
     27  1.1  mrg   typedef u16 uint16_t;
     28  1.1  mrg 
     29  1.1  mrg typedef struct {
     30  1.1  mrg   dispatch_queue_t queue;
     31  1.1  mrg   void *orig_context;
     32  1.1  mrg   dispatch_function_t orig_work;
     33  1.1  mrg   bool free_context_in_callback;
     34  1.1  mrg   bool submitted_synchronously;
     35  1.1  mrg   bool is_barrier_block;
     36  1.1  mrg   uptr non_queue_sync_object;
     37  1.1  mrg } block_context_t;
     38  1.1  mrg 
     39  1.1  mrg // The offsets of different fields of the dispatch_queue_t structure, exported
     40  1.1  mrg // by libdispatch.dylib.
     41  1.1  mrg extern "C" struct dispatch_queue_offsets_s {
     42  1.1  mrg   const uint16_t dqo_version;
     43  1.1  mrg   const uint16_t dqo_label;
     44  1.1  mrg   const uint16_t dqo_label_size;
     45  1.1  mrg   const uint16_t dqo_flags;
     46  1.1  mrg   const uint16_t dqo_flags_size;
     47  1.1  mrg   const uint16_t dqo_serialnum;
     48  1.1  mrg   const uint16_t dqo_serialnum_size;
     49  1.1  mrg   const uint16_t dqo_width;
     50  1.1  mrg   const uint16_t dqo_width_size;
     51  1.1  mrg   const uint16_t dqo_running;
     52  1.1  mrg   const uint16_t dqo_running_size;
     53  1.1  mrg   const uint16_t dqo_suspend_cnt;
     54  1.1  mrg   const uint16_t dqo_suspend_cnt_size;
     55  1.1  mrg   const uint16_t dqo_target_queue;
     56  1.1  mrg   const uint16_t dqo_target_queue_size;
     57  1.1  mrg   const uint16_t dqo_priority;
     58  1.1  mrg   const uint16_t dqo_priority_size;
     59  1.1  mrg } dispatch_queue_offsets;
     60  1.1  mrg 
     61  1.1  mrg static bool IsQueueSerial(dispatch_queue_t q) {
     62  1.1  mrg   CHECK_EQ(dispatch_queue_offsets.dqo_width_size, 2);
     63  1.1  mrg   uptr width = *(uint16_t *)(((uptr)q) + dispatch_queue_offsets.dqo_width);
     64  1.1  mrg   CHECK_NE(width, 0);
     65  1.1  mrg   return width == 1;
     66  1.1  mrg }
     67  1.1  mrg 
     68  1.1  mrg static dispatch_queue_t GetTargetQueueFromQueue(dispatch_queue_t q) {
     69  1.1  mrg   CHECK_EQ(dispatch_queue_offsets.dqo_target_queue_size, 8);
     70  1.1  mrg   dispatch_queue_t tq = *(
     71  1.1  mrg       dispatch_queue_t *)(((uptr)q) + dispatch_queue_offsets.dqo_target_queue);
     72  1.1  mrg   return tq;
     73  1.1  mrg }
     74  1.1  mrg 
     75  1.1  mrg static dispatch_queue_t GetTargetQueueFromSource(dispatch_source_t source) {
     76  1.1  mrg   dispatch_queue_t tq = GetTargetQueueFromQueue((dispatch_queue_t)source);
     77  1.1  mrg   CHECK_NE(tq, 0);
     78  1.1  mrg   return tq;
     79  1.1  mrg }
     80  1.1  mrg 
     81  1.1  mrg static block_context_t *AllocContext(ThreadState *thr, uptr pc,
     82  1.1  mrg                                      dispatch_queue_t queue, void *orig_context,
     83  1.1  mrg                                      dispatch_function_t orig_work) {
     84  1.1  mrg   block_context_t *new_context =
     85  1.1  mrg       (block_context_t *)user_alloc_internal(thr, pc, sizeof(block_context_t));
     86  1.1  mrg   new_context->queue = queue;
     87  1.1  mrg   new_context->orig_context = orig_context;
     88  1.1  mrg   new_context->orig_work = orig_work;
     89  1.1  mrg   new_context->free_context_in_callback = true;
     90  1.1  mrg   new_context->submitted_synchronously = false;
     91  1.1  mrg   new_context->is_barrier_block = false;
     92  1.1  mrg   new_context->non_queue_sync_object = 0;
     93  1.1  mrg   return new_context;
     94  1.1  mrg }
     95  1.1  mrg 
     96  1.1  mrg #define GET_QUEUE_SYNC_VARS(context, q)                                  \
     97  1.1  mrg   bool is_queue_serial = q && IsQueueSerial(q);                          \
     98  1.1  mrg   uptr sync_ptr = (uptr)q ?: context->non_queue_sync_object;             \
     99  1.1  mrg   uptr serial_sync = (uptr)sync_ptr;                                     \
    100  1.1  mrg   uptr concurrent_sync = sync_ptr ? ((uptr)sync_ptr) + sizeof(uptr) : 0; \
    101  1.1  mrg   bool serial_task = context->is_barrier_block || is_queue_serial
    102  1.1  mrg 
    103  1.1  mrg static void dispatch_sync_pre_execute(ThreadState *thr, uptr pc,
    104  1.1  mrg                                       block_context_t *context) {
    105  1.1  mrg   uptr submit_sync = (uptr)context;
    106  1.1  mrg   Acquire(thr, pc, submit_sync);
    107  1.1  mrg 
    108  1.1  mrg   dispatch_queue_t q = context->queue;
    109  1.1  mrg   do {
    110  1.1  mrg     GET_QUEUE_SYNC_VARS(context, q);
    111  1.1  mrg     if (serial_sync) Acquire(thr, pc, serial_sync);
    112  1.1  mrg     if (serial_task && concurrent_sync) Acquire(thr, pc, concurrent_sync);
    113  1.1  mrg 
    114  1.1  mrg     if (q) q = GetTargetQueueFromQueue(q);
    115  1.1  mrg   } while (q);
    116  1.1  mrg }
    117  1.1  mrg 
    118  1.1  mrg static void dispatch_sync_post_execute(ThreadState *thr, uptr pc,
    119  1.1  mrg                                        block_context_t *context) {
    120  1.1  mrg   uptr submit_sync = (uptr)context;
    121  1.1  mrg   if (context->submitted_synchronously) Release(thr, pc, submit_sync);
    122  1.1  mrg 
    123  1.1  mrg   dispatch_queue_t q = context->queue;
    124  1.1  mrg   do {
    125  1.1  mrg     GET_QUEUE_SYNC_VARS(context, q);
    126  1.1  mrg     if (serial_task && serial_sync) Release(thr, pc, serial_sync);
    127  1.1  mrg     if (!serial_task && concurrent_sync) Release(thr, pc, concurrent_sync);
    128  1.1  mrg 
    129  1.1  mrg     if (q) q = GetTargetQueueFromQueue(q);
    130  1.1  mrg   } while (q);
    131  1.1  mrg }
    132  1.1  mrg 
    133  1.1  mrg static void dispatch_callback_wrap(void *param) {
    134  1.1  mrg   SCOPED_INTERCEPTOR_RAW(dispatch_callback_wrap);
    135  1.1  mrg   block_context_t *context = (block_context_t *)param;
    136  1.1  mrg 
    137  1.1  mrg   dispatch_sync_pre_execute(thr, pc, context);
    138  1.1  mrg 
    139  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
    140  1.1  mrg   context->orig_work(context->orig_context);
    141  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
    142  1.1  mrg 
    143  1.1  mrg   dispatch_sync_post_execute(thr, pc, context);
    144  1.1  mrg 
    145  1.1  mrg   if (context->free_context_in_callback) user_free(thr, pc, context);
    146  1.1  mrg }
    147  1.1  mrg 
    148  1.1  mrg static void invoke_block(void *param) {
    149  1.1  mrg   dispatch_block_t block = (dispatch_block_t)param;
    150  1.1  mrg   block();
    151  1.1  mrg }
    152  1.1  mrg 
    153  1.1  mrg static void invoke_and_release_block(void *param) {
    154  1.1  mrg   dispatch_block_t block = (dispatch_block_t)param;
    155  1.1  mrg   block();
    156  1.1  mrg   Block_release(block);
    157  1.1  mrg }
    158  1.1  mrg 
    159  1.1  mrg #define DISPATCH_INTERCEPT_ASYNC_B(name, barrier)                            \
    160  1.1  mrg   TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, dispatch_block_t block) { \
    161  1.1  mrg     SCOPED_TSAN_INTERCEPTOR(name, q, block);                                 \
    162  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();                           \
    163  1.1  mrg     dispatch_block_t heap_block = Block_copy(block);                         \
    164  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();                             \
    165  1.1  mrg     block_context_t *new_context =                                           \
    166  1.1  mrg         AllocContext(thr, pc, q, heap_block, &invoke_and_release_block);     \
    167  1.1  mrg     new_context->is_barrier_block = barrier;                                 \
    168  1.1  mrg     Release(thr, pc, (uptr)new_context);                                     \
    169  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();                           \
    170  1.1  mrg     REAL(name##_f)(q, new_context, dispatch_callback_wrap);                  \
    171  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();                             \
    172  1.1  mrg   }
    173  1.1  mrg 
    174  1.1  mrg #define DISPATCH_INTERCEPT_SYNC_B(name, barrier)                             \
    175  1.1  mrg   TSAN_INTERCEPTOR(void, name, dispatch_queue_t q,                           \
    176  1.1  mrg                    DISPATCH_NOESCAPE dispatch_block_t block) {               \
    177  1.1  mrg     SCOPED_TSAN_INTERCEPTOR(name, q, block);                                 \
    178  1.1  mrg     block_context_t new_context = {                                          \
    179  1.1  mrg         q, block, &invoke_block, false, true, barrier, 0};                   \
    180  1.1  mrg     Release(thr, pc, (uptr)&new_context);                                    \
    181  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();                           \
    182  1.1  mrg     REAL(name##_f)(q, &new_context, dispatch_callback_wrap);                 \
    183  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();                             \
    184  1.1  mrg     Acquire(thr, pc, (uptr)&new_context);                                    \
    185  1.1  mrg   }
    186  1.1  mrg 
    187  1.1  mrg #define DISPATCH_INTERCEPT_ASYNC_F(name, barrier)                 \
    188  1.1  mrg   TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, void *context, \
    189  1.1  mrg                    dispatch_function_t work) {                    \
    190  1.1  mrg     SCOPED_TSAN_INTERCEPTOR(name, q, context, work);              \
    191  1.1  mrg     block_context_t *new_context =                                \
    192  1.1  mrg         AllocContext(thr, pc, q, context, work);                  \
    193  1.1  mrg     new_context->is_barrier_block = barrier;                      \
    194  1.1  mrg     Release(thr, pc, (uptr)new_context);                          \
    195  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();                \
    196  1.1  mrg     REAL(name)(q, new_context, dispatch_callback_wrap);           \
    197  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();                  \
    198  1.1  mrg   }
    199  1.1  mrg 
    200  1.1  mrg #define DISPATCH_INTERCEPT_SYNC_F(name, barrier)                              \
    201  1.1  mrg   TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, void *context,             \
    202  1.1  mrg                    dispatch_function_t work) {                                \
    203  1.1  mrg     SCOPED_TSAN_INTERCEPTOR(name, q, context, work);                          \
    204  1.1  mrg     block_context_t new_context = {                                           \
    205  1.1  mrg         q, context, work, false, true, barrier, 0};                           \
    206  1.1  mrg     Release(thr, pc, (uptr)&new_context);                                     \
    207  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();                            \
    208  1.1  mrg     REAL(name)(q, &new_context, dispatch_callback_wrap);                      \
    209  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();                              \
    210  1.1  mrg     Acquire(thr, pc, (uptr)&new_context);                                     \
    211  1.1  mrg   }
    212  1.1  mrg 
    213  1.1  mrg #define DISPATCH_INTERCEPT(name, barrier)             \
    214  1.1  mrg   DISPATCH_INTERCEPT_ASYNC_F(name##_async_f, barrier) \
    215  1.1  mrg   DISPATCH_INTERCEPT_ASYNC_B(name##_async, barrier)   \
    216  1.1  mrg   DISPATCH_INTERCEPT_SYNC_F(name##_sync_f, barrier)   \
    217  1.1  mrg   DISPATCH_INTERCEPT_SYNC_B(name##_sync, barrier)
    218  1.1  mrg 
    219  1.1  mrg // We wrap dispatch_async, dispatch_sync and friends where we allocate a new
    220  1.1  mrg // context, which is used to synchronize (we release the context before
    221  1.1  mrg // submitting, and the callback acquires it before executing the original
    222  1.1  mrg // callback).
    223  1.1  mrg DISPATCH_INTERCEPT(dispatch, false)
    224  1.1  mrg DISPATCH_INTERCEPT(dispatch_barrier, true)
    225  1.1  mrg 
    226  1.3  mrg // dispatch_async_and_wait() and friends were introduced in macOS 10.14.
    227  1.3  mrg // Linking of these interceptors fails when using an older SDK.
    228  1.4  mrg #if !SANITIZER_APPLE || defined(__MAC_10_14)
    229  1.3  mrg // macOS 10.14 is greater than our minimal deployment target.  To ensure we
    230  1.3  mrg // generate a weak reference so the TSan dylib continues to work on older
    231  1.3  mrg // systems, we need to forward declare the intercepted functions as "weak
    232  1.3  mrg // imports".   Note that this file is multi-platform, so we cannot include the
    233  1.3  mrg // actual header file (#include <dispatch/dispatch.h>).
    234  1.3  mrg SANITIZER_WEAK_IMPORT void dispatch_async_and_wait(
    235  1.3  mrg     dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);
    236  1.3  mrg SANITIZER_WEAK_IMPORT void dispatch_async_and_wait_f(
    237  1.3  mrg     dispatch_queue_t queue, void *context, dispatch_function_t work);
    238  1.3  mrg SANITIZER_WEAK_IMPORT void dispatch_barrier_async_and_wait(
    239  1.3  mrg     dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block);
    240  1.3  mrg SANITIZER_WEAK_IMPORT void dispatch_barrier_async_and_wait_f(
    241  1.3  mrg     dispatch_queue_t queue, void *context, dispatch_function_t work);
    242  1.3  mrg 
    243  1.3  mrg DISPATCH_INTERCEPT_SYNC_F(dispatch_async_and_wait_f, false)
    244  1.3  mrg DISPATCH_INTERCEPT_SYNC_B(dispatch_async_and_wait, false)
    245  1.3  mrg DISPATCH_INTERCEPT_SYNC_F(dispatch_barrier_async_and_wait_f, true)
    246  1.3  mrg DISPATCH_INTERCEPT_SYNC_B(dispatch_barrier_async_and_wait, true)
    247  1.3  mrg #endif
    248  1.3  mrg 
    249  1.3  mrg 
    250  1.1  mrg DECLARE_REAL(void, dispatch_after_f, dispatch_time_t when,
    251  1.1  mrg              dispatch_queue_t queue, void *context, dispatch_function_t work)
    252  1.1  mrg 
    253  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_after, dispatch_time_t when,
    254  1.1  mrg                  dispatch_queue_t queue, dispatch_block_t block) {
    255  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_after, when, queue, block);
    256  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
    257  1.1  mrg   dispatch_block_t heap_block = Block_copy(block);
    258  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
    259  1.1  mrg   block_context_t *new_context =
    260  1.1  mrg       AllocContext(thr, pc, queue, heap_block, &invoke_and_release_block);
    261  1.1  mrg   Release(thr, pc, (uptr)new_context);
    262  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
    263  1.1  mrg   REAL(dispatch_after_f)(when, queue, new_context, dispatch_callback_wrap);
    264  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
    265  1.1  mrg }
    266  1.1  mrg 
    267  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
    268  1.1  mrg                  dispatch_queue_t queue, void *context,
    269  1.1  mrg                  dispatch_function_t work) {
    270  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_after_f, when, queue, context, work);
    271  1.1  mrg   WRAP(dispatch_after)(when, queue, ^(void) {
    272  1.1  mrg     work(context);
    273  1.1  mrg   });
    274  1.1  mrg }
    275  1.1  mrg 
    276  1.1  mrg // GCD's dispatch_once implementation has a fast path that contains a racy read
    277  1.1  mrg // and it's inlined into user's code. Furthermore, this fast path doesn't
    278  1.1  mrg // establish a proper happens-before relations between the initialization and
    279  1.1  mrg // code following the call to dispatch_once. We could deal with this in
    280  1.1  mrg // instrumented code, but there's not much we can do about it in system
    281  1.1  mrg // libraries. Let's disable the fast path (by never storing the value ~0 to
    282  1.1  mrg // predicate), so the interceptor is always called, and let's add proper release
    283  1.1  mrg // and acquire semantics. Since TSan does not see its own atomic stores, the
    284  1.1  mrg // race on predicate won't be reported - the only accesses to it that TSan sees
    285  1.1  mrg // are the loads on the fast path. Loads don't race. Secondly, dispatch_once is
    286  1.1  mrg // both a macro and a real function, we want to intercept the function, so we
    287  1.1  mrg // need to undefine the macro.
    288  1.1  mrg #undef dispatch_once
    289  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_once, dispatch_once_t *predicate,
    290  1.1  mrg                  DISPATCH_NOESCAPE dispatch_block_t block) {
    291  1.1  mrg   SCOPED_INTERCEPTOR_RAW(dispatch_once, predicate, block);
    292  1.1  mrg   atomic_uint32_t *a = reinterpret_cast<atomic_uint32_t *>(predicate);
    293  1.1  mrg   u32 v = atomic_load(a, memory_order_acquire);
    294  1.1  mrg   if (v == 0 &&
    295  1.1  mrg       atomic_compare_exchange_strong(a, &v, 1, memory_order_relaxed)) {
    296  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
    297  1.1  mrg     block();
    298  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
    299  1.1  mrg     Release(thr, pc, (uptr)a);
    300  1.1  mrg     atomic_store(a, 2, memory_order_release);
    301  1.1  mrg   } else {
    302  1.1  mrg     while (v != 2) {
    303  1.1  mrg       internal_sched_yield();
    304  1.1  mrg       v = atomic_load(a, memory_order_acquire);
    305  1.1  mrg     }
    306  1.1  mrg     Acquire(thr, pc, (uptr)a);
    307  1.1  mrg   }
    308  1.1  mrg }
    309  1.1  mrg 
    310  1.1  mrg #undef dispatch_once_f
    311  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_once_f, dispatch_once_t *predicate,
    312  1.1  mrg                  void *context, dispatch_function_t function) {
    313  1.1  mrg   SCOPED_INTERCEPTOR_RAW(dispatch_once_f, predicate, context, function);
    314  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
    315  1.1  mrg   WRAP(dispatch_once)(predicate, ^(void) {
    316  1.1  mrg     function(context);
    317  1.1  mrg   });
    318  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
    319  1.1  mrg }
    320  1.1  mrg 
    321  1.1  mrg TSAN_INTERCEPTOR(long_t, dispatch_semaphore_signal,
    322  1.1  mrg                  dispatch_semaphore_t dsema) {
    323  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_semaphore_signal, dsema);
    324  1.1  mrg   Release(thr, pc, (uptr)dsema);
    325  1.1  mrg   return REAL(dispatch_semaphore_signal)(dsema);
    326  1.1  mrg }
    327  1.1  mrg 
    328  1.1  mrg TSAN_INTERCEPTOR(long_t, dispatch_semaphore_wait, dispatch_semaphore_t dsema,
    329  1.1  mrg                  dispatch_time_t timeout) {
    330  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_semaphore_wait, dsema, timeout);
    331  1.1  mrg   long_t result = REAL(dispatch_semaphore_wait)(dsema, timeout);
    332  1.1  mrg   if (result == 0) Acquire(thr, pc, (uptr)dsema);
    333  1.1  mrg   return result;
    334  1.1  mrg }
    335  1.1  mrg 
    336  1.1  mrg TSAN_INTERCEPTOR(long_t, dispatch_group_wait, dispatch_group_t group,
    337  1.1  mrg                  dispatch_time_t timeout) {
    338  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_group_wait, group, timeout);
    339  1.1  mrg   long_t result = REAL(dispatch_group_wait)(group, timeout);
    340  1.1  mrg   if (result == 0) Acquire(thr, pc, (uptr)group);
    341  1.1  mrg   return result;
    342  1.1  mrg }
    343  1.1  mrg 
    344  1.1  mrg // Used, but not intercepted.
    345  1.1  mrg extern "C" void dispatch_group_enter(dispatch_group_t group);
    346  1.1  mrg 
    347  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_group_leave, dispatch_group_t group) {
    348  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_group_leave, group);
    349  1.1  mrg   // Acquired in the group notification callback in dispatch_group_notify[_f].
    350  1.1  mrg   Release(thr, pc, (uptr)group);
    351  1.1  mrg   REAL(dispatch_group_leave)(group);
    352  1.1  mrg }
    353  1.1  mrg 
    354  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_group_async, dispatch_group_t group,
    355  1.1  mrg                  dispatch_queue_t queue, dispatch_block_t block) {
    356  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_group_async, group, queue, block);
    357  1.1  mrg   dispatch_retain(group);
    358  1.1  mrg   dispatch_group_enter(group);
    359  1.1  mrg   __block dispatch_block_t block_copy = (dispatch_block_t)Block_copy(block);
    360  1.1  mrg   WRAP(dispatch_async)(queue, ^(void) {
    361  1.1  mrg     block_copy();
    362  1.1  mrg     Block_release(block_copy);
    363  1.1  mrg     WRAP(dispatch_group_leave)(group);
    364  1.1  mrg     dispatch_release(group);
    365  1.1  mrg   });
    366  1.1  mrg }
    367  1.1  mrg 
    368  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
    369  1.1  mrg                  dispatch_queue_t queue, void *context,
    370  1.1  mrg                  dispatch_function_t work) {
    371  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_group_async_f, group, queue, context, work);
    372  1.1  mrg   dispatch_retain(group);
    373  1.1  mrg   dispatch_group_enter(group);
    374  1.1  mrg   WRAP(dispatch_async)(queue, ^(void) {
    375  1.1  mrg     work(context);
    376  1.1  mrg     WRAP(dispatch_group_leave)(group);
    377  1.1  mrg     dispatch_release(group);
    378  1.1  mrg   });
    379  1.1  mrg }
    380  1.1  mrg 
    381  1.1  mrg DECLARE_REAL(void, dispatch_group_notify_f, dispatch_group_t group,
    382  1.1  mrg              dispatch_queue_t q, void *context, dispatch_function_t work)
    383  1.1  mrg 
    384  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_group_notify, dispatch_group_t group,
    385  1.1  mrg                  dispatch_queue_t q, dispatch_block_t block) {
    386  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_group_notify, group, q, block);
    387  1.1  mrg 
    388  1.1  mrg   // To make sure the group is still available in the callback (otherwise
    389  1.1  mrg   // it can be already destroyed).  Will be released in the callback.
    390  1.1  mrg   dispatch_retain(group);
    391  1.1  mrg 
    392  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
    393  1.1  mrg   dispatch_block_t heap_block = Block_copy(^(void) {
    394  1.1  mrg     {
    395  1.1  mrg       SCOPED_INTERCEPTOR_RAW(dispatch_read_callback);
    396  1.1  mrg       // Released when leaving the group (dispatch_group_leave).
    397  1.1  mrg       Acquire(thr, pc, (uptr)group);
    398  1.1  mrg     }
    399  1.1  mrg     dispatch_release(group);
    400  1.1  mrg     block();
    401  1.1  mrg   });
    402  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
    403  1.1  mrg   block_context_t *new_context =
    404  1.1  mrg       AllocContext(thr, pc, q, heap_block, &invoke_and_release_block);
    405  1.1  mrg   new_context->is_barrier_block = true;
    406  1.1  mrg   Release(thr, pc, (uptr)new_context);
    407  1.1  mrg   REAL(dispatch_group_notify_f)(group, q, new_context, dispatch_callback_wrap);
    408  1.1  mrg }
    409  1.1  mrg 
    410  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_group_notify_f, dispatch_group_t group,
    411  1.1  mrg                  dispatch_queue_t q, void *context, dispatch_function_t work) {
    412  1.1  mrg   WRAP(dispatch_group_notify)(group, q, ^(void) { work(context); });
    413  1.1  mrg }
    414  1.1  mrg 
    415  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_source_set_event_handler,
    416  1.1  mrg                  dispatch_source_t source, dispatch_block_t handler) {
    417  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_event_handler, source, handler);
    418  1.1  mrg   if (handler == nullptr)
    419  1.1  mrg     return REAL(dispatch_source_set_event_handler)(source, nullptr);
    420  1.1  mrg   dispatch_queue_t q = GetTargetQueueFromSource(source);
    421  1.1  mrg   __block block_context_t new_context = {
    422  1.1  mrg       q, handler, &invoke_block, false, false, false, 0 };
    423  1.1  mrg   dispatch_block_t new_handler = Block_copy(^(void) {
    424  1.1  mrg     new_context.orig_context = handler;  // To explicitly capture "handler".
    425  1.1  mrg     dispatch_callback_wrap(&new_context);
    426  1.1  mrg   });
    427  1.1  mrg   uptr submit_sync = (uptr)&new_context;
    428  1.1  mrg   Release(thr, pc, submit_sync);
    429  1.1  mrg   REAL(dispatch_source_set_event_handler)(source, new_handler);
    430  1.1  mrg   Block_release(new_handler);
    431  1.1  mrg }
    432  1.1  mrg 
    433  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_source_set_event_handler_f,
    434  1.1  mrg                  dispatch_source_t source, dispatch_function_t handler) {
    435  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_event_handler_f, source, handler);
    436  1.1  mrg   if (handler == nullptr)
    437  1.1  mrg     return REAL(dispatch_source_set_event_handler)(source, nullptr);
    438  1.1  mrg   dispatch_block_t block = ^(void) {
    439  1.1  mrg     handler(dispatch_get_context(source));
    440  1.1  mrg   };
    441  1.1  mrg   WRAP(dispatch_source_set_event_handler)(source, block);
    442  1.1  mrg }
    443  1.1  mrg 
    444  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_source_set_cancel_handler,
    445  1.1  mrg                  dispatch_source_t source, dispatch_block_t handler) {
    446  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_cancel_handler, source, handler);
    447  1.1  mrg   if (handler == nullptr)
    448  1.1  mrg     return REAL(dispatch_source_set_cancel_handler)(source, nullptr);
    449  1.1  mrg   dispatch_queue_t q = GetTargetQueueFromSource(source);
    450  1.1  mrg   __block block_context_t new_context = {
    451  1.1  mrg       q, handler, &invoke_block, false, false, false, 0};
    452  1.1  mrg   dispatch_block_t new_handler = Block_copy(^(void) {
    453  1.1  mrg     new_context.orig_context = handler;  // To explicitly capture "handler".
    454  1.1  mrg     dispatch_callback_wrap(&new_context);
    455  1.1  mrg   });
    456  1.1  mrg   uptr submit_sync = (uptr)&new_context;
    457  1.1  mrg   Release(thr, pc, submit_sync);
    458  1.1  mrg   REAL(dispatch_source_set_cancel_handler)(source, new_handler);
    459  1.1  mrg   Block_release(new_handler);
    460  1.1  mrg }
    461  1.1  mrg 
    462  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_source_set_cancel_handler_f,
    463  1.1  mrg                  dispatch_source_t source, dispatch_function_t handler) {
    464  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_cancel_handler_f, source,
    465  1.1  mrg                           handler);
    466  1.1  mrg   if (handler == nullptr)
    467  1.1  mrg     return REAL(dispatch_source_set_cancel_handler)(source, nullptr);
    468  1.1  mrg   dispatch_block_t block = ^(void) {
    469  1.1  mrg     handler(dispatch_get_context(source));
    470  1.1  mrg   };
    471  1.1  mrg   WRAP(dispatch_source_set_cancel_handler)(source, block);
    472  1.1  mrg }
    473  1.1  mrg 
    474  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler,
    475  1.1  mrg                  dispatch_source_t source, dispatch_block_t handler) {
    476  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_registration_handler, source,
    477  1.1  mrg                           handler);
    478  1.1  mrg   if (handler == nullptr)
    479  1.1  mrg     return REAL(dispatch_source_set_registration_handler)(source, nullptr);
    480  1.1  mrg   dispatch_queue_t q = GetTargetQueueFromSource(source);
    481  1.1  mrg   __block block_context_t new_context = {
    482  1.1  mrg       q, handler, &invoke_block, false, false, false, 0};
    483  1.1  mrg   dispatch_block_t new_handler = Block_copy(^(void) {
    484  1.1  mrg     new_context.orig_context = handler;  // To explicitly capture "handler".
    485  1.1  mrg     dispatch_callback_wrap(&new_context);
    486  1.1  mrg   });
    487  1.1  mrg   uptr submit_sync = (uptr)&new_context;
    488  1.1  mrg   Release(thr, pc, submit_sync);
    489  1.1  mrg   REAL(dispatch_source_set_registration_handler)(source, new_handler);
    490  1.1  mrg   Block_release(new_handler);
    491  1.1  mrg }
    492  1.1  mrg 
    493  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler_f,
    494  1.1  mrg                  dispatch_source_t source, dispatch_function_t handler) {
    495  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_registration_handler_f, source,
    496  1.1  mrg                           handler);
    497  1.1  mrg   if (handler == nullptr)
    498  1.1  mrg     return REAL(dispatch_source_set_registration_handler)(source, nullptr);
    499  1.1  mrg   dispatch_block_t block = ^(void) {
    500  1.1  mrg     handler(dispatch_get_context(source));
    501  1.1  mrg   };
    502  1.1  mrg   WRAP(dispatch_source_set_registration_handler)(source, block);
    503  1.1  mrg }
    504  1.1  mrg 
    505  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_apply, size_t iterations,
    506  1.1  mrg                  dispatch_queue_t queue,
    507  1.1  mrg                  DISPATCH_NOESCAPE void (^block)(size_t)) {
    508  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_apply, iterations, queue, block);
    509  1.1  mrg 
    510  1.1  mrg   u8 sync1, sync2;
    511  1.1  mrg   uptr parent_to_child_sync = (uptr)&sync1;
    512  1.1  mrg   uptr child_to_parent_sync = (uptr)&sync2;
    513  1.1  mrg 
    514  1.1  mrg   Release(thr, pc, parent_to_child_sync);
    515  1.1  mrg   void (^new_block)(size_t) = ^(size_t iteration) {
    516  1.1  mrg     SCOPED_INTERCEPTOR_RAW(dispatch_apply);
    517  1.1  mrg     Acquire(thr, pc, parent_to_child_sync);
    518  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
    519  1.1  mrg     block(iteration);
    520  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
    521  1.1  mrg     Release(thr, pc, child_to_parent_sync);
    522  1.1  mrg   };
    523  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
    524  1.1  mrg   REAL(dispatch_apply)(iterations, queue, new_block);
    525  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
    526  1.1  mrg   Acquire(thr, pc, child_to_parent_sync);
    527  1.1  mrg }
    528  1.1  mrg 
    529  1.1  mrg static void invoke_block_iteration(void *param, size_t iteration) {
    530  1.1  mrg   auto block = (void (^)(size_t)) param;
    531  1.1  mrg   block(iteration);
    532  1.1  mrg }
    533  1.1  mrg 
    534  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_apply_f, size_t iterations,
    535  1.1  mrg                  dispatch_queue_t queue, void *context,
    536  1.1  mrg                  void (*work)(void *, size_t)) {
    537  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_apply_f, iterations, queue, context, work);
    538  1.1  mrg 
    539  1.1  mrg   // Unfortunately, we cannot delegate to dispatch_apply, since libdispatch
    540  1.1  mrg   // implements dispatch_apply in terms of dispatch_apply_f.
    541  1.1  mrg   u8 sync1, sync2;
    542  1.1  mrg   uptr parent_to_child_sync = (uptr)&sync1;
    543  1.1  mrg   uptr child_to_parent_sync = (uptr)&sync2;
    544  1.1  mrg 
    545  1.1  mrg   Release(thr, pc, parent_to_child_sync);
    546  1.1  mrg   void (^new_block)(size_t) = ^(size_t iteration) {
    547  1.1  mrg     SCOPED_INTERCEPTOR_RAW(dispatch_apply_f);
    548  1.1  mrg     Acquire(thr, pc, parent_to_child_sync);
    549  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
    550  1.1  mrg     work(context, iteration);
    551  1.1  mrg     SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
    552  1.1  mrg     Release(thr, pc, child_to_parent_sync);
    553  1.1  mrg   };
    554  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
    555  1.1  mrg   REAL(dispatch_apply_f)(iterations, queue, new_block, invoke_block_iteration);
    556  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
    557  1.1  mrg   Acquire(thr, pc, child_to_parent_sync);
    558  1.1  mrg }
    559  1.1  mrg 
    560  1.1  mrg DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
    561  1.4  mrg DECLARE_REAL_AND_INTERCEPTOR(int, munmap, void *addr, SIZE_T sz)
    562  1.1  mrg 
    563  1.1  mrg TSAN_INTERCEPTOR(dispatch_data_t, dispatch_data_create, const void *buffer,
    564  1.1  mrg                  size_t size, dispatch_queue_t q, dispatch_block_t destructor) {
    565  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_data_create, buffer, size, q, destructor);
    566  1.1  mrg   if ((q == nullptr) || (destructor == DISPATCH_DATA_DESTRUCTOR_DEFAULT))
    567  1.1  mrg     return REAL(dispatch_data_create)(buffer, size, q, destructor);
    568  1.1  mrg 
    569  1.1  mrg   if (destructor == DISPATCH_DATA_DESTRUCTOR_FREE)
    570  1.1  mrg     destructor = ^(void) { WRAP(free)((void *)(uintptr_t)buffer); };
    571  1.1  mrg   else if (destructor == DISPATCH_DATA_DESTRUCTOR_MUNMAP)
    572  1.1  mrg     destructor = ^(void) { WRAP(munmap)((void *)(uintptr_t)buffer, size); };
    573  1.1  mrg 
    574  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
    575  1.1  mrg   dispatch_block_t heap_block = Block_copy(destructor);
    576  1.1  mrg   SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
    577  1.1  mrg   block_context_t *new_context =
    578  1.1  mrg       AllocContext(thr, pc, q, heap_block, &invoke_and_release_block);
    579  1.1  mrg   uptr submit_sync = (uptr)new_context;
    580  1.1  mrg   Release(thr, pc, submit_sync);
    581  1.1  mrg   return REAL(dispatch_data_create)(buffer, size, q, ^(void) {
    582  1.1  mrg     dispatch_callback_wrap(new_context);
    583  1.1  mrg   });
    584  1.1  mrg }
    585  1.1  mrg 
    586  1.1  mrg typedef void (^fd_handler_t)(dispatch_data_t data, int error);
    587  1.1  mrg typedef void (^cleanup_handler_t)(int error);
    588  1.1  mrg 
    589  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_read, dispatch_fd_t fd, size_t length,
    590  1.1  mrg                  dispatch_queue_t q, fd_handler_t h) {
    591  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_read, fd, length, q, h);
    592  1.1  mrg   __block block_context_t new_context = {
    593  1.1  mrg       q, nullptr, &invoke_block, false, false, false, 0};
    594  1.1  mrg   fd_handler_t new_h = Block_copy(^(dispatch_data_t data, int error) {
    595  1.1  mrg     new_context.orig_context = ^(void) {
    596  1.1  mrg       h(data, error);
    597  1.1  mrg     };
    598  1.1  mrg     dispatch_callback_wrap(&new_context);
    599  1.1  mrg   });
    600  1.1  mrg   uptr submit_sync = (uptr)&new_context;
    601  1.1  mrg   Release(thr, pc, submit_sync);
    602  1.1  mrg   REAL(dispatch_read)(fd, length, q, new_h);
    603  1.1  mrg   Block_release(new_h);
    604  1.1  mrg }
    605  1.1  mrg 
    606  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_write, dispatch_fd_t fd, dispatch_data_t data,
    607  1.1  mrg                  dispatch_queue_t q, fd_handler_t h) {
    608  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_write, fd, data, q, h);
    609  1.1  mrg   __block block_context_t new_context = {
    610  1.1  mrg       q, nullptr, &invoke_block, false, false, false, 0};
    611  1.1  mrg   fd_handler_t new_h = Block_copy(^(dispatch_data_t data, int error) {
    612  1.1  mrg     new_context.orig_context = ^(void) {
    613  1.1  mrg       h(data, error);
    614  1.1  mrg     };
    615  1.1  mrg     dispatch_callback_wrap(&new_context);
    616  1.1  mrg   });
    617  1.1  mrg   uptr submit_sync = (uptr)&new_context;
    618  1.1  mrg   Release(thr, pc, submit_sync);
    619  1.1  mrg   REAL(dispatch_write)(fd, data, q, new_h);
    620  1.1  mrg   Block_release(new_h);
    621  1.1  mrg }
    622  1.1  mrg 
    623  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_io_read, dispatch_io_t channel, off_t offset,
    624  1.1  mrg                  size_t length, dispatch_queue_t q, dispatch_io_handler_t h) {
    625  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_io_read, channel, offset, length, q, h);
    626  1.1  mrg   __block block_context_t new_context = {
    627  1.1  mrg       q, nullptr, &invoke_block, false, false, false, 0};
    628  1.1  mrg   dispatch_io_handler_t new_h =
    629  1.1  mrg       Block_copy(^(bool done, dispatch_data_t data, int error) {
    630  1.1  mrg         new_context.orig_context = ^(void) {
    631  1.1  mrg           h(done, data, error);
    632  1.1  mrg         };
    633  1.1  mrg         dispatch_callback_wrap(&new_context);
    634  1.1  mrg       });
    635  1.1  mrg   uptr submit_sync = (uptr)&new_context;
    636  1.1  mrg   Release(thr, pc, submit_sync);
    637  1.1  mrg   REAL(dispatch_io_read)(channel, offset, length, q, new_h);
    638  1.1  mrg   Block_release(new_h);
    639  1.1  mrg }
    640  1.1  mrg 
    641  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_io_write, dispatch_io_t channel, off_t offset,
    642  1.1  mrg                  dispatch_data_t data, dispatch_queue_t q,
    643  1.1  mrg                  dispatch_io_handler_t h) {
    644  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_io_write, channel, offset, data, q, h);
    645  1.1  mrg   __block block_context_t new_context = {
    646  1.1  mrg       q, nullptr, &invoke_block, false, false, false, 0};
    647  1.1  mrg   dispatch_io_handler_t new_h =
    648  1.1  mrg       Block_copy(^(bool done, dispatch_data_t data, int error) {
    649  1.1  mrg         new_context.orig_context = ^(void) {
    650  1.1  mrg           h(done, data, error);
    651  1.1  mrg         };
    652  1.1  mrg         dispatch_callback_wrap(&new_context);
    653  1.1  mrg       });
    654  1.1  mrg   uptr submit_sync = (uptr)&new_context;
    655  1.1  mrg   Release(thr, pc, submit_sync);
    656  1.1  mrg   REAL(dispatch_io_write)(channel, offset, data, q, new_h);
    657  1.1  mrg   Block_release(new_h);
    658  1.1  mrg }
    659  1.1  mrg 
    660  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_io_barrier, dispatch_io_t channel,
    661  1.1  mrg                  dispatch_block_t barrier) {
    662  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_io_barrier, channel, barrier);
    663  1.1  mrg   __block block_context_t new_context = {
    664  1.1  mrg       nullptr, nullptr, &invoke_block, false, false, false, 0};
    665  1.1  mrg   new_context.non_queue_sync_object = (uptr)channel;
    666  1.1  mrg   new_context.is_barrier_block = true;
    667  1.1  mrg   dispatch_block_t new_block = Block_copy(^(void) {
    668  1.1  mrg     new_context.orig_context = ^(void) {
    669  1.1  mrg       barrier();
    670  1.1  mrg     };
    671  1.1  mrg     dispatch_callback_wrap(&new_context);
    672  1.1  mrg   });
    673  1.1  mrg   uptr submit_sync = (uptr)&new_context;
    674  1.1  mrg   Release(thr, pc, submit_sync);
    675  1.1  mrg   REAL(dispatch_io_barrier)(channel, new_block);
    676  1.1  mrg   Block_release(new_block);
    677  1.1  mrg }
    678  1.1  mrg 
    679  1.1  mrg TSAN_INTERCEPTOR(dispatch_io_t, dispatch_io_create, dispatch_io_type_t type,
    680  1.1  mrg                  dispatch_fd_t fd, dispatch_queue_t q, cleanup_handler_t h) {
    681  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_io_create, type, fd, q, h);
    682  1.1  mrg   __block dispatch_io_t new_channel = nullptr;
    683  1.1  mrg   __block block_context_t new_context = {
    684  1.1  mrg       q, nullptr, &invoke_block, false, false, false, 0};
    685  1.1  mrg   cleanup_handler_t new_h = Block_copy(^(int error) {
    686  1.1  mrg     {
    687  1.1  mrg       SCOPED_INTERCEPTOR_RAW(dispatch_io_create_callback);
    688  1.1  mrg       Acquire(thr, pc, (uptr)new_channel);  // Release() in dispatch_io_close.
    689  1.1  mrg     }
    690  1.1  mrg     new_context.orig_context = ^(void) {
    691  1.1  mrg       h(error);
    692  1.1  mrg     };
    693  1.1  mrg     dispatch_callback_wrap(&new_context);
    694  1.1  mrg   });
    695  1.1  mrg   uptr submit_sync = (uptr)&new_context;
    696  1.1  mrg   Release(thr, pc, submit_sync);
    697  1.1  mrg   new_channel = REAL(dispatch_io_create)(type, fd, q, new_h);
    698  1.1  mrg   Block_release(new_h);
    699  1.1  mrg   return new_channel;
    700  1.1  mrg }
    701  1.1  mrg 
    702  1.1  mrg TSAN_INTERCEPTOR(dispatch_io_t, dispatch_io_create_with_path,
    703  1.1  mrg                  dispatch_io_type_t type, const char *path, int oflag,
    704  1.1  mrg                  mode_t mode, dispatch_queue_t q, cleanup_handler_t h) {
    705  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_io_create_with_path, type, path, oflag, mode,
    706  1.1  mrg                           q, h);
    707  1.1  mrg   __block dispatch_io_t new_channel = nullptr;
    708  1.1  mrg   __block block_context_t new_context = {
    709  1.1  mrg       q, nullptr, &invoke_block, false, false, false, 0};
    710  1.1  mrg   cleanup_handler_t new_h = Block_copy(^(int error) {
    711  1.1  mrg     {
    712  1.1  mrg       SCOPED_INTERCEPTOR_RAW(dispatch_io_create_callback);
    713  1.1  mrg       Acquire(thr, pc, (uptr)new_channel);  // Release() in dispatch_io_close.
    714  1.1  mrg     }
    715  1.1  mrg     new_context.orig_context = ^(void) {
    716  1.1  mrg       h(error);
    717  1.1  mrg     };
    718  1.1  mrg     dispatch_callback_wrap(&new_context);
    719  1.1  mrg   });
    720  1.1  mrg   uptr submit_sync = (uptr)&new_context;
    721  1.1  mrg   Release(thr, pc, submit_sync);
    722  1.1  mrg   new_channel =
    723  1.1  mrg       REAL(dispatch_io_create_with_path)(type, path, oflag, mode, q, new_h);
    724  1.1  mrg   Block_release(new_h);
    725  1.1  mrg   return new_channel;
    726  1.1  mrg }
    727  1.1  mrg 
    728  1.1  mrg TSAN_INTERCEPTOR(dispatch_io_t, dispatch_io_create_with_io,
    729  1.1  mrg                  dispatch_io_type_t type, dispatch_io_t io, dispatch_queue_t q,
    730  1.1  mrg                  cleanup_handler_t h) {
    731  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_io_create_with_io, type, io, q, h);
    732  1.1  mrg   __block dispatch_io_t new_channel = nullptr;
    733  1.1  mrg   __block block_context_t new_context = {
    734  1.1  mrg       q, nullptr, &invoke_block, false, false, false, 0};
    735  1.1  mrg   cleanup_handler_t new_h = Block_copy(^(int error) {
    736  1.1  mrg     {
    737  1.1  mrg       SCOPED_INTERCEPTOR_RAW(dispatch_io_create_callback);
    738  1.1  mrg       Acquire(thr, pc, (uptr)new_channel);  // Release() in dispatch_io_close.
    739  1.1  mrg     }
    740  1.1  mrg     new_context.orig_context = ^(void) {
    741  1.1  mrg       h(error);
    742  1.1  mrg     };
    743  1.1  mrg     dispatch_callback_wrap(&new_context);
    744  1.1  mrg   });
    745  1.1  mrg   uptr submit_sync = (uptr)&new_context;
    746  1.1  mrg   Release(thr, pc, submit_sync);
    747  1.1  mrg   new_channel = REAL(dispatch_io_create_with_io)(type, io, q, new_h);
    748  1.1  mrg   Block_release(new_h);
    749  1.1  mrg   return new_channel;
    750  1.1  mrg }
    751  1.1  mrg 
    752  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_io_close, dispatch_io_t channel,
    753  1.1  mrg                  dispatch_io_close_flags_t flags) {
    754  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_io_close, channel, flags);
    755  1.1  mrg   Release(thr, pc, (uptr)channel);  // Acquire() in dispatch_io_create[_*].
    756  1.1  mrg   return REAL(dispatch_io_close)(channel, flags);
    757  1.1  mrg }
    758  1.1  mrg 
    759  1.1  mrg // Resuming a suspended queue needs to synchronize with all subsequent
    760  1.1  mrg // executions of blocks in that queue.
    761  1.1  mrg TSAN_INTERCEPTOR(void, dispatch_resume, dispatch_object_t o) {
    762  1.1  mrg   SCOPED_TSAN_INTERCEPTOR(dispatch_resume, o);
    763  1.1  mrg   Release(thr, pc, (uptr)o);  // Synchronizes with the Acquire() on serial_sync
    764  1.1  mrg                               // in dispatch_sync_pre_execute
    765  1.1  mrg   return REAL(dispatch_resume)(o);
    766  1.1  mrg }
    767  1.1  mrg 
    768  1.1  mrg void InitializeLibdispatchInterceptors() {
    769  1.1  mrg   INTERCEPT_FUNCTION(dispatch_async);
    770  1.1  mrg   INTERCEPT_FUNCTION(dispatch_async_f);
    771  1.1  mrg   INTERCEPT_FUNCTION(dispatch_sync);
    772  1.1  mrg   INTERCEPT_FUNCTION(dispatch_sync_f);
    773  1.1  mrg   INTERCEPT_FUNCTION(dispatch_barrier_async);
    774  1.1  mrg   INTERCEPT_FUNCTION(dispatch_barrier_async_f);
    775  1.1  mrg   INTERCEPT_FUNCTION(dispatch_barrier_sync);
    776  1.1  mrg   INTERCEPT_FUNCTION(dispatch_barrier_sync_f);
    777  1.3  mrg   INTERCEPT_FUNCTION(dispatch_async_and_wait);
    778  1.3  mrg   INTERCEPT_FUNCTION(dispatch_async_and_wait_f);
    779  1.3  mrg   INTERCEPT_FUNCTION(dispatch_barrier_async_and_wait);
    780  1.3  mrg   INTERCEPT_FUNCTION(dispatch_barrier_async_and_wait_f);
    781  1.1  mrg   INTERCEPT_FUNCTION(dispatch_after);
    782  1.1  mrg   INTERCEPT_FUNCTION(dispatch_after_f);
    783  1.1  mrg   INTERCEPT_FUNCTION(dispatch_once);
    784  1.1  mrg   INTERCEPT_FUNCTION(dispatch_once_f);
    785  1.1  mrg   INTERCEPT_FUNCTION(dispatch_semaphore_signal);
    786  1.1  mrg   INTERCEPT_FUNCTION(dispatch_semaphore_wait);
    787  1.1  mrg   INTERCEPT_FUNCTION(dispatch_group_wait);
    788  1.1  mrg   INTERCEPT_FUNCTION(dispatch_group_leave);
    789  1.1  mrg   INTERCEPT_FUNCTION(dispatch_group_async);
    790  1.1  mrg   INTERCEPT_FUNCTION(dispatch_group_async_f);
    791  1.1  mrg   INTERCEPT_FUNCTION(dispatch_group_notify);
    792  1.1  mrg   INTERCEPT_FUNCTION(dispatch_group_notify_f);
    793  1.1  mrg   INTERCEPT_FUNCTION(dispatch_source_set_event_handler);
    794  1.1  mrg   INTERCEPT_FUNCTION(dispatch_source_set_event_handler_f);
    795  1.1  mrg   INTERCEPT_FUNCTION(dispatch_source_set_cancel_handler);
    796  1.1  mrg   INTERCEPT_FUNCTION(dispatch_source_set_cancel_handler_f);
    797  1.1  mrg   INTERCEPT_FUNCTION(dispatch_source_set_registration_handler);
    798  1.1  mrg   INTERCEPT_FUNCTION(dispatch_source_set_registration_handler_f);
    799  1.1  mrg   INTERCEPT_FUNCTION(dispatch_apply);
    800  1.1  mrg   INTERCEPT_FUNCTION(dispatch_apply_f);
    801  1.1  mrg   INTERCEPT_FUNCTION(dispatch_data_create);
    802  1.1  mrg   INTERCEPT_FUNCTION(dispatch_read);
    803  1.1  mrg   INTERCEPT_FUNCTION(dispatch_write);
    804  1.1  mrg   INTERCEPT_FUNCTION(dispatch_io_read);
    805  1.1  mrg   INTERCEPT_FUNCTION(dispatch_io_write);
    806  1.1  mrg   INTERCEPT_FUNCTION(dispatch_io_barrier);
    807  1.1  mrg   INTERCEPT_FUNCTION(dispatch_io_create);
    808  1.1  mrg   INTERCEPT_FUNCTION(dispatch_io_create_with_path);
    809  1.1  mrg   INTERCEPT_FUNCTION(dispatch_io_create_with_io);
    810  1.1  mrg   INTERCEPT_FUNCTION(dispatch_io_close);
    811  1.1  mrg   INTERCEPT_FUNCTION(dispatch_resume);
    812  1.1  mrg }
    813  1.1  mrg 
    814  1.1  mrg }  // namespace __tsan
    815