forked from OSchip/llvm-project
[tsan] Add interceptors for dispatch_apply
Adding an interceptor with two more release+acquire pairs to avoid false positives with dispatch_apply. Differential Revision: http://reviews.llvm.org/D18722 llvm-svn: 265662
This commit is contained in:
parent
e316bb61b3
commit
399af93242
|
@ -389,6 +389,40 @@ TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler_f,
|
|||
WRAP(dispatch_source_set_registration_handler)(source, block);
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(void, dispatch_apply, size_t iterations,
|
||||
dispatch_queue_t queue, void (^block)(size_t)) {
|
||||
SCOPED_TSAN_INTERCEPTOR(dispatch_apply, iterations, queue, block);
|
||||
|
||||
void *parent_to_child_sync = nullptr;
|
||||
uptr parent_to_child_sync_uptr = (uptr)&parent_to_child_sync;
|
||||
void *child_to_parent_sync = nullptr;
|
||||
uptr child_to_parent_sync_uptr = (uptr)&child_to_parent_sync;
|
||||
|
||||
Release(thr, pc, parent_to_child_sync_uptr);
|
||||
void (^new_block)(size_t) = ^(size_t iteration) {
|
||||
SCOPED_INTERCEPTOR_RAW(dispatch_apply);
|
||||
Acquire(thr, pc, parent_to_child_sync_uptr);
|
||||
SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
|
||||
block(iteration);
|
||||
SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
|
||||
Release(thr, pc, child_to_parent_sync_uptr);
|
||||
};
|
||||
SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
|
||||
REAL(dispatch_apply)(iterations, queue, new_block);
|
||||
SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
|
||||
Acquire(thr, pc, child_to_parent_sync_uptr);
|
||||
}
|
||||
|
||||
TSAN_INTERCEPTOR(void, dispatch_apply_f, size_t iterations,
|
||||
dispatch_queue_t queue, void *context,
|
||||
void (*work)(void *, size_t)) {
|
||||
SCOPED_TSAN_INTERCEPTOR(dispatch_apply_f, iterations, queue, context, work);
|
||||
void (^new_block)(size_t) = ^(size_t iteration) {
|
||||
work(context, iteration);
|
||||
};
|
||||
WRAP(dispatch_apply)(iterations, queue, new_block);
|
||||
}
|
||||
|
||||
} // namespace __tsan
|
||||
|
||||
#endif // SANITIZER_MAC
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
// RUN: %clang_tsan %s -o %t -framework Foundation
|
||||
// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 not %run %t 2>&1 | FileCheck %s
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "../test.h"
|
||||
|
||||
long global;
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
barrier_init(&barrier, 2);
|
||||
fprintf(stderr, "start\n");
|
||||
dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
|
||||
dispatch_apply(2, q, ^(size_t i) {
|
||||
global = i;
|
||||
barrier_wait(&barrier);
|
||||
});
|
||||
|
||||
fprintf(stderr, "done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// CHECK: start
|
||||
// CHECK: WARNING: ThreadSanitizer: data race
|
||||
// CHECK: Location is global 'global'
|
||||
// CHECK: done
|
|
@ -0,0 +1,44 @@
|
|||
// RUN: %clang_tsan %s -o %t -framework Foundation
|
||||
// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "../test.h"
|
||||
|
||||
long global;
|
||||
long array[2];
|
||||
|
||||
void callback(void *context, size_t i) {
|
||||
long n = global;
|
||||
array[i] = n + i;
|
||||
barrier_wait(&barrier);
|
||||
}
|
||||
|
||||
int main(int argc, const char *argv[]) {
|
||||
barrier_init(&barrier, 2);
|
||||
fprintf(stderr, "start\n");
|
||||
dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT);
|
||||
|
||||
global = 42;
|
||||
|
||||
dispatch_apply(100, q, ^(size_t i) {
|
||||
long n = global;
|
||||
array[i] = n + i;
|
||||
barrier_wait(&barrier);
|
||||
});
|
||||
|
||||
for (int i = 0; i < 100; i++) {
|
||||
fprintf(stderr, "array[%d] = %ld\n", i, array[i]);
|
||||
}
|
||||
|
||||
global = 43;
|
||||
|
||||
dispatch_apply_f(100, q, NULL, &callback);
|
||||
|
||||
fprintf(stderr, "done\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// CHECK: start
|
||||
// CHECK: done
|
||||
// CHECK-NOT: WARNING: ThreadSanitizer
|
Loading…
Reference in New Issue