Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
XPC APIs have async callbacks, and we need some more happen-before edges to avoid false positives. This patch add them, plus a test case (sorry for the long boilerplate code, but XPC just needs all that). Differential Revision: http://reviews.llvm.org/D18493 llvm-svn: 265661
- Loading branch information
1 parent
cecb7fa
commit e316bb6
Showing
3 changed files
with
200 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// RUN: %clang_tsan %s -o %t -framework Foundation | ||
// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %deflake %run %t 2>&1 | FileCheck %s | ||
|
||
#import <Foundation/Foundation.h> | ||
|
||
#import "../test.h" | ||
|
||
long global; | ||
|
||
long received_msgs; | ||
xpc_connection_t server_conn; | ||
xpc_connection_t client_conns[2]; | ||
|
||
int main(int argc, const char *argv[]) { | ||
@autoreleasepool { | ||
NSLog(@"Hello world."); | ||
barrier_init(&barrier, 2); | ||
|
||
dispatch_queue_t server_q = dispatch_queue_create("server.queue", DISPATCH_QUEUE_CONCURRENT); | ||
|
||
server_conn = xpc_connection_create(NULL, server_q); | ||
|
||
xpc_connection_set_event_handler(server_conn, ^(xpc_object_t client) { | ||
NSLog(@"server event handler, client = %@", client); | ||
|
||
if (client == XPC_ERROR_CONNECTION_INTERRUPTED || client == XPC_ERROR_CONNECTION_INVALID) { | ||
return; | ||
} | ||
xpc_connection_set_event_handler(client, ^(xpc_object_t object) { | ||
NSLog(@"received message: %@", object); | ||
|
||
barrier_wait(&barrier); | ||
global = 42; | ||
|
||
dispatch_sync(dispatch_get_main_queue(), ^{ | ||
received_msgs++; | ||
|
||
if (received_msgs >= 2) { | ||
xpc_connection_cancel(client_conns[0]); | ||
xpc_connection_cancel(client_conns[1]); | ||
xpc_connection_cancel(server_conn); | ||
CFRunLoopStop(CFRunLoopGetCurrent()); | ||
} | ||
}); | ||
}); | ||
|
||
xpc_connection_resume(client); | ||
}); | ||
xpc_connection_resume(server_conn); | ||
xpc_endpoint_t endpoint = xpc_endpoint_create(server_conn); | ||
|
||
for (int i = 0; i < 2; i++) { | ||
client_conns[i] = xpc_connection_create_from_endpoint(endpoint); | ||
xpc_connection_set_event_handler(client_conns[i], ^(xpc_object_t event) { | ||
NSLog(@"client event handler, event = %@", event); | ||
}); | ||
|
||
xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0); | ||
xpc_dictionary_set_string(msg, "hello", "world"); | ||
NSLog(@"sending message: %@", msg); | ||
|
||
xpc_connection_send_message(client_conns[i], msg); | ||
xpc_connection_resume(client_conns[i]); | ||
} | ||
|
||
CFRunLoopRun(); | ||
|
||
NSLog(@"Done."); | ||
} | ||
return 0; | ||
} | ||
|
||
// CHECK: Hello world. | ||
// CHECK: WARNING: ThreadSanitizer: data race | ||
// CHECK: Write of size 8 | ||
// CHECK: #0 {{.*}}xpc-race.mm:33 | ||
// CHECK: Previous write of size 8 | ||
// CHECK: #0 {{.*}}xpc-race.mm:33 | ||
// CHECK: Location is global 'global' | ||
// CHECK: Done. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// 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> | ||
|
||
long global; | ||
|
||
int main(int argc, const char *argv[]) { | ||
@autoreleasepool { | ||
NSLog(@"Hello world."); | ||
|
||
dispatch_queue_t server_q = dispatch_queue_create("server.queue", DISPATCH_QUEUE_CONCURRENT); | ||
dispatch_queue_t client_q = dispatch_queue_create("client.queue", DISPATCH_QUEUE_CONCURRENT); | ||
|
||
xpc_connection_t server_conn = xpc_connection_create(NULL, server_q); | ||
|
||
global = 42; | ||
|
||
xpc_connection_set_event_handler(server_conn, ^(xpc_object_t client) { | ||
NSLog(@"global = %ld", global); | ||
NSLog(@"server event handler, client = %@", client); | ||
|
||
if (client == XPC_ERROR_CONNECTION_INTERRUPTED || client == XPC_ERROR_CONNECTION_INVALID) { | ||
return; | ||
} | ||
xpc_connection_set_event_handler(client, ^(xpc_object_t object) { | ||
NSLog(@"received message: %@", object); | ||
|
||
xpc_object_t reply = xpc_dictionary_create_reply(object); | ||
if (!reply) | ||
return; | ||
xpc_dictionary_set_string(reply, "reply", "value"); | ||
|
||
xpc_connection_t remote = xpc_dictionary_get_remote_connection(object); | ||
xpc_connection_send_message(remote, reply); | ||
}); | ||
|
||
xpc_connection_resume(client); | ||
}); | ||
xpc_connection_resume(server_conn); | ||
xpc_endpoint_t endpoint = xpc_endpoint_create(server_conn); | ||
|
||
xpc_connection_t client_conn = xpc_connection_create_from_endpoint(endpoint); | ||
xpc_connection_set_event_handler(client_conn, ^(xpc_object_t event) { | ||
NSLog(@"client event handler, event = %@", event); | ||
}); | ||
|
||
xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0); | ||
xpc_dictionary_set_string(msg, "hello", "world"); | ||
NSLog(@"sending message: %@", msg); | ||
|
||
xpc_connection_send_message_with_reply( | ||
client_conn, msg, client_q, ^(xpc_object_t object) { | ||
NSLog(@"received reply: %@", object); | ||
|
||
xpc_connection_cancel(client_conn); | ||
xpc_connection_cancel(server_conn); | ||
|
||
dispatch_sync(dispatch_get_main_queue(), ^{ | ||
CFRunLoopStop(CFRunLoopGetCurrent()); | ||
}); | ||
}); | ||
xpc_connection_resume(client_conn); | ||
|
||
CFRunLoopRun(); | ||
|
||
NSLog(@"Done."); | ||
} | ||
return 0; | ||
} | ||
|
||
// CHECK: Done. | ||
// CHECK-NOT: WARNING: ThreadSanitizer |