1 | // RUN: %clangxx_tsan %s -o %t -framework Foundation |
2 | // RUN: %deflake %run %t 2>&1 | FileCheck %s |
3 | |
4 | // UNSUPPORTED: ios |
5 | |
6 | #import <Foundation/Foundation.h> |
7 | #import <xpc/xpc.h> |
8 | #import <stdatomic.h> |
9 | |
10 | #import "../test.h" |
11 | |
12 | long global; |
13 | |
14 | _Atomic(long) msg_counter; |
15 | _Atomic(long) processed_msgs; |
16 | xpc_connection_t server_conn; |
17 | xpc_connection_t client_conns[2]; |
18 | |
19 | int main(int argc, const char *argv[]) { |
20 | @autoreleasepool { |
21 | fprintf(stderr, format: "Hello world.\n" ); |
22 | // CHECK: Hello world. |
23 | |
24 | barrier_init(barrier: &barrier, count: 2); |
25 | |
26 | dispatch_queue_t server_q = dispatch_queue_create("server.queue" , DISPATCH_QUEUE_CONCURRENT); |
27 | |
28 | server_conn = xpc_connection_create(NULL, server_q); |
29 | |
30 | xpc_connection_set_event_handler(server_conn, ^(xpc_object_t client) { |
31 | fprintf(stderr, "server event handler, client = %p\n" , client); |
32 | |
33 | if (client == XPC_ERROR_CONNECTION_INTERRUPTED || client == XPC_ERROR_CONNECTION_INVALID) { |
34 | return; |
35 | } |
36 | xpc_connection_set_event_handler(client, ^(xpc_object_t object) { |
37 | fprintf(stderr, "received message: %p\n" , object); |
38 | |
39 | long msg_number = atomic_fetch_add_explicit(&msg_counter, 1, memory_order_relaxed); |
40 | |
41 | if (msg_number == 0) |
42 | barrier_wait(barrier: &barrier); |
43 | |
44 | global++; |
45 | // CHECK: WARNING: ThreadSanitizer: data race |
46 | // CHECK: Write of size 8 |
47 | // CHECK: #0 {{.*}}xpc-race.mm:[[@LINE-3]] |
48 | // CHECK: Previous write of size 8 |
49 | // CHECK: #0 {{.*}}xpc-race.mm:[[@LINE-5]] |
50 | // CHECK: Location is global 'global' |
51 | |
52 | if (msg_number == 1) |
53 | barrier_wait(barrier: &barrier); |
54 | |
55 | atomic_fetch_add(&processed_msgs, 1); |
56 | |
57 | dispatch_sync(dispatch_get_main_queue(), ^{ |
58 | if (processed_msgs >= 2) { |
59 | xpc_connection_cancel(client_conns[0]); |
60 | xpc_connection_cancel(client_conns[1]); |
61 | xpc_connection_cancel(server_conn); |
62 | CFRunLoopStop(CFRunLoopGetCurrent()); |
63 | } |
64 | }); |
65 | }); |
66 | |
67 | xpc_connection_resume(client); |
68 | }); |
69 | xpc_connection_resume(server_conn); |
70 | xpc_endpoint_t endpoint = xpc_endpoint_create(server_conn); |
71 | |
72 | for (int i = 0; i < 2; i++) { |
73 | client_conns[i] = xpc_connection_create_from_endpoint(endpoint); |
74 | xpc_connection_set_event_handler(client_conns[i], ^(xpc_object_t event) { |
75 | fprintf(stderr, "client event handler, event = %p\n" , event); |
76 | }); |
77 | |
78 | xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0); |
79 | xpc_dictionary_set_string(msg, "hello" , "world" ); |
80 | fprintf(stderr, "sending message: %p\n" , msg); |
81 | |
82 | xpc_connection_send_message(client_conns[i], msg); |
83 | xpc_connection_resume(client_conns[i]); |
84 | } |
85 | |
86 | CFRunLoopRun(); |
87 | |
88 | fprintf(stderr, format: "Done.\n" ); |
89 | // CHECK: Done. |
90 | } |
91 | return 0; |
92 | } |
93 | |