3 * File: sprace_test_11891562.c
4 * Test Description: The test ensures that there are no race conditions when multiple threads
5 * attempt to send messages to a mach port with a subset of threads waiting for a send possible
7 * Radar: <rdar://problem/11891562>
17 #include <mach/mach.h>
22 semaphore_t sender_sema
= SEMAPHORE_NULL
;
23 mach_port_t msg_port
= MACH_PORT_NULL
;
24 boolean_t msg_port_modref
= FALSE
;
29 mach_msg_empty_send_t smsg
;
30 mach_port_t notify
, old_notify
;
33 boolean_t use_sp
= *(boolean_t
*)arg
;
34 int send_possible_count
= 0;
36 fprintf(stderr
, "starting a thread %susing send-possible notifications.\n",
37 (!use_sp
) ? "not " : "");
40 kr
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, ¬ify
);
41 if (KERN_SUCCESS
!= kr
) {
42 mach_error("mach_port_allocate(notify)", kr
);
47 kr
= mach_port_request_notification(mach_task_self(), msg_port
,
48 MACH_NOTIFY_SEND_POSSIBLE
, 0 /* delayed */,
49 notify
, MACH_MSG_TYPE_MAKE_SEND_ONCE
,
51 if (KERN_INVALID_ARGUMENT
== kr
&& msg_port_modref
)
54 if (KERN_SUCCESS
!= kr
) {
55 mach_error("mach_port_request_notification(MACH_NOTIFY_SEND_POSSIBLE)", kr
);
58 if (MACH_PORT_NULL
!= old_notify
) {
59 fprintf(stderr
, "unexecpted old notify port (0x%x)\n", old_notify
);
67 mach_send_possible_notification_t nmsg
;
68 mach_msg_option_t options
;
69 mach_msg_return_t mret
;
72 mach_msg_option_t options
;
74 smsg
.header
.msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND
, 0);
75 smsg
.header
.msgh_remote_port
= msg_port
;
76 smsg
.header
.msgh_local_port
= MACH_PORT_NULL
;
77 smsg
.header
.msgh_size
= sizeof(smsg
);
78 smsg
.header
.msgh_id
= 0;
82 options
= MACH_SEND_MSG
| MACH_SEND_TIMEOUT
;
84 options
|= MACH_SEND_NOTIFY
;
86 mret
= mach_msg(&smsg
.header
, options
,
89 MACH_MSG_TIMEOUT_NONE
/* immediate timeout */,
92 if (MACH_MSG_SUCCESS
== mret
) {
97 if (MACH_SEND_INVALID_DEST
== mret
)
100 if (MACH_SEND_TIMED_OUT
!= mret
) {
101 mach_error("mach_msg(send)", mret
);
107 /* Wait for the send-possible notification */
108 mret
= mach_msg(&nmsg
.not_header
, MACH_RCV_MSG
| MACH_RCV_TIMEOUT
,
111 10000 /* 10 second timeout */,
117 if (MACH_RCV_TIMED_OUT
== mret
) {
118 fprintf(stderr
, "FAILED! Didn't receive send-possible notification\n");
122 if (MACH_MSG_SUCCESS
!= mret
) {
123 mach_error("mach_msg_receive(notify)\n", mret
);
127 switch (nmsg
.not_header
.msgh_id
) {
129 case MACH_NOTIFY_SEND_POSSIBLE
:
130 if (nmsg
.not_port
!= msg_port
) {
131 fprintf(stderr
, "send possible notification about wrong port (0x%x != 0x%x)\n", nmsg
.not_port
, msg_port
);
134 send_possible_count
++;
136 semaphore_signal_all(sender_sema
);
139 case MACH_NOTIFY_DEAD_NAME
:
140 if (nmsg
.not_port
!= msg_port
) {
141 fprintf(stderr
, "dead name notification about wrong port (0x%x != 0x%x)\n", nmsg
.not_port
, msg_port
);
146 fprintf(stderr
, "unexected notify id (%d)\n", nmsg
.not_header
.msgh_id
);
150 semaphore_wait(sender_sema
);
156 mach_port_destroy(mach_task_self(), notify
);
157 fprintf(stderr
, "received %d send-possible notifications\n", send_possible_count
);
163 main(int argc
, char **argv
) {
164 mach_msg_return_t mret
;
165 mach_port_limits_t limits
;
166 pthread_t thread1
, thread2
, thread3
;
167 boolean_t thread1_arg
, thread2_arg
, thread3_arg
;
171 /* allocate receive and send right for the message port */
172 kr
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &msg_port
);
173 if (KERN_SUCCESS
!= kr
) {
174 mach_error("mach_port_allocate(msg_port)", kr
);
177 kr
= mach_port_insert_right(mach_task_self(), msg_port
, msg_port
, MACH_MSG_TYPE_MAKE_SEND
);
178 if (KERN_SUCCESS
!= kr
) {
179 mach_error("mach_port_insert_right(msg_port)", kr
);
183 /* bump its qlimit up enough to allow races to develop between threads */
184 limits
.mpl_qlimit
= 100;
185 kr
= mach_port_set_attributes(mach_task_self(), msg_port
,
186 MACH_PORT_LIMITS_INFO
, (mach_port_info_t
)&limits
, sizeof(limits
)/sizeof(int));
187 if (KERN_SUCCESS
!= kr
) {
188 mach_error("mach_port_allocate(msg_port)", kr
);
192 kr
= semaphore_create(mach_task_self(), &sender_sema
, SYNC_POLICY_FIFO
, 0 /* initial value */);
193 if (KERN_SUCCESS
!= kr
) {
194 mach_error("semaphore_create(sender_sema)\n", kr
);
198 thread1_arg
= FALSE
; /* don't use send-possible notifications */
199 res
= pthread_create(&thread1
, (pthread_attr_t
*)NULL
, sender
, &thread1_arg
);
201 perror("pthread_create(non-send-possible_thread-1)");
205 thread2_arg
= FALSE
; /* don't use send-possible notifications */
206 res
= pthread_create(&thread2
, (pthread_attr_t
*)NULL
, sender
, &thread2_arg
);
208 perror("pthread_create(non-send-possible_thread-2)");
212 thread3_arg
= TRUE
; /* use send-possible notifications */
213 res
= pthread_create(&thread3
, (pthread_attr_t
*)NULL
, sender
, &thread3_arg
);
215 perror("pthread_create(send-possible-thread-3)");
219 for (i
=0; i
< COUNT
; i
++) {
220 mach_msg_empty_rcv_t rmsg
;
222 mret
= mach_msg(&rmsg
.header
, MACH_RCV_MSG
,
225 MACH_MSG_TIMEOUT_NONE
,
227 if (MACH_MSG_SUCCESS
!= mret
) {
228 mach_error("mach_msg_receive(msg_port)\n", mret
);
233 msg_port_modref
= TRUE
;
234 kr
= mach_port_mod_refs(mach_task_self(), msg_port
, MACH_PORT_RIGHT_RECEIVE
, -1);
235 if (KERN_SUCCESS
!= kr
) {
236 mach_error("mach_port_mod_refs(msg_port)", kr
);
240 kr
= semaphore_destroy(mach_task_self(), sender_sema
);
241 if (KERN_SUCCESS
!= kr
) {
242 mach_error("semaphore_destroy(sender_sema)", kr
);
246 res
= pthread_join(thread1
, NULL
);
248 perror("pthread_join(thread1)");
251 res
= pthread_join(thread2
, NULL
);
253 perror("pthread_join(thread2)");
256 res
= pthread_join(thread3
, NULL
);
258 perror("pthread_join(thread3)");
262 printf("[PASSED] Test sprace_test_11891562 passed. \n");