mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-01-30 13:47:32 +00:00
[tsan] Add dispatch_group API interceptors and synchronization
This patch adds release and acquire semantics for dispatch groups, plus a test case. Differential Revision: http://reviews.llvm.org/D15048 llvm-svn: 255020
This commit is contained in:
parent
1956244e5a
commit
25dba9b781
@ -33,6 +33,7 @@ typedef struct {
|
||||
dispatch_queue_t queue;
|
||||
void *orig_context;
|
||||
dispatch_function_t orig_work;
|
||||
uptr object_to_acquire;
|
||||
} tsan_block_context_t;
|
||||
|
||||
// The offsets of different fields of the dispatch_queue_t structure, exported
|
||||
@ -73,13 +74,14 @@ static tsan_block_context_t *AllocContext(ThreadState *thr, uptr pc,
|
||||
new_context->queue = queue;
|
||||
new_context->orig_context = orig_context;
|
||||
new_context->orig_work = orig_work;
|
||||
new_context->object_to_acquire = (uptr)new_context;
|
||||
return new_context;
|
||||
}
|
||||
|
||||
static void dispatch_callback_wrap_acquire(void *param) {
|
||||
SCOPED_INTERCEPTOR_RAW(dispatch_async_f_callback_wrap);
|
||||
tsan_block_context_t *context = (tsan_block_context_t *)param;
|
||||
Acquire(thr, pc, (uptr)context);
|
||||
Acquire(thr, pc, context->object_to_acquire);
|
||||
// In serial queues, work items can be executed on different threads, we need
|
||||
// to explicitly synchronize on the queue itself.
|
||||
if (IsQueueSerial(context->queue)) Acquire(thr, pc, (uptr)context->queue);
|
||||
@ -183,6 +185,67 @@ TSAN_INTERCEPTOR(long_t, dispatch_semaphore_wait, dispatch_semaphore_t dsema,
|
||||
return result;
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(long_t, dispatch_group_wait, dispatch_group_t group,
|
||||
dispatch_time_t timeout) {
|
||||
SCOPED_TSAN_INTERCEPTOR(dispatch_group_wait, group, timeout);
|
||||
long_t result = REAL(dispatch_group_wait)(group, timeout);
|
||||
if (result == 0) Acquire(thr, pc, (uptr)group);
|
||||
return result;
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(void, dispatch_group_leave, dispatch_group_t group) {
|
||||
SCOPED_TSAN_INTERCEPTOR(dispatch_group_leave, group);
|
||||
Release(thr, pc, (uptr)group);
|
||||
REAL(dispatch_group_leave)(group);
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(void, dispatch_group_async, dispatch_group_t group,
|
||||
dispatch_queue_t queue, dispatch_block_t block) {
|
||||
SCOPED_TSAN_INTERCEPTOR(dispatch_group_async, group, queue, block);
|
||||
dispatch_retain(group);
|
||||
dispatch_group_enter(group);
|
||||
WRAP(dispatch_async)(queue, ^(void) {
|
||||
block();
|
||||
WRAP(dispatch_group_leave)(group);
|
||||
dispatch_release(group);
|
||||
});
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
|
||||
dispatch_queue_t queue, void *context,
|
||||
dispatch_function_t work) {
|
||||
SCOPED_TSAN_INTERCEPTOR(dispatch_group_async_f, group, queue, context, work);
|
||||
dispatch_retain(group);
|
||||
dispatch_group_enter(group);
|
||||
WRAP(dispatch_async)(queue, ^(void) {
|
||||
work(context);
|
||||
WRAP(dispatch_group_leave)(group);
|
||||
dispatch_release(group);
|
||||
});
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(void, dispatch_group_notify, dispatch_group_t group,
|
||||
dispatch_queue_t q, dispatch_block_t block) {
|
||||
SCOPED_TSAN_INTERCEPTOR(dispatch_group_notify, group, q, block);
|
||||
dispatch_block_t heap_block = Block_copy(block);
|
||||
tsan_block_context_t *new_context =
|
||||
AllocContext(thr, pc, q, heap_block, &invoke_and_release_block);
|
||||
new_context->object_to_acquire = (uptr)group;
|
||||
Release(thr, pc, (uptr)group);
|
||||
REAL(dispatch_group_notify_f)(group, q, new_context,
|
||||
dispatch_callback_wrap_acquire);
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(void, dispatch_group_notify_f, dispatch_group_t group,
|
||||
dispatch_queue_t q, void *context, dispatch_function_t work) {
|
||||
SCOPED_TSAN_INTERCEPTOR(dispatch_group_notify_f, group, q, context, work);
|
||||
tsan_block_context_t *new_context = AllocContext(thr, pc, q, context, work);
|
||||
new_context->object_to_acquire = (uptr)group;
|
||||
Release(thr, pc, (uptr)group);
|
||||
REAL(dispatch_group_notify_f)(group, q, new_context,
|
||||
dispatch_callback_wrap_acquire);
|
||||
}
|
||||
|
||||
} // namespace __tsan
|
||||
|
||||
#endif // SANITIZER_MAC
|
||||
|
53
compiler-rt/test/tsan/Darwin/gcd-groups-norace.mm
Normal file
53
compiler-rt/test/tsan/Darwin/gcd-groups-norace.mm
Normal file
@ -0,0 +1,53 @@
|
||||
// RUN: %clang_tsan %s -o %t -framework Foundation
|
||||
// RUN: %run %t 2>&1
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "../test.h"
|
||||
|
||||
long global;
|
||||
|
||||
int main() {
|
||||
NSLog(@"Hello world.");
|
||||
NSLog(@"addr=%p\n", &global);
|
||||
|
||||
dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
|
||||
global = 42;
|
||||
|
||||
dispatch_group_t g = dispatch_group_create();
|
||||
dispatch_group_async(g, q, ^{
|
||||
global = 43;
|
||||
});
|
||||
dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
|
||||
|
||||
global = 44;
|
||||
|
||||
dispatch_group_enter(g);
|
||||
dispatch_async(q, ^{
|
||||
global = 45;
|
||||
dispatch_group_leave(g);
|
||||
});
|
||||
dispatch_group_wait(g, DISPATCH_TIME_FOREVER);
|
||||
|
||||
global = 46;
|
||||
|
||||
dispatch_group_enter(g);
|
||||
dispatch_async(q, ^{
|
||||
global = 47;
|
||||
dispatch_group_leave(g);
|
||||
});
|
||||
dispatch_group_notify(g, q, ^{
|
||||
global = 48;
|
||||
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
CFRunLoopStop(CFRunLoopGetCurrent());
|
||||
});
|
||||
});
|
||||
|
||||
CFRunLoopRun();
|
||||
NSLog(@"Done.");
|
||||
}
|
||||
|
||||
// CHECK: Hello world.
|
||||
// CHECK: Done.
|
||||
// CHECK-NOT: WARNING: ThreadSanitizer
|
Loading…
x
Reference in New Issue
Block a user