diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_libdispatch.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_libdispatch.cpp --- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_libdispatch.cpp +++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_libdispatch.cpp @@ -219,6 +219,9 @@ DISPATCH_INTERCEPT(dispatch, false) DISPATCH_INTERCEPT(dispatch_barrier, true) +DISPATCH_INTERCEPT_SYNC_F(dispatch_async_and_wait_f, false) +DISPATCH_INTERCEPT_SYNC_B(dispatch_async_and_wait, false) + DECLARE_REAL(void, dispatch_after_f, dispatch_time_t when, dispatch_queue_t queue, void *context, dispatch_function_t work) @@ -746,6 +749,8 @@ INTERCEPT_FUNCTION(dispatch_barrier_async_f); INTERCEPT_FUNCTION(dispatch_barrier_sync); INTERCEPT_FUNCTION(dispatch_barrier_sync_f); + INTERCEPT_FUNCTION(dispatch_async_and_wait); + INTERCEPT_FUNCTION(dispatch_async_and_wait_f); INTERCEPT_FUNCTION(dispatch_after); INTERCEPT_FUNCTION(dispatch_after_f); INTERCEPT_FUNCTION(dispatch_once); diff --git a/compiler-rt/test/tsan/libdispatch/async_and_wait.c b/compiler-rt/test/tsan/libdispatch/async_and_wait.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/tsan/libdispatch/async_and_wait.c @@ -0,0 +1,31 @@ +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s --implicit-check-not='ThreadSanitizer' + +#include "dispatch/dispatch.h" + +#include + +long global; + +int main() { + dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_SERIAL); + dispatch_semaphore_t s = dispatch_semaphore_create(0); + + // Force queue to context switch onto separate thread. + dispatch_async(q, ^{ + dispatch_semaphore_wait(s, DISPATCH_TIME_FOREVER); + }); + dispatch_semaphore_signal(s); + + global++; + dispatch_async_and_wait(q, ^{ + // The queue continues to execute on separate thread. This would cause a + // race if we had used `dispatch_async()` without the `_and_wait` part. + global++; + }); + global++; + + fprintf(stderr, "Done.\n"); +} + +// CHECK: Done.