[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:
Kuba Brecka 2016-04-07 11:52:51 +00:00
parent e316bb61b3
commit 399af93242
3 changed files with 104 additions and 0 deletions

View File

@ -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

View File

@ -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

View File

@ -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