]> git.saurik.com Git - apple/xnu.git/blame - tests/prioritize_process_launch_helper.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / tests / prioritize_process_launch_helper.c
CommitLineData
cb323159
A
1/*
2 * prioritize process launch: Tests prioritized process launch across posix spawn and exec.
3 */
4
5#include <dispatch/dispatch.h>
6#include <pthread.h>
7#include <launch.h>
8#include <mach/mach.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>
14#include <stdlib.h>
15#include <sys/event.h>
16#include <stdio.h>
17#include <unistd.h>
18#include <crt_externs.h>
19#include <signal.h>
20#include <sys/types.h>
21#include <sys/sysctl.h>
22#include <libkern/OSAtomic.h>
23#include <sys/wait.h>
24#include <spawn.h>
25#include <spawn_private.h>
26#include <string.h>
27
28
29mach_port_t
30receive(
31 mach_port_t rcv_port,
32 mach_port_t notify_port);
33
34static int
35get_pri(thread_t thread_port)
36{
37 kern_return_t kr;
38
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);
43
44 if (kr != KERN_SUCCESS) {
45 printf("thread info failed to get current priority of the thread\n");
46 }
47 return extended_info.pth_curpri;
48}
49
50static void
51set_thread_name(const char *fn_name)
52{
53 char name[50] = "";
54
55 thread_t thread_port = pthread_mach_thread_np(pthread_self());
56
57 int pri = get_pri(thread_port);
58
59 snprintf(name, sizeof(name), "%s at pri %2d", fn_name, pri);
60 pthread_setname_np(name);
61}
62
63static void
64send(
65 mach_port_t send_port,
66 mach_port_t reply_port,
67 mach_port_t msg_port,
68 mach_msg_option_t options,
69 int send_disposition)
70{
71 kern_return_t ret = 0;
72
73 struct {
74 mach_msg_header_t header;
75 mach_msg_body_t body;
76 mach_msg_port_descriptor_t port_descriptor;
77 } send_msg = {
78 .header = {
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),
85 .msgh_id = 0x100,
86 .msgh_size = sizeof(send_msg),
87 },
88 .body = {
89 .msgh_descriptor_count = 1,
90 },
91 .port_descriptor = {
92 .name = msg_port,
93 .disposition = MACH_MSG_TYPE_MOVE_RECEIVE,
94 .type = MACH_MSG_PORT_DESCRIPTOR,
95 },
96 };
97
98 if (msg_port == MACH_PORT_NULL) {
99 send_msg.body.msgh_descriptor_count = 0;
100 }
101
102 ret = mach_msg(&(send_msg.header),
103 MACH_SEND_MSG |
104 MACH_SEND_TIMEOUT |
105 MACH_SEND_OVERRIDE |
106 ((reply_port ? MACH_SEND_SYNC_OVERRIDE : 0) | options),
107 send_msg.header.msgh_size,
108 0,
109 MACH_PORT_NULL,
110 10000,
111 0);
112
113 if (ret != KERN_SUCCESS) {
114 printf("mach_msg_send failed with error %d\n", ret);
115 }
116}
117
118mach_port_t
119receive(
120 mach_port_t rcv_port,
121 mach_port_t notify_port)
122{
123 kern_return_t ret = 0;
124 mach_port_t service_port;
125
126 struct {
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;
131 } rcv_msg = {
132 .header =
133 {
134 .msgh_remote_port = MACH_PORT_NULL,
135 .msgh_local_port = rcv_port,
136 .msgh_size = sizeof(rcv_msg),
137 },
138 };
139
140 printf("Client: Starting sync receive\n");
141
142 ret = mach_msg(&(rcv_msg.header),
143 MACH_RCV_MSG | MACH_RCV_LARGE |
144 (notify_port ? MACH_RCV_SYNC_WAIT : 0),
145 0,
146 rcv_msg.header.msgh_size,
147 rcv_port,
148 0,
149 notify_port);
150
151 printf("mach msg rcv returned %d\n", ret);
152
153
154 if (rcv_msg.body.msgh_descriptor_count != 1) {
155 if (notify_port) {
156 printf("Did not receive a service port in mach msg %d\n", rcv_msg.body.msgh_descriptor_count);
157 }
158 return MACH_PORT_NULL;
159 }
160
161 service_port = rcv_msg.port_descriptor.name;
162 return service_port;
163}
164
165int
166main(int argc __attribute__((unused)), char *argv[])
167{
168 int priority;
169 set_thread_name(__FUNCTION__);
170
171 /* Check for priority */
172 priority = get_pri(mach_thread_self());
173 printf("The priority of child is %d\n", priority);
174
175 if (strcmp(argv[1], "EXIT") == 0) {
176 printf("Helper process exiting\n");
177 exit(priority);
178 } else if (strcmp(argv[1], "EXEC") == 0) {
179 int ret;
180
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);
186 exit(ret);
187 } else if (strcmp(argv[1], "SETEXEC") == 0) {
188 int ret;
189 int child_pid;
190 posix_spawnattr_t attr;
191
192 ret = posix_spawnattr_init(&attr);
193 if (ret != 0) {
194 printf("posix_spawnattr_init failed \n");
195 exit(ret);
196 }
197 ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC);
198 if (ret != 0) {
199 printf("posix_spawnattr_setflags failed \n");
200 exit(ret);
201 }
202
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};
207
208 ret = posix_spawn(&child_pid, binary, NULL, &attr, new_argv, NULL);
209 exit(ret);
210 } else if (strcmp(argv[1], "SETEXEC_PORTS") == 0) {
211 int ret;
212 int child_pid;
213 posix_spawnattr_t attr;
214 mach_port_t port;
215
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);
219 exit(kr);
220 }
221
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);
225 exit(kr);
226 }
227
228 ret = posix_spawnattr_init(&attr);
229 if (ret != 0) {
230 printf("posix_spawnattr_init failed \n");
231 exit(ret);
232 }
233
234 ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC);
235 if (ret != 0) {
236 printf("posix_spawnattr_setflags failed \n");
237 exit(ret);
238 }
239
240 ret = posix_spawnattr_set_importancewatch_port_np(&attr, 1, &port);
241 if (ret != 0) {
242 printf("posix_spawnattr_set_importance_port_np failed \n");
243 exit(ret);
244 }
245
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};
250
251 ret = posix_spawn(&child_pid, binary, NULL, &attr, new_argv, NULL);
252 printf("spawned failed with error %d\n", ret);
253 exit(ret);
254 } else if (strcmp(argv[1], "WAIT") == 0) {
255 do {
256 sleep(1);
257 priority = get_pri(mach_thread_self());
258 } while (priority == 47);
259 exit(priority);
260 } else if (strcmp(argv[1], "MULTIWAIT") == 0) {
261 do {
262 sleep(1);
263 priority = get_pri(mach_thread_self());
264 } while (priority == 47);
265 printf("The priority came down to %d\n", priority);
266 do {
267 sleep(1);
268 priority = get_pri(mach_thread_self());
269 } while (priority == 37);
270 printf("The priority came down to %d\n", priority);
271 exit(priority);
272 } else if (strcmp(argv[1], "MSGSYNC") == 0) {
273 int ret_val = 31;
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;
279 kern_return_t kr;
280
281 priority = get_pri(mach_thread_self());
282 printf("The priority of spawned binary is to %d\n", priority);
283 if (priority != 47) {
284 ret_val = 0;
285 }
286
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);
291 exit(0);
292 }
293
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");
298 exit(0);
299 }
300
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);
303 sleep(2);
304
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) {
309 ret_val = 0;
310 }
311
312 /* Receive the service port */
313 service_port = receive(special_reply_port, send_port);
314
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) {
319 ret_val = 0;
320 }
321
322 /* Try to receive on service port */
323 receive(service_port, MACH_PORT_NULL);
324
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) {
329 ret_val = 0;
330 }
331 exit(ret_val);
332 }
333
334 exit(0);
335}