2 * prioritize process launch: Tests prioritized process launch across posix spawn and exec.
5 #include <dispatch/dispatch.h>
9 #include <mach/message.h>
10 #include <mach/mach_voucher.h>
11 #include <pthread/workqueue_private.h>
12 #include <voucher/ipc_pthread_priority_types.h>
13 #include <servers/bootstrap.h>
15 #include <sys/event.h>
18 #include <crt_externs.h>
20 #include <sys/types.h>
21 #include <sys/sysctl.h>
22 #include <libkern/OSAtomic.h>
25 #include <spawn_private.h>
32 mach_port_t notify_port
);
35 get_pri(thread_t thread_port
)
39 thread_extended_info_data_t extended_info
;
40 mach_msg_type_number_t count
= THREAD_EXTENDED_INFO_COUNT
;
41 kr
= thread_info(thread_port
, THREAD_EXTENDED_INFO
,
42 (thread_info_t
)&extended_info
, &count
);
44 if (kr
!= KERN_SUCCESS
) {
45 printf("thread info failed to get current priority of the thread\n");
47 return extended_info
.pth_curpri
;
51 set_thread_name(const char *fn_name
)
55 thread_t thread_port
= pthread_mach_thread_np(pthread_self());
57 int pri
= get_pri(thread_port
);
59 snprintf(name
, sizeof(name
), "%s at pri %2d", fn_name
, pri
);
60 pthread_setname_np(name
);
65 mach_port_t send_port
,
66 mach_port_t reply_port
,
68 mach_msg_option_t options
,
71 kern_return_t ret
= 0;
74 mach_msg_header_t header
;
76 mach_msg_port_descriptor_t port_descriptor
;
79 .msgh_remote_port
= send_port
,
80 .msgh_local_port
= reply_port
,
81 .msgh_bits
= MACH_MSGH_BITS_SET(send_disposition
,
82 reply_port
? MACH_MSG_TYPE_MAKE_SEND_ONCE
: 0,
83 MACH_MSG_TYPE_MOVE_SEND
,
84 MACH_MSGH_BITS_COMPLEX
),
86 .msgh_size
= sizeof(send_msg
),
89 .msgh_descriptor_count
= 1,
93 .disposition
= MACH_MSG_TYPE_MOVE_RECEIVE
,
94 .type
= MACH_MSG_PORT_DESCRIPTOR
,
98 if (msg_port
== MACH_PORT_NULL
) {
99 send_msg
.body
.msgh_descriptor_count
= 0;
102 ret
= mach_msg(&(send_msg
.header
),
106 ((reply_port
? MACH_SEND_SYNC_OVERRIDE
: 0) | options
),
107 send_msg
.header
.msgh_size
,
113 if (ret
!= KERN_SUCCESS
) {
114 printf("mach_msg_send failed with error %d\n", ret
);
120 mach_port_t rcv_port
,
121 mach_port_t notify_port
)
123 kern_return_t ret
= 0;
124 mach_port_t service_port
;
127 mach_msg_header_t header
;
128 mach_msg_body_t body
;
129 mach_msg_port_descriptor_t port_descriptor
;
130 mach_msg_trailer_t trailer
;
134 .msgh_remote_port
= MACH_PORT_NULL
,
135 .msgh_local_port
= rcv_port
,
136 .msgh_size
= sizeof(rcv_msg
),
140 printf("Client: Starting sync receive\n");
142 ret
= mach_msg(&(rcv_msg
.header
),
143 MACH_RCV_MSG
| MACH_RCV_LARGE
|
144 (notify_port
? MACH_RCV_SYNC_WAIT
: 0),
146 rcv_msg
.header
.msgh_size
,
151 printf("mach msg rcv returned %d\n", ret
);
154 if (rcv_msg
.body
.msgh_descriptor_count
!= 1) {
156 printf("Did not receive a service port in mach msg %d\n", rcv_msg
.body
.msgh_descriptor_count
);
158 return MACH_PORT_NULL
;
161 service_port
= rcv_msg
.port_descriptor
.name
;
166 main(int argc
__attribute__((unused
)), char *argv
[])
169 set_thread_name(__FUNCTION__
);
171 /* Check for priority */
172 priority
= get_pri(mach_thread_self());
173 printf("The priority of child is %d\n", priority
);
175 if (strcmp(argv
[1], "EXIT") == 0) {
176 printf("Helper process exiting\n");
178 } else if (strcmp(argv
[1], "EXEC") == 0) {
181 printf("Helper process execing\n");
182 /* exec the same binary with EXIT arg */
183 char *binary
= "prioritize_process_launch_helper";
184 char *new_argv
[] = {binary
, "EXIT", NULL
};
185 ret
= execve(binary
, new_argv
, NULL
);
187 } else if (strcmp(argv
[1], "SETEXEC") == 0) {
190 posix_spawnattr_t attr
;
192 ret
= posix_spawnattr_init(&attr
);
194 printf("posix_spawnattr_init failed \n");
197 ret
= posix_spawnattr_setflags(&attr
, POSIX_SPAWN_SETEXEC
);
199 printf("posix_spawnattr_setflags failed \n");
203 printf("Helper process doing posix_spawn set_exec\n");
204 /* set exec the same binary with EXIT arg */
205 char *binary
= "prioritize_process_launch_helper";
206 char *new_argv
[] = {binary
, "EXIT", NULL
};
208 ret
= posix_spawn(&child_pid
, binary
, NULL
, &attr
, new_argv
, NULL
);
210 } else if (strcmp(argv
[1], "SETEXEC_PORTS") == 0) {
213 posix_spawnattr_t attr
;
216 kern_return_t kr
= mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE
, &port
);
217 if (kr
!= KERN_SUCCESS
) {
218 printf("mach_port_allocate failed with error %d\n", kr
);
222 kr
= mach_port_insert_right(mach_task_self(), port
, port
, MACH_MSG_TYPE_MAKE_SEND
);
223 if (kr
!= KERN_SUCCESS
) {
224 printf("mach_port_insert_right failed with error %d\n", kr
);
228 ret
= posix_spawnattr_init(&attr
);
230 printf("posix_spawnattr_init failed \n");
234 ret
= posix_spawnattr_setflags(&attr
, POSIX_SPAWN_SETEXEC
);
236 printf("posix_spawnattr_setflags failed \n");
240 ret
= posix_spawnattr_set_importancewatch_port_np(&attr
, 1, &port
);
242 printf("posix_spawnattr_set_importance_port_np failed \n");
246 printf("Helper process doing posix_spawn set_exec\n");
247 /* set exec the same binary with EXIT arg */
248 char *binary
= "prioritize_process_launch_helper";
249 char *new_argv
[] = {binary
, "EXIT", NULL
};
251 ret
= posix_spawn(&child_pid
, binary
, NULL
, &attr
, new_argv
, NULL
);
252 printf("spawned failed with error %d\n", ret
);
254 } else if (strcmp(argv
[1], "WAIT") == 0) {
257 priority
= get_pri(mach_thread_self());
258 } while (priority
== 47);
260 } else if (strcmp(argv
[1], "MULTIWAIT") == 0) {
263 priority
= get_pri(mach_thread_self());
264 } while (priority
== 47);
265 printf("The priority came down to %d\n", priority
);
268 priority
= get_pri(mach_thread_self());
269 } while (priority
== 37);
270 printf("The priority came down to %d\n", priority
);
272 } else if (strcmp(argv
[1], "MSGSYNC") == 0) {
274 mach_port_array_t port_array
= NULL
;
275 unsigned int portCnt
= 0;
276 mach_port_t send_port
;
277 mach_port_t special_reply_port
;
278 mach_port_t service_port
;
281 priority
= get_pri(mach_thread_self());
282 printf("The priority of spawned binary is to %d\n", priority
);
283 if (priority
!= 47) {
287 /* Get the stashed send right using mach_ports_lookup */
288 kr
= mach_ports_lookup(mach_task_self(), &port_array
, &portCnt
);
289 if (kr
!= KERN_SUCCESS
) {
290 printf("mach_ports_lookup failed with return value %d and port count %d\n", kr
, portCnt
);
294 send_port
= port_array
[0];
295 special_reply_port
= thread_get_special_reply_port();
296 if (!MACH_PORT_VALID(special_reply_port
)) {
297 printf("Failed to special reply port for thread\n");
301 /* Perform a Sync bootstrap checkin */
302 send(send_port
, special_reply_port
, MACH_PORT_NULL
, MACH_SEND_SYNC_BOOTSTRAP_CHECKIN
, MACH_MSG_TYPE_COPY_SEND
);
305 /* Make sure we are still boosted */
306 priority
= get_pri(mach_thread_self());
307 printf("The priority of spawned binary is to %d\n", priority
);
308 if (priority
!= 47) {
312 /* Receive the service port */
313 service_port
= receive(special_reply_port
, send_port
);
315 /* Make sure we are still boosted */
316 priority
= get_pri(mach_thread_self());
317 printf("The priority of spawned binary is to %d\n", priority
);
318 if (priority
!= 47) {
322 /* Try to receive on service port */
323 receive(service_port
, MACH_PORT_NULL
);
325 /* Make sure we are no longer boosted */
326 priority
= get_pri(mach_thread_self());
327 printf("The priority of spawned binary is to %d\n", priority
);
328 if (priority
!= 31) {