Index: compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc =================================================================== --- compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc +++ compiler-rt/trunk/lib/tsan/rtl/tsan_libdispatch_mac.cc @@ -67,6 +67,15 @@ return width == 1; } +static dispatch_queue_t GetTargetQueueFromSource(dispatch_source_t source) { + CHECK_EQ(dispatch_queue_offsets.dqo_target_queue_size, 8); + dispatch_queue_t target_queue = + *(dispatch_queue_t *)(((uptr)source) + + dispatch_queue_offsets.dqo_target_queue); + CHECK_NE(target_queue, 0); + return target_queue; +} + static tsan_block_context_t *AllocContext(ThreadState *thr, uptr pc, dispatch_queue_t queue, void *orig_context, @@ -106,6 +115,11 @@ if (context->free_context_in_callback) user_free(thr, pc, context); } +static void invoke_block(void *param) { + dispatch_block_t block = (dispatch_block_t)param; + block(); +} + static void invoke_and_release_block(void *param) { dispatch_block_t block = (dispatch_block_t)param; block(); @@ -342,15 +356,17 @@ SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_event_handler, source, handler); if (handler == nullptr) return REAL(dispatch_source_set_event_handler)(source, nullptr); - dispatch_block_t new_handler = ^(void) { - { - SCOPED_INTERCEPTOR_RAW(dispatch_source_set_event_handler_callback); - Acquire(thr, pc, (uptr)source); - } - handler(); - }; - Release(thr, pc, (uptr)source); + dispatch_queue_t q = GetTargetQueueFromSource(source); + __block tsan_block_context_t new_context = { + q, handler, &invoke_block, false, false, false }; + dispatch_block_t new_handler = Block_copy(^(void) { + new_context.orig_context = handler; // To explicitly capture "handler". + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); REAL(dispatch_source_set_event_handler)(source, new_handler); + Block_release(new_handler); } TSAN_INTERCEPTOR(void, dispatch_source_set_event_handler_f, @@ -369,15 +385,17 @@ SCOPED_TSAN_INTERCEPTOR(dispatch_source_set_cancel_handler, source, handler); if (handler == nullptr) return REAL(dispatch_source_set_cancel_handler)(source, nullptr); - dispatch_block_t new_handler = ^(void) { - { - SCOPED_INTERCEPTOR_RAW(dispatch_source_set_cancel_handler_callback); - Acquire(thr, pc, (uptr)source); - } - handler(); - }; - Release(thr, pc, (uptr)source); + dispatch_queue_t q = GetTargetQueueFromSource(source); + __block tsan_block_context_t new_context = { + q, handler, &invoke_block, false, false, false }; + dispatch_block_t new_handler = Block_copy(^(void) { + new_context.orig_context = handler; // To explicitly capture "handler". + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); REAL(dispatch_source_set_cancel_handler)(source, new_handler); + Block_release(new_handler); } TSAN_INTERCEPTOR(void, dispatch_source_set_cancel_handler_f, @@ -398,15 +416,17 @@ handler); if (handler == nullptr) return REAL(dispatch_source_set_registration_handler)(source, nullptr); - dispatch_block_t new_handler = ^(void) { - { - SCOPED_INTERCEPTOR_RAW(dispatch_source_set_registration_handler_callback); - Acquire(thr, pc, (uptr)source); - } - handler(); - }; - Release(thr, pc, (uptr)source); + dispatch_queue_t q = GetTargetQueueFromSource(source); + __block tsan_block_context_t new_context = { + q, handler, &invoke_block, false, false, false }; + dispatch_block_t new_handler = Block_copy(^(void) { + new_context.orig_context = handler; // To explicitly capture "handler". + dispatch_callback_wrap(&new_context); + }); + uptr submit_sync = (uptr)&new_context; + Release(thr, pc, submit_sync); REAL(dispatch_source_set_registration_handler)(source, new_handler); + Block_release(new_handler); } TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler_f, Index: compiler-rt/trunk/test/tsan/Darwin/gcd-source-serial.mm =================================================================== --- compiler-rt/trunk/test/tsan/Darwin/gcd-source-serial.mm +++ compiler-rt/trunk/test/tsan/Darwin/gcd-source-serial.mm @@ -0,0 +1,33 @@ +// RUN: %clang_tsan %s -o %t -framework Foundation +// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s + +#import + +long global; + +int main(int argc, const char *argv[]) { + fprintf(stderr, "Hello world.\n"); + + dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL); + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, q); + long long interval_ms = 10; + dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, 0), interval_ms * NSEC_PER_MSEC, 0); + dispatch_source_set_event_handler(timer, ^{ + fprintf(stderr, "timer\n"); + global++; + + if (global > 50) { + dispatch_semaphore_signal(sem); + } + }); + dispatch_resume(timer); + + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); + + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello world. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: Done.