xref: /xnu-11417.101.15/tests/kevent_qos.c (revision e3723e1f17661b24996789d8afc084c0c3303b26)
1 /*
2  * kevent_qos: Tests Synchronous IPC QOS override.
3  */
4 
5 #ifdef T_NAMESPACE
6 #undef T_NAMESPACE
7 #endif
8 
9 #include <darwintest.h>
10 #include <darwintest_multiprocess.h>
11 
12 #include <dispatch/dispatch.h>
13 #include <pthread.h>
14 #include <launch.h>
15 #include <mach/mach.h>
16 #include <mach/message.h>
17 #include <mach/mach_voucher.h>
18 #include <pthread/workqueue_private.h>
19 #include <voucher/ipc_pthread_priority_types.h>
20 #include <servers/bootstrap.h>
21 #include <stdlib.h>
22 #include <sys/event.h>
23 #include <unistd.h>
24 #include <crt_externs.h>
25 #include <mach/mach_port.h>
26 #include <mach/mach_sync_ipc.h>
27 
28 T_GLOBAL_META(T_META_NAMESPACE("xnu.kevent_qos"),
29     T_META_RADAR_COMPONENT_NAME("xnu"),
30     T_META_RADAR_COMPONENT_VERSION("kevent"));
31 
32 #define ARRAYLEN(arr) (sizeof(arr) / sizeof(arr[0]))
33 
34 #define INTERMITTENT_TIMEOUT_SEC (3)
35 #define RECV_TIMEOUT_SECS   (4)
36 #define SEND_TIMEOUT_SECS   (6)
37 #define HELPER_TIMEOUT_SECS (15)
38 
39 #define ENV_VAR_QOS (3)
40 static const char *qos_env[ENV_VAR_QOS] = {"XNU_TEST_QOS_BO", "XNU_TEST_QOS_QO", "XNU_TEST_QOS_AO"};
41 static const char *qos_name_env[ENV_VAR_QOS] = {"XNU_TEST_QOS_NAME_BO", "XNU_TEST_QOS_NAME_QO", "XNU_TEST_QOS_NAME_AO"};
42 
43 #define ENV_VAR_FUNCTION (1)
44 static const char *wl_function_name = "XNU_TEST_WL_FUNCTION";
45 
46 static qos_class_t g_expected_qos[ENV_VAR_QOS];
47 static const char *g_expected_qos_name[ENV_VAR_QOS];
48 
49 #define ENV_QOS_BEFORE_OVERRIDE (0)
50 #define ENV_QOS_QUEUE_OVERRIDE  (1)
51 #define ENV_QOS_AFTER_OVERRIDE  (2)
52 
53 #define USR_THROTTLE_LEVEL_TIER0 0
54 #define USR_THROTTLE_LEVEL_TIER1 1
55 
56 struct test_msg {
57 	mach_msg_header_t header;
58 	mach_msg_body_t body;
59 	mach_msg_port_descriptor_t port_descriptor;
60 	mach_msg_option_t opts;
61 	mach_msg_priority_t qos;
62 };
63 
64 #pragma mark pthread callbacks
65 
66 static pthread_t
67 thread_create_at_qos(qos_class_t qos, void * (*function)(void *));
68 static void
69 send(mach_port_t send_port, mach_port_t reply_port, mach_port_t msg_port, qos_class_t qos, mach_msg_option_t options);
70 static void
71 enable_kevent(uint64_t *workloop_id, unsigned long long port);
72 static void
73 populate_kevent(struct kevent_qos_s *kev, unsigned long long port);
74 
75 static void
worker_cb(pthread_priority_t __unused priority)76 worker_cb(pthread_priority_t __unused priority)
77 {
78 	T_FAIL("a worker thread was created");
79 }
80 
81 static void
event_cb(void ** __unused events,int * __unused nevents)82 event_cb(void ** __unused events, int * __unused nevents)
83 {
84 	T_FAIL("a kevent routine was called instead of workloop");
85 }
86 
87 static uint32_t
get_user_promotion_basepri(void)88 get_user_promotion_basepri(void)
89 {
90 	mach_msg_type_number_t count = THREAD_POLICY_STATE_COUNT;
91 	struct thread_policy_state thread_policy;
92 	boolean_t get_default = FALSE;
93 	mach_port_t thread_port = pthread_mach_thread_np(pthread_self());
94 
95 	kern_return_t kr = thread_policy_get(thread_port, THREAD_POLICY_STATE,
96 	    (thread_policy_t)&thread_policy, &count, &get_default);
97 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_policy_get");
98 	return thread_policy.thps_user_promotion_basepri;
99 }
100 
101 static uint32_t
get_thread_iotier(void)102 get_thread_iotier(void)
103 {
104 	mach_msg_type_number_t count = THREAD_POLICY_STATE_COUNT;
105 	struct thread_policy_state thread_policy;
106 	boolean_t get_default = FALSE;
107 	mach_port_t thread_port = pthread_mach_thread_np(pthread_self());
108 
109 	kern_return_t kr = thread_policy_get(thread_port, THREAD_POLICY_STATE,
110 	    (thread_policy_t)&thread_policy, &count, &get_default);
111 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_policy_get");
112 	return (thread_policy.effective >> POLICY_EFF_IO_TIER_SHIFT) & POLICY_EFF_IO_TIER_MASK;
113 }
114 
115 #define EXPECT_QOS_EQ(qos, ...) do { \
116 	        if ((qos) == QOS_CLASS_USER_INTERACTIVE) { \
117 	                T_EXPECT_EFFECTIVE_QOS_EQ(QOS_CLASS_USER_INITIATED, __VA_ARGS__); \
118 	                T_EXPECT_EQ(47u, get_user_promotion_basepri(), __VA_ARGS__); \
119 	        } else { \
120 	                T_EXPECT_EFFECTIVE_QOS_EQ(qos, __VA_ARGS__); \
121 	        } \
122 	} while (0)
123 
124 #define EXPECT_TEST_MSG(_ke)  do { \
125 	        struct kevent_qos_s *ke = _ke; \
126 	        mach_msg_header_t *hdr = (mach_msg_header_t *)ke->ext[0]; \
127 	        T_ASSERT_NOTNULL(hdr, "has a message"); \
128 	        T_ASSERT_EQ(hdr->msgh_size, (uint32_t)sizeof(struct test_msg), "of the right size"); \
129 	        struct test_msg *tmsg = (struct test_msg *)hdr; \
130 	        if (tmsg->opts & MACH_SEND_PROPAGATE_QOS) { \
131 	                T_EXPECT_EQ(tmsg->qos, ((uint32_t)(ke->ext[2] >> 32)), \
132 	                                "propagation works"); \
133 	        } \
134 	} while (0)
135 
136 /*
137  * Basic WL handler callback, it sleeps for n seconds and then checks the
138  * effective Qos of the servicer thread.
139  */
140 static void
workloop_cb_test_intransit(uint64_t * workloop_id __unused,void ** eventslist,int * events)141 workloop_cb_test_intransit(uint64_t *workloop_id __unused, void **eventslist, int *events)
142 {
143 	T_LOG("Workloop handler workloop_cb_test_intransit called. "
144 	    "Will wait for %d seconds to make sure client enqueues the sync msg \n",
145 	    2 * RECV_TIMEOUT_SECS);
146 
147 	EXPECT_TEST_MSG(*eventslist);
148 
149 	/* Wait for the client to send the high priority message to override the qos */
150 	sleep(2 * RECV_TIMEOUT_SECS);
151 
152 	/* Skip the test if we can't check Qos */
153 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
154 
155 	/* The effective Qos should be the one expected after override */
156 	EXPECT_QOS_EQ(g_expected_qos[ENV_QOS_AFTER_OVERRIDE],
157 	    "dispatch_source event handler QoS should be %s", g_expected_qos_name[ENV_QOS_AFTER_OVERRIDE]);
158 
159 	*events = 0;
160 	T_END;
161 }
162 
163 /*
164  * WL handler which checks if the servicer thread has correct Qos.
165  */
166 static void
workloop_cb_test_sync_send(uint64_t * workloop_id __unused,void ** eventslist,int * events)167 workloop_cb_test_sync_send(uint64_t *workloop_id __unused, void **eventslist, int *events)
168 {
169 	T_LOG("Workloop handler workloop_cb_test_sync_send called");
170 
171 	EXPECT_TEST_MSG(*eventslist);
172 
173 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
174 
175 	/* The effective Qos should be the one expected after override */
176 	EXPECT_QOS_EQ(g_expected_qos[ENV_QOS_AFTER_OVERRIDE],
177 	    "dispatch_source event handler QoS should be %s", g_expected_qos_name[ENV_QOS_AFTER_OVERRIDE]);
178 
179 	*events = 0;
180 	T_END;
181 }
182 
183 /*
184  * WL handler which checks if the servicer thread has correct Qos.
185  */
186 static void
workloop_cb_test_kernel_sync_send(uint64_t * workloop_id __unused,void ** eventslist,int * events)187 workloop_cb_test_kernel_sync_send(uint64_t *workloop_id __unused, void **eventslist, int *events)
188 {
189 	T_LOG("Workloop handler workloop_cb_test_kernel_sync_send called");
190 
191 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
192 
193 	/* Wait for the kernel upcall to block on receive */
194 	sleep(2 * RECV_TIMEOUT_SECS);
195 
196 	/* The effective Qos should be the one expected after override */
197 	EXPECT_QOS_EQ(g_expected_qos[ENV_QOS_AFTER_OVERRIDE],
198 	    "dispatch_source event handler QoS should be %s", g_expected_qos_name[ENV_QOS_AFTER_OVERRIDE]);
199 
200 	*events = 0;
201 	T_END;
202 }
203 
204 /*
205  * WL handler which checks if the servicer thread has correct Qos.
206  */
207 static void
workloop_cb_test_kernel_async_send(uint64_t * workloop_id __unused,void ** eventslist,int * events)208 workloop_cb_test_kernel_async_send(uint64_t *workloop_id __unused, void **eventslist, int *events)
209 {
210 	T_LOG("Workloop handler workloop_cb_test_kernel_sync_send called");
211 
212 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
213 
214 	/* The effective Qos should be the one expected after override */
215 	EXPECT_QOS_EQ(g_expected_qos[ENV_QOS_AFTER_OVERRIDE],
216 	    "dispatch_source event handler QoS should be %s", g_expected_qos_name[ENV_QOS_AFTER_OVERRIDE]);
217 
218 	T_ASSERT_EQ(get_thread_iotier(), USR_THROTTLE_LEVEL_TIER0, "Thread IOTier has correct override");
219 
220 	*events = 0;
221 	T_END;
222 }
223 
224 /*
225  * WL handler which checks the overridden Qos and then enables the knote and checks
226  * for the Qos again if that dropped the sync ipc override.
227  */
228 static void
workloop_cb_test_sync_send_and_enable(uint64_t * workloop_id,struct kevent_qos_s ** eventslist,int * events)229 workloop_cb_test_sync_send_and_enable(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events)
230 {
231 	unsigned override_priority;
232 	unsigned reenable_priority;
233 
234 	T_LOG("Workloop handler workloop_cb_test_sync_send_and_enable called");
235 
236 	EXPECT_TEST_MSG(*eventslist);
237 
238 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
239 
240 	/* The effective Qos should be the one expected after override */
241 	EXPECT_QOS_EQ(g_expected_qos[ENV_QOS_AFTER_OVERRIDE],
242 	    "dispatch_source event handler QoS should be %s", g_expected_qos_name[ENV_QOS_AFTER_OVERRIDE]);
243 
244 	/* Snapshot the current override priority */
245 	override_priority = get_user_promotion_basepri();
246 
247 	/* Enable the knote */
248 	struct kevent_qos_s *kev = *eventslist;
249 	enable_kevent(workloop_id, kev->ident);
250 
251 	/*
252 	 * Check if the override has been dropped, check for priority instead of qos since
253 	 * there will be async qos push.
254 	 */
255 	reenable_priority = get_user_promotion_basepri();
256 	T_EXPECT_LT(reenable_priority, override_priority,
257 	    "thread's current override priority %d should be less than override priority prior to enabling knote %d",
258 	    reenable_priority, override_priority);
259 
260 	*events = 0;
261 	T_END;
262 }
263 
264 /*
265  * WL handler which checks the overridden Qos and then handoffs the IPC,
266  * enables the knote and checks for the Qos again that it hasn't dropped the sync ipc override.
267  */
268 static void
workloop_cb_test_sync_send_and_enable_handoff(uint64_t * workloop_id,struct kevent_qos_s ** eventslist,int * events)269 workloop_cb_test_sync_send_and_enable_handoff(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events)
270 {
271 	unsigned override_priority;
272 	int error;
273 
274 	T_LOG("Workloop handler workloop_cb_test_sync_send_and_enable_handoff called");
275 
276 	EXPECT_TEST_MSG(*eventslist);
277 
278 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
279 
280 	/* The effective Qos should be the one expected after override */
281 	EXPECT_QOS_EQ(g_expected_qos[ENV_QOS_AFTER_OVERRIDE],
282 	    "dispatch_source event handler QoS should be %s",
283 	    g_expected_qos_name[ENV_QOS_AFTER_OVERRIDE]);
284 
285 	/* Snapshot the current override priority */
286 	override_priority = get_user_promotion_basepri();
287 
288 	struct kevent_qos_s *kev = *eventslist;
289 	mach_msg_header_t *hdr = (mach_msg_header_t *)kev->ext[0];
290 
291 	/* handoff the IPC */
292 	struct kevent_qos_s handoff_kev = {
293 		.filter = EVFILT_WORKLOOP,
294 		.ident = hdr->msgh_remote_port,
295 		.flags = EV_ADD | EV_DISABLE,
296 		.fflags = 0x80000000,
297 	};
298 
299 	error = kevent_id(*workloop_id, &handoff_kev, 1, &handoff_kev, 1, NULL,
300 	    NULL, KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_ERROR_EVENTS | KEVENT_FLAG_DYNAMIC_KQ_MUST_EXIST);
301 	T_QUIET; T_ASSERT_POSIX_SUCCESS(error, "kevent_id");
302 	T_ASSERT_EQ(0, error, "Handed off the sync IPC");
303 
304 	/* Enable the knote */
305 	enable_kevent(workloop_id, kev->ident);
306 
307 	/*
308 	 * Check if the override has not been dropped.
309 	 */
310 	EXPECT_QOS_EQ(g_expected_qos[ENV_QOS_AFTER_OVERRIDE],
311 	    "dispatch_source event handler QoS should still be %s",
312 	    g_expected_qos_name[ENV_QOS_AFTER_OVERRIDE]);
313 
314 	*events = 0;
315 	T_END;
316 }
317 
318 /*
319  * WL handler receives the first message and checks sync ipc override, then enables the knote
320  * and receives 2nd message and checks it sync ipc override.
321  */
322 static int send_two_sync_handler_called = 0;
323 static void
workloop_cb_test_send_two_sync(uint64_t * workloop_id __unused,struct kevent_qos_s ** eventslist,int * events)324 workloop_cb_test_send_two_sync(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events)
325 {
326 	T_LOG("Workloop handler workloop_cb_test_send_two_sync called for %d time", send_two_sync_handler_called + 1);
327 
328 	EXPECT_TEST_MSG(*eventslist);
329 
330 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
331 
332 	T_LOG("Number of events received is %d\n", *events);
333 
334 	if (send_two_sync_handler_called == 0) {
335 		/* The effective Qos should be the one expected after override */
336 		EXPECT_QOS_EQ(g_expected_qos[ENV_QOS_AFTER_OVERRIDE],
337 		    "dispatch_source event handler QoS should be %s", g_expected_qos_name[ENV_QOS_AFTER_OVERRIDE]);
338 
339 		/* Enable the knote to get 2nd message */
340 		struct kevent_qos_s *kev = *eventslist;
341 		uint64_t port = kev->ident;
342 		populate_kevent(kev, port);
343 		*events = 1;
344 	} else {
345 		EXPECT_QOS_EQ(g_expected_qos[ENV_QOS_BEFORE_OVERRIDE],
346 		    "dispatch_source event handler QoS should be %s", g_expected_qos_name[ENV_QOS_BEFORE_OVERRIDE]);
347 		*events = 0;
348 		T_END;
349 	}
350 	send_two_sync_handler_called++;
351 }
352 
353 /*
354  * Checks the sync ipc override and then waits for client to destroy the
355  * special reply port and checks if that removes the sync ipc override.
356  */
357 static boolean_t two_send_and_destroy_test_passed = FALSE;
358 static int two_send_and_destroy_handler = 0;
359 static void
workloop_cb_test_two_send_and_destroy(uint64_t * workloop_id __unused,struct kevent_qos_s ** eventslist __unused,int * events)360 workloop_cb_test_two_send_and_destroy(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist __unused, int *events)
361 {
362 	T_LOG("Workloop handler workloop_cb_test_two_send_and_destroy called %d times", two_send_and_destroy_handler + 1);
363 
364 	EXPECT_TEST_MSG(*eventslist);
365 
366 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
367 
368 	if (two_send_and_destroy_handler == 0) {
369 		/* Sleep to make sure the mqueue gets full */
370 		sleep(RECV_TIMEOUT_SECS);
371 
372 		/* The effective Qos should be the one expected after override */
373 		EXPECT_QOS_EQ(g_expected_qos[ENV_QOS_AFTER_OVERRIDE],
374 		    "dispatch_source event handler QoS should be %s", g_expected_qos_name[ENV_QOS_AFTER_OVERRIDE]);
375 
376 		sleep(SEND_TIMEOUT_SECS);
377 
378 		/* Special reply port should have been destroyed, check Qos again */
379 		EXPECT_QOS_EQ(g_expected_qos[ENV_QOS_BEFORE_OVERRIDE],
380 		    "dispatch_source event handler QoS should be %s", g_expected_qos_name[ENV_QOS_BEFORE_OVERRIDE]);
381 
382 		two_send_and_destroy_test_passed = TRUE;
383 	} else {
384 		if (two_send_and_destroy_test_passed) {
385 			T_END;
386 		}
387 	}
388 
389 	/* Enable the knote to get next message */
390 	struct kevent_qos_s *kev = *eventslist;
391 	uint64_t port = kev->ident;
392 	populate_kevent(kev, port);
393 	*events = 1;
394 	two_send_and_destroy_handler++;
395 	T_LOG("Handler returning \n");
396 }
397 
398 static mach_port_type_t
get_reply_port(struct kevent_qos_s * kev)399 get_reply_port(struct kevent_qos_s *kev)
400 {
401 	mach_msg_header_t *hdr;
402 	mach_port_t reply_port;
403 	mach_port_type_t type;
404 	kern_return_t kr;
405 
406 	hdr = (void*)kev->ext[0];
407 	T_QUIET; T_ASSERT_NOTNULL(hdr, "msg hdr");
408 
409 	reply_port = hdr->msgh_remote_port;
410 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(reply_port), "reply port valid");
411 	kr = mach_port_type(mach_task_self(), reply_port, &type);
412 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_type");
413 	T_QUIET; T_ASSERT_TRUE(type & MACH_PORT_TYPE_SEND_ONCE, "send once received");
414 
415 	return reply_port;
416 }
417 
418 static void
send_reply(mach_port_t reply_port)419 send_reply(mach_port_t reply_port)
420 {
421 	kern_return_t kr;
422 
423 	struct {
424 		mach_msg_header_t header;
425 	} send_msg = {
426 		.header = {
427 			.msgh_remote_port = reply_port,
428 			.msgh_local_port  = MACH_PORT_NULL,
429 			.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0),
430 			.msgh_id          = 0x100,
431 			.msgh_size        = sizeof(send_msg),
432 		},
433 	};
434 
435 	kr = mach_msg(&(send_msg.header),
436 	    MACH_SEND_MSG,
437 	    send_msg.header.msgh_size,
438 	    0,
439 	    MACH_PORT_NULL,
440 	    0,
441 	    0);
442 
443 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "server mach_msg");
444 }
445 
446 static void
populate_kevent(struct kevent_qos_s * kev,unsigned long long port)447 populate_kevent(struct kevent_qos_s *kev, unsigned long long port)
448 {
449 	memset(kev, 0, sizeof(struct kevent_qos_s));
450 	kev->ident = port;
451 	kev->filter = EVFILT_MACHPORT;
452 	kev->flags = EV_ADD | EV_ENABLE | EV_UDATA_SPECIFIC | EV_DISPATCH | EV_VANISHED;
453 	kev->fflags = (MACH_RCV_MSG | MACH_RCV_VOUCHER | MACH_RCV_LARGE | MACH_RCV_LARGE_IDENTITY |
454 	    MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV) |
455 	    MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
456 	kev->data = 1;
457 }
458 
459 static void
enable_kevent(uint64_t * workloop_id,unsigned long long port)460 enable_kevent(uint64_t *workloop_id, unsigned long long port)
461 {
462 	struct kevent_qos_s kev;
463 	int error;
464 
465 	populate_kevent(&kev, port);
466 	struct kevent_qos_s kev_err[] = {{ 0 }};
467 
468 	error = kevent_id(*workloop_id, &kev, 1, kev_err, 1, NULL,
469 	    NULL, KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_ERROR_EVENTS | KEVENT_FLAG_DYNAMIC_KQ_MUST_EXIST);
470 	T_QUIET; T_ASSERT_POSIX_SUCCESS(error, "kevent_id");
471 }
472 
473 /*
474  * WL handler which sends a msg to the client from handler.
475  */
476 static void
workloop_cb_test_sync_send_reply(uint64_t * workloop_id __unused,struct kevent_qos_s ** eventslist,int * events)477 workloop_cb_test_sync_send_reply(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events)
478 {
479 	T_LOG("Workloop handler workloop_cb_test_sync_send_reply called");
480 
481 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
482 
483 	T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received");
484 	T_QUIET; T_ASSERT_EQ_INT((*eventslist)->filter, EVFILT_MACHPORT, "received EVFILT_MACHPORT");
485 
486 	/* send reply */
487 	send_reply(get_reply_port(*eventslist));
488 
489 	*events = 0;
490 }
491 
492 /*
493  * WL handler which deallocates reply port.
494  */
495 static void
workloop_cb_test_sync_send_deallocate(uint64_t * workloop_id __unused,struct kevent_qos_s ** eventslist,int * events)496 workloop_cb_test_sync_send_deallocate(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events)
497 {
498 	mach_port_t reply_port;
499 	kern_return_t kr;
500 
501 	T_LOG("Workloop handler workloop_cb_test_sync_send_deallocate called");
502 
503 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
504 
505 	T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received");
506 	T_QUIET; T_ASSERT_EQ_INT((*eventslist)->filter, EVFILT_MACHPORT, "received EVFILT_MACHPORT");
507 
508 	reply_port = get_reply_port(*eventslist);
509 
510 	/* deallocate port */
511 	kr = mach_port_deallocate(mach_task_self(), reply_port);
512 
513 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_deallocate");
514 
515 	*events = 0;
516 
517 	T_LOG("Handler returning \n");
518 }
519 
520 
521 /*
522  * WL handler which sends a msg to the client before enabling the event from handler.
523  */
524 static void
workloop_cb_test_sync_send_reply_kevent(uint64_t * workloop_id,struct kevent_qos_s ** eventslist,int * events)525 workloop_cb_test_sync_send_reply_kevent(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events)
526 {
527 	T_LOG("Workloop handler workloop_cb_test_sync_send_reply_kevent called");
528 
529 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
530 
531 	T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received");
532 	T_QUIET; T_ASSERT_EQ_INT(((*eventslist)->filter), EVFILT_MACHPORT, "received EVFILT_MACHPORT");
533 
534 	struct kevent_qos_s *kev = *eventslist;
535 
536 	/* send reply */
537 	send_reply(get_reply_port(kev));
538 
539 	/* Enable the knote */
540 	enable_kevent(workloop_id, kev->ident);
541 
542 	*events = 0;
543 
544 	T_LOG("Handler returning \n");
545 }
546 
547 /*
548  * WL handler which sends a msg to the client before enabling the event from pthread.
549  */
550 static void
workloop_cb_test_sync_send_reply_kevent_pthread(uint64_t * workloop_id __unused,struct kevent_qos_s ** eventslist,int * events)551 workloop_cb_test_sync_send_reply_kevent_pthread(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events)
552 {
553 	T_LOG("Workloop handler workloop_cb_test_sync_send_reply_kevent_pthread called");
554 
555 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
556 
557 	T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received");
558 	T_QUIET; T_ASSERT_EQ_INT((*eventslist)->filter, EVFILT_MACHPORT, "received EVFILT_MACHPORT");
559 
560 	struct kevent_qos_s *kev = *eventslist;
561 
562 	/* send reply */
563 	send_reply(get_reply_port(kev));
564 
565 	populate_kevent(kev, kev->ident);
566 
567 	*events = 1;
568 
569 	T_LOG("Handler returning \n");
570 }
571 
572 /*
573  * WL handler which sends a msg to the client after reenabling the event.
574  */
575 static void
workloop_cb_test_sync_send_kevent_reply(uint64_t * workloop_id,struct kevent_qos_s ** eventslist,int * events)576 workloop_cb_test_sync_send_kevent_reply(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events)
577 {
578 	T_LOG("workloop handler workloop_cb_test_sync_send_kevent_reply called");
579 
580 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
581 
582 	T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received");
583 	T_QUIET; T_ASSERT_EQ_INT((*eventslist)->filter, EVFILT_MACHPORT, "received EVFILT_MACHPORT");
584 
585 	struct kevent_qos_s *kev = *eventslist;
586 	mach_port_t reply_port = get_reply_port(*eventslist);
587 
588 	/* Enable the knote */
589 	enable_kevent(workloop_id, kev->ident);
590 
591 	/* send reply */
592 	send_reply(reply_port);
593 
594 	*events = 0;
595 
596 	T_LOG("Handler returning \n");
597 }
598 
599 /*
600  * WL handler that does nothing.
601  */
602 static void
workloop_cb_test_sync_send_do_nothing(uint64_t * workloop_id __unused,struct kevent_qos_s ** eventslist,int * events)603 workloop_cb_test_sync_send_do_nothing(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events)
604 {
605 	T_LOG("Workloop handler workloop_cb_test_sync_send_do_nothing called");
606 
607 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
608 
609 	T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received");
610 	T_QUIET; T_ASSERT_EQ_INT((*eventslist)->filter, EVFILT_MACHPORT, "received EVFILT_MACHPORT");
611 
612 	/* do nothing */
613 
614 	*events = 0;
615 
616 	T_LOG("Handler returning \n");
617 }
618 
619 /*
620  * WL handler that returns the event to reenable.
621  */
622 static void
workloop_cb_test_sync_send_do_nothing_kevent_pthread(uint64_t * workloop_id __unused,struct kevent_qos_s ** eventslist,int * events)623 workloop_cb_test_sync_send_do_nothing_kevent_pthread(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events)
624 {
625 	T_LOG("Workloop handler workloop_cb_test_sync_send_do_nothing_kevent_pthread called");
626 
627 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
628 
629 	T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received");
630 	T_QUIET; T_ASSERT_EQ_INT((*eventslist)->filter, EVFILT_MACHPORT, "received EVFILT_MACHPORT");
631 
632 	struct kevent_qos_s *kev = *eventslist;
633 	populate_kevent(kev, kev->ident);
634 
635 	*events = 1;
636 
637 	T_LOG("handler returning \n");
638 }
639 
640 /*
641  * WL handler that exits.
642  */
643 static void
workloop_cb_test_sync_send_do_nothing_exit(uint64_t * workloop_id __unused,struct kevent_qos_s ** eventslist,__unused int * events)644 workloop_cb_test_sync_send_do_nothing_exit(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, __unused int *events)
645 {
646 	T_LOG("workloop handler workloop_cb_test_sync_send_do_nothing_exit called");
647 
648 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
649 
650 	T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received");
651 	T_QUIET; T_ASSERT_EQ_INT((*eventslist)->filter, EVFILT_MACHPORT, "received EVFILT_MACHPORT");
652 
653 	/* call exit */
654 	exit(0);
655 }
656 
657 /*
658  * WL handler which:
659  * first sync sends a msg to the client and reenables kevent after
660  * second sync sends a msg and reenables kevent after.
661  */
662 static void
workloop_cb_test_sync_send_reply_kevent_reply_kevent(uint64_t * workloop_id __unused,struct kevent_qos_s ** eventslist,int * events)663 workloop_cb_test_sync_send_reply_kevent_reply_kevent(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events)
664 {
665 	T_LOG("Workloop handler workloop_cb_test_sync_send_reply_kevent_reply_kevent called");
666 
667 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
668 
669 	T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received");
670 	T_QUIET; T_ASSERT_EQ_INT((*eventslist)->filter, EVFILT_MACHPORT, "received EVFILT_MACHPORT");
671 
672 	struct kevent_qos_s *kev = *eventslist;
673 
674 	/* send reply */
675 	send_reply(get_reply_port(kev));
676 
677 	populate_kevent(kev, kev->ident);
678 
679 	*events = 1;
680 
681 	T_LOG("Handler returning \n");
682 }
683 
684 /*
685  * WL handler which:
686  * first sync reenables kevent and after sends a msg
687  * second sync sends a msg and reenables kevent after.
688  */
689 static int workloop_cb_test_sync_send_kevent_reply_reply_kevent_handler_called = 0;
690 static void
workloop_cb_test_sync_send_kevent_reply_reply_kevent(uint64_t * workloop_id,struct kevent_qos_s ** eventslist,int * events)691 workloop_cb_test_sync_send_kevent_reply_reply_kevent(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events)
692 {
693 	T_LOG("workloop handler workloop_cb_test_sync_send_kevent_reply_reply_kevent called");
694 
695 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
696 
697 	T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received");
698 	T_QUIET; T_ASSERT_EQ_INT((*eventslist)->filter, EVFILT_MACHPORT, "received EVFILT_MACHPORT");
699 
700 	struct kevent_qos_s *kev = *eventslist;
701 	mach_port_t reply_port = get_reply_port(kev);
702 
703 	if (workloop_cb_test_sync_send_kevent_reply_reply_kevent_handler_called == 0) {
704 		workloop_cb_test_sync_send_kevent_reply_reply_kevent_handler_called = 1;
705 
706 		/* Enable the knote */
707 		enable_kevent(workloop_id, kev->ident);
708 
709 		/* send reply */
710 		send_reply(reply_port);
711 
712 		*events = 0;
713 	} else {
714 		/* send reply */
715 		send_reply(reply_port);
716 
717 		/* Enable the knote */
718 		enable_kevent(workloop_id, kev->ident);
719 
720 		*events = 0;
721 	}
722 
723 	T_LOG("Handler returning \n");
724 }
725 
726 /*
727  * WL handler which:
728  * first sync reenables kevent and after sends a msg
729  * second sync reenables kevent and after sends a msg
730  */
731 static void
workloop_cb_test_sync_send_kevent_reply_kevent_reply(uint64_t * workloop_id,struct kevent_qos_s ** eventslist,int * events)732 workloop_cb_test_sync_send_kevent_reply_kevent_reply(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events)
733 {
734 	T_LOG("workloop handler workloop_cb_test_sync_send_kevent_reply_kevent_reply called");
735 
736 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
737 
738 	T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received");
739 	T_QUIET; T_ASSERT_EQ_INT((*eventslist)->filter, EVFILT_MACHPORT, "received EVFILT_MACHPORT");
740 
741 	struct kevent_qos_s *kev = *eventslist;
742 	mach_port_t reply_port = get_reply_port(kev);
743 
744 	/* Enable the knote */
745 	enable_kevent(workloop_id, kev->ident);
746 
747 	/* send reply */
748 	send_reply(reply_port);
749 
750 	*events = 0;
751 	T_LOG("Handler returning \n");
752 }
753 
754 /*
755  * WL handler which:
756  * first sync ends a msg and reenables kevent after
757  * second sync reenables kevent and sends a msg after
758  */
759 static int workloop_cb_test_sync_send_reply_kevent_kevent_reply_handler_called = 0;
760 static void
workloop_cb_test_sync_send_reply_kevent_kevent_reply(uint64_t * workloop_id,struct kevent_qos_s ** eventslist,int * events)761 workloop_cb_test_sync_send_reply_kevent_kevent_reply(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events)
762 {
763 	T_LOG("workloop handler workloop_cb_test_sync_send_reply_kevent_kevent_reply called");
764 
765 	T_ASSERT_EQ(geteuid(), 0, "kevent_qos test requires root privileges to run.");
766 
767 	T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received");
768 	T_QUIET; T_ASSERT_EQ_INT((*eventslist)->filter, EVFILT_MACHPORT, "received EVFILT_MACHPORT");
769 
770 	struct kevent_qos_s *kev = *eventslist;
771 	mach_port_t reply_port = get_reply_port(kev);
772 
773 	if (workloop_cb_test_sync_send_reply_kevent_kevent_reply_handler_called == 0) {
774 		workloop_cb_test_sync_send_reply_kevent_kevent_reply_handler_called = 1;
775 
776 		/* send reply */
777 		send_reply(reply_port);
778 
779 		populate_kevent(kev, kev->ident);
780 
781 		*events = 1;
782 	} else {
783 		/* Enable the knote */
784 		enable_kevent(workloop_id, kev->ident);
785 		/* send reply */
786 		send_reply(reply_port);
787 
788 		*events = 0;
789 	}
790 
791 	T_LOG("Handler returning \n");
792 }
793 #pragma mark Mach receive
794 
795 #define KEVENT_QOS_SERVICE_NAME "com.apple.xnu.test.kevent_qos"
796 
797 static mach_port_t
get_server_port(void)798 get_server_port(void)
799 {
800 	mach_port_t port;
801 	kern_return_t kr = bootstrap_check_in(bootstrap_port,
802 	    KEVENT_QOS_SERVICE_NAME, &port);
803 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "server bootstrap_check_in");
804 	return port;
805 }
806 
807 static void
env_set_qos(char ** env,qos_class_t qos[],const char * qos_name[],const char * wl_function)808 env_set_qos(char **env, qos_class_t qos[], const char *qos_name[], const char *wl_function)
809 {
810 	int i;
811 	char *qos_str, *qos_name_str;
812 	for (i = 0; i < ENV_VAR_QOS; i++) {
813 		T_QUIET; T_ASSERT_POSIX_SUCCESS(asprintf(&qos_str, "%s=%d", qos_env[i], qos[i]),
814 		    NULL);
815 		T_QUIET; T_ASSERT_POSIX_SUCCESS(
816 			asprintf(&qos_name_str, "%s=%s", qos_name_env[i], qos_name[i]), NULL);
817 		env[2 * i] = qos_str;
818 		env[2 * i + 1] = qos_name_str;
819 	}
820 	T_QUIET; T_ASSERT_POSIX_SUCCESS(asprintf(&env[2 * i], "%s=%s", wl_function_name, wl_function),
821 	    NULL);
822 	env[2 * i + 1] = NULL;
823 }
824 
825 static void
environ_get_qos(qos_class_t qos[],const char * qos_name[],const char ** wl_function)826 environ_get_qos(qos_class_t qos[], const char *qos_name[], const char **wl_function)
827 {
828 	char *qos_str;
829 	char *qos_end;
830 	int i;
831 
832 	for (i = 0; i < ENV_VAR_QOS; i++) {
833 		qos_str = getenv(qos_env[i]);
834 		T_QUIET; T_ASSERT_NOTNULL(qos_str, "getenv(%s)", qos_env[i]);
835 
836 		unsigned long qos_l = strtoul(qos_str, &qos_end, 10);
837 		T_QUIET; T_ASSERT_EQ(*qos_end, '\0', "getenv(%s) = '%s' should be an "
838 		    "integer", qos_env[i], qos_str);
839 
840 		T_QUIET; T_ASSERT_LT(qos_l, (unsigned long)100, "getenv(%s) = '%s' should "
841 		    "be less than 100", qos_env[i], qos_str);
842 
843 		qos[i] = (qos_class_t)qos_l;
844 		qos_name[i] = getenv(qos_name_env[i]);
845 		T_QUIET; T_ASSERT_NOTNULL(qos_name[i], "getenv(%s)", qos_name_env[i]);
846 	}
847 	*wl_function = getenv(wl_function_name);
848 	T_QUIET; T_ASSERT_NOTNULL(*wl_function, "getenv(%s)", wl_function_name);
849 }
850 
851 static inline thread_qos_t
thread_qos_from_qos_class(qos_class_t cls)852 thread_qos_from_qos_class(qos_class_t cls)
853 {
854 	switch ((unsigned int)cls) {
855 	case QOS_CLASS_USER_INTERACTIVE: return THREAD_QOS_USER_INTERACTIVE;
856 	case QOS_CLASS_USER_INITIATED:   return THREAD_QOS_USER_INITIATED;
857 	case QOS_CLASS_DEFAULT:          return THREAD_QOS_DEFAULT;
858 	case QOS_CLASS_UTILITY:          return THREAD_QOS_UTILITY;
859 	case QOS_CLASS_BACKGROUND:       return THREAD_QOS_BACKGROUND;
860 	case QOS_CLASS_MAINTENANCE:      return THREAD_QOS_MAINTENANCE;
861 	default: return THREAD_QOS_UNSPECIFIED;
862 	}
863 }
864 
865 static void
send(mach_port_t send_port,mach_port_t reply_port,mach_port_t msg_port,qos_class_t qos,mach_msg_option_t options)866 send(
867 	mach_port_t send_port,
868 	mach_port_t reply_port,
869 	mach_port_t msg_port,
870 	qos_class_t qos,
871 	mach_msg_option_t options)
872 {
873 	kern_return_t ret = 0;
874 	mach_msg_priority_t priority = (uint32_t)_pthread_qos_class_encode(qos, 0, 0);
875 
876 	struct test_msg send_msg = {
877 		.header = {
878 			.msgh_remote_port = send_port,
879 			.msgh_local_port  = reply_port,
880 			.msgh_bits        = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND,
881 	    reply_port ? MACH_MSG_TYPE_MAKE_SEND_ONCE : 0, 0,
882 	    MACH_MSGH_BITS_COMPLEX),
883 			.msgh_id          = 0x100,
884 			.msgh_size        = sizeof(send_msg),
885 		},
886 		.body = {
887 			.msgh_descriptor_count = 1,
888 		},
889 		.port_descriptor = {
890 			.name        = msg_port,
891 			.disposition = MACH_MSG_TYPE_MOVE_RECEIVE,
892 			.type        = MACH_MSG_PORT_DESCRIPTOR,
893 		},
894 		.opts = options,
895 	};
896 
897 	if (msg_port == MACH_PORT_NULL) {
898 		send_msg.body.msgh_descriptor_count = 0;
899 	}
900 
901 	send_msg.qos = priority;
902 	priority = mach_msg_priority_encode(0, thread_qos_from_qos_class(qos), 0);
903 
904 	mach_msg_option_t send_opts = options;
905 	send_opts |= MACH_SEND_MSG | MACH_SEND_TIMEOUT | MACH_SEND_OVERRIDE;
906 
907 	ret = mach_msg(&send_msg.header, send_opts, send_msg.header.msgh_size,
908 	    0, MACH_PORT_NULL, 10000, priority);
909 
910 	T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "client mach_msg");
911 }
912 
913 static kern_return_t
receive(mach_port_t rcv_port,mach_port_t notify_port)914 receive(
915 	mach_port_t rcv_port,
916 	mach_port_t notify_port)
917 {
918 	kern_return_t ret = 0;
919 
920 	struct test_msg rcv_msg = {
921 		.header = {
922 			.msgh_remote_port = MACH_PORT_NULL,
923 			.msgh_local_port  = rcv_port,
924 			.msgh_size        = sizeof(rcv_msg),
925 		},
926 	};
927 
928 	T_LOG("Client: Starting sync receive\n");
929 
930 	ret = mach_msg(&(rcv_msg.header),
931 	    MACH_RCV_MSG |
932 	    MACH_RCV_TIMEOUT |
933 	    MACH_RCV_SYNC_WAIT,
934 	    0,
935 	    rcv_msg.header.msgh_size,
936 	    rcv_port,
937 	    SEND_TIMEOUT_SECS * 1000,
938 	    notify_port);
939 
940 	return ret;
941 }
942 
943 T_HELPER_DECL(qos_get_special_reply_port,
944     "Test get_special_reply_port and it's corner cases.")
945 {
946 	mach_port_t special_reply_port;
947 	mach_port_t new_special_reply_port;
948 
949 	special_reply_port = thread_get_special_reply_port();
950 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port), "get_thread_special_reply_port");
951 
952 	new_special_reply_port = thread_get_special_reply_port();
953 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(new_special_reply_port), "get_thread_special_reply_port");
954 
955 	mach_port_destroy(mach_task_self(), special_reply_port);
956 	mach_port_destroy(mach_task_self(), new_special_reply_port);
957 
958 	new_special_reply_port = thread_get_special_reply_port();
959 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(new_special_reply_port), "get_thread_special_reply_port");
960 
961 	T_END;
962 }
963 
964 static void *
qos_client_send_to_intransit(void * arg __unused)965 qos_client_send_to_intransit(void *arg __unused)
966 {
967 	mach_port_t qos_send_port;
968 	mach_port_t msg_port;
969 	mach_port_t special_reply_port;
970 
971 	kern_return_t kr = bootstrap_look_up(bootstrap_port,
972 	    KEVENT_QOS_SERVICE_NAME, &qos_send_port);
973 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
974 
975 	special_reply_port = thread_get_special_reply_port();
976 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port), "get_thread_special_reply_port");
977 
978 	/* Create a rcv right to send in a msg */
979 	kr = mach_port_allocate(mach_task_self(),
980 	    MACH_PORT_RIGHT_RECEIVE,
981 	    &msg_port);
982 
983 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client mach_port_allocate");
984 
985 	kr = mach_port_insert_right(mach_task_self(),
986 	    msg_port,
987 	    msg_port,
988 	    MACH_MSG_TYPE_MAKE_SEND);
989 
990 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client mach_port_insert_right");
991 
992 	/* Send an empty msg on the port to fire the WL thread */
993 	send(qos_send_port, MACH_PORT_NULL, MACH_PORT_NULL,
994 	    g_expected_qos[ENV_QOS_BEFORE_OVERRIDE], 0);
995 
996 	/* Sleep 3 seconds for the server to start */
997 	sleep(3);
998 
999 	/* Send the message with msg port as in-transit port, this msg will not be dequeued */
1000 	send(qos_send_port, MACH_PORT_NULL, msg_port,
1001 	    g_expected_qos[ENV_QOS_BEFORE_OVERRIDE], 0);
1002 
1003 	/* Send 5 messages to msg port to make sure the port is full */
1004 	for (int i = 0; i < 5; i++) {
1005 		send(msg_port, MACH_PORT_NULL, MACH_PORT_NULL,
1006 		    g_expected_qos[ENV_QOS_BEFORE_OVERRIDE], 0);
1007 	}
1008 
1009 	T_LOG("Sent 5 msgs, now trying to send sync ipc message, which will block with a timeout\n");
1010 	/* Send the message to the in-transit port, it should block and override the rcv's workloop */
1011 	send(msg_port, special_reply_port, MACH_PORT_NULL,
1012 	    g_expected_qos[ENV_QOS_AFTER_OVERRIDE], 0);
1013 	T_LOG("Client done sending messages, now waiting for server to end the test");
1014 
1015 	T_ASSERT_FAIL("client timed out");
1016 	return NULL;
1017 }
1018 
1019 T_HELPER_DECL(qos_client_send_to_intransit_with_thr_pri,
1020     "Send synchronous messages from a pri thread to an intransit port")
1021 {
1022 	thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE], qos_client_send_to_intransit);
1023 	sleep(HELPER_TIMEOUT_SECS);
1024 }
1025 
1026 static pthread_t
thread_create_at_qos(qos_class_t qos,void * (* function)(void *))1027 thread_create_at_qos(qos_class_t qos, void * (*function)(void *))
1028 {
1029 	qos_class_t qos_thread;
1030 	pthread_t thread;
1031 	pthread_attr_t attr;
1032 	int ret;
1033 
1034 	ret = setpriority(PRIO_DARWIN_ROLE, 0, PRIO_DARWIN_ROLE_UI_FOCAL);
1035 	if (ret != 0) {
1036 		T_LOG("set priority failed\n");
1037 	}
1038 
1039 	pthread_attr_init(&attr);
1040 	pthread_attr_set_qos_class_np(&attr, qos, 0);
1041 	pthread_create(&thread, &attr, function, NULL);
1042 
1043 	T_LOG("pthread created\n");
1044 	pthread_get_qos_class_np(thread, &qos_thread, NULL);
1045 	T_EXPECT_EQ(qos_thread, (qos_class_t)qos, NULL);
1046 	return thread;
1047 }
1048 
1049 static void *
qos_send_and_sync_rcv(void * arg __unused)1050 qos_send_and_sync_rcv(void *arg __unused)
1051 {
1052 	mach_port_t qos_send_port;
1053 	mach_port_t special_reply_port;
1054 
1055 	T_LOG("Client: from created thread\n");
1056 	T_EXPECT_EFFECTIVE_QOS_EQ(g_expected_qos[ENV_QOS_AFTER_OVERRIDE],
1057 	    "pthread QoS should be %s", g_expected_qos_name[ENV_QOS_AFTER_OVERRIDE]);
1058 
1059 	kern_return_t kr = bootstrap_look_up(bootstrap_port,
1060 	    KEVENT_QOS_SERVICE_NAME, &qos_send_port);
1061 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
1062 
1063 	special_reply_port = thread_get_special_reply_port();
1064 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port), "get_thread_special_reply_port");
1065 
1066 	/* enqueue two messages to make sure that mqueue is not empty */
1067 	send(qos_send_port, MACH_PORT_NULL, MACH_PORT_NULL,
1068 	    g_expected_qos[ENV_QOS_QUEUE_OVERRIDE], 0);
1069 
1070 	send(qos_send_port, MACH_PORT_NULL, MACH_PORT_NULL,
1071 	    g_expected_qos[ENV_QOS_QUEUE_OVERRIDE], 0);
1072 
1073 	sleep(SEND_TIMEOUT_SECS);
1074 
1075 	/* sync wait on msg port */
1076 	receive(special_reply_port, qos_send_port);
1077 
1078 	T_LOG("Client done doing sync rcv, now waiting for server to end the test");
1079 	sleep(SEND_TIMEOUT_SECS);
1080 
1081 	T_ASSERT_FAIL("client timed out");
1082 	return NULL;
1083 }
1084 
1085 static void *
qos_sync_rcv(void * arg __unused)1086 qos_sync_rcv(void *arg __unused)
1087 {
1088 	mach_port_t qos_send_port;
1089 	mach_port_t special_reply_port;
1090 
1091 	T_LOG("Client: from created thread\n");
1092 
1093 	kern_return_t kr = bootstrap_look_up(bootstrap_port,
1094 	    KEVENT_QOS_SERVICE_NAME, &qos_send_port);
1095 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
1096 
1097 	special_reply_port = thread_get_special_reply_port();
1098 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port), "get_thread_special_reply_port");
1099 
1100 	/* enqueue two messages to make sure that mqueue is not empty */
1101 	send(qos_send_port, MACH_PORT_NULL, MACH_PORT_NULL,
1102 	    g_expected_qos[ENV_QOS_QUEUE_OVERRIDE], 0);
1103 
1104 	sleep(RECV_TIMEOUT_SECS);
1105 
1106 	/* sync wait on msg port */
1107 	receive(special_reply_port, qos_send_port);
1108 
1109 	T_LOG("Client done doing sync rcv, now waiting for server to end the test");
1110 	sleep(SEND_TIMEOUT_SECS);
1111 
1112 	T_ASSERT_FAIL("client timed out");
1113 	return NULL;
1114 }
1115 
1116 static void
thread_wait_to_block(mach_port_t thread_port)1117 thread_wait_to_block(mach_port_t thread_port)
1118 {
1119 	thread_extended_info_data_t extended_info;
1120 	kern_return_t kr;
1121 
1122 	while (1) {
1123 		mach_msg_type_number_t count = THREAD_EXTENDED_INFO_COUNT;
1124 		kr = thread_info(thread_port, THREAD_EXTENDED_INFO,
1125 		    (thread_info_t)&extended_info, &count);
1126 
1127 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_info");
1128 
1129 		if (extended_info.pth_run_state == TH_STATE_WAITING) {
1130 			T_LOG("Target thread blocked\n");
1131 			break;
1132 		}
1133 		thread_switch(thread_port, SWITCH_OPTION_DEPRESS, 0);
1134 	}
1135 }
1136 
1137 T_HELPER_DECL(qos_client_send_sync_and_sync_rcv,
1138     "Send messages and syncronously wait for rcv")
1139 {
1140 	thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE], qos_send_and_sync_rcv);
1141 	sleep(HELPER_TIMEOUT_SECS);
1142 }
1143 
1144 T_HELPER_DECL(qos_client_sync_rcv_qos_change,
1145     "Send messages and syncronously wait for rcv and change qos of waiting thread")
1146 {
1147 	pthread_t rcv_thread;
1148 
1149 	rcv_thread = thread_create_at_qos(g_expected_qos[ENV_QOS_BEFORE_OVERRIDE], qos_sync_rcv);
1150 
1151 	T_LOG("Waiting for %d seconds before changing qos of rcv thread", SEND_TIMEOUT_SECS);
1152 	sleep(SEND_TIMEOUT_SECS);
1153 
1154 	/* Wait for the thread to block */
1155 	thread_wait_to_block(pthread_mach_thread_np(rcv_thread));
1156 
1157 	/* Update the rcv thread's qos */
1158 	pthread_override_qos_class_start_np(rcv_thread, g_expected_qos[ENV_QOS_AFTER_OVERRIDE], 0);
1159 
1160 	sleep(HELPER_TIMEOUT_SECS);
1161 }
1162 
1163 static void *
qos_client_send_sync_msg_and_test_link(void * arg)1164 qos_client_send_sync_msg_and_test_link(void *arg)
1165 {
1166 	mach_port_t qos_send_port;
1167 	mach_port_t special_reply_port;
1168 	boolean_t in_effect = FALSE;
1169 	kern_return_t kr;
1170 	unsigned long expected_result = (unsigned long) arg;
1171 
1172 	kr = bootstrap_look_up(bootstrap_port,
1173 	    KEVENT_QOS_SERVICE_NAME, &qos_send_port);
1174 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
1175 
1176 	/* start monitoring sync ipc link */
1177 	kr = mach_sync_ipc_link_monitoring_start(&special_reply_port);
1178 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_sync_ipc_link_monitoring_start");
1179 
1180 	/* Send the message to msg port */
1181 	send(qos_send_port, special_reply_port, MACH_PORT_NULL,
1182 	    g_expected_qos[ENV_QOS_AFTER_OVERRIDE], 0);
1183 
1184 	/*
1185 	 * wait for the reply
1186 	 * some tests do not send a msg back so the receive
1187 	 * might fail
1188 	 */
1189 	receive(special_reply_port, qos_send_port);
1190 
1191 	/* stop monitoring link */
1192 	kr = mach_sync_ipc_link_monitoring_stop(special_reply_port, &in_effect);
1193 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_sync_ipc_link_monitoring_stop");
1194 
1195 	if (!in_effect) {
1196 		T_LOG("Link was broken");
1197 	} else {
1198 		T_LOG("Link correct");
1199 	}
1200 
1201 	if (expected_result == 1) {
1202 		T_ASSERT_TRUE(in_effect, "special reply port link after rcv");
1203 	} else {
1204 		T_ASSERT_FALSE(in_effect, "special reply port link after rcv");
1205 	}
1206 	T_END;
1207 }
1208 
1209 static void *
qos_client_send_2sync_msg_and_test_link(void * arg)1210 qos_client_send_2sync_msg_and_test_link(void *arg)
1211 {
1212 	mach_port_t qos_send_port;
1213 	mach_port_t special_reply_port;
1214 	boolean_t in_effect = FALSE;
1215 	kern_return_t kr;
1216 	unsigned long expected_result = (unsigned long) arg;
1217 
1218 	kr = bootstrap_look_up(bootstrap_port,
1219 	    KEVENT_QOS_SERVICE_NAME, &qos_send_port);
1220 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
1221 
1222 	/* start monitoring sync ipc link */
1223 	kr = mach_sync_ipc_link_monitoring_start(&special_reply_port);
1224 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_sync_ipc_link_monitoring_start");
1225 
1226 	/* Send the first message to msg port */
1227 	send(qos_send_port, special_reply_port, MACH_PORT_NULL,
1228 	    g_expected_qos[ENV_QOS_AFTER_OVERRIDE], 0);
1229 
1230 	/* wait for the reply */
1231 	kr = receive(special_reply_port, qos_send_port);
1232 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "receive");
1233 
1234 	/* Send the second message to msg port */
1235 	send(qos_send_port, special_reply_port, MACH_PORT_NULL,
1236 	    g_expected_qos[ENV_QOS_AFTER_OVERRIDE], 0);
1237 
1238 	/* wait for the reply */
1239 	kr = receive(special_reply_port, qos_send_port);
1240 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "receive");
1241 
1242 	/* stop monitoring link */
1243 	kr = mach_sync_ipc_link_monitoring_stop(special_reply_port, &in_effect);
1244 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_sync_ipc_link_monitoring_stop");
1245 
1246 	if (!in_effect) {
1247 		T_LOG("Link was broken");
1248 	} else {
1249 		T_LOG("Link correct");
1250 	}
1251 
1252 	if (expected_result == 1) {
1253 		T_ASSERT_TRUE(in_effect, "special reply port link after rcv");
1254 	} else {
1255 		T_ASSERT_FALSE(in_effect, "special reply port link after rcv");
1256 	}
1257 	T_END;
1258 }
1259 T_HELPER_DECL(qos_client_send_sync_msg_with_link_check_correct_server,
1260     "Send sync message, wait for reply and check sync ipc link")
1261 {
1262 	pthread_t thread;
1263 	pthread_attr_t attr;
1264 	unsigned long expected_result = 1;
1265 
1266 	pthread_attr_init(&attr);
1267 	pthread_create(&thread, &attr, qos_client_send_sync_msg_and_test_link, (void *)expected_result);
1268 
1269 	sleep(HELPER_TIMEOUT_SECS);
1270 }
1271 
1272 T_HELPER_DECL(qos_client_send_sync_msg_with_link_check_incorrect_server,
1273     "Send sync message, wait for reply and check sync ipc link")
1274 {
1275 	pthread_t thread;
1276 	pthread_attr_t attr;
1277 	unsigned long expected_result = 0;
1278 
1279 	pthread_attr_init(&attr);
1280 	pthread_create(&thread, &attr, qos_client_send_sync_msg_and_test_link, (void *)expected_result);
1281 
1282 	sleep(HELPER_TIMEOUT_SECS);
1283 }
1284 
1285 T_HELPER_DECL(qos_client_send_2sync_msg_with_link_check_correct_server,
1286     "Send sync message, wait for reply and check sync ipc link")
1287 {
1288 	pthread_t thread;
1289 	pthread_attr_t attr;
1290 	unsigned long expected_result = 1;
1291 
1292 	pthread_attr_init(&attr);
1293 	pthread_create(&thread, &attr, qos_client_send_2sync_msg_and_test_link, (void *)expected_result);
1294 
1295 	sleep(HELPER_TIMEOUT_SECS);
1296 }
1297 
1298 T_HELPER_DECL(qos_client_send_2sync_msg_with_link_check_incorrect_server,
1299     "Send sync message, wait for reply and check sync ipc link")
1300 {
1301 	pthread_t thread;
1302 	pthread_attr_t attr;
1303 	unsigned long expected_result = 0;
1304 
1305 	pthread_attr_init(&attr);
1306 	pthread_create(&thread, &attr, qos_client_send_2sync_msg_and_test_link, (void *)expected_result);
1307 
1308 	sleep(HELPER_TIMEOUT_SECS);
1309 }
1310 
1311 static void *
qos_client_send_sync_msg(void * arg __unused)1312 qos_client_send_sync_msg(void *arg __unused)
1313 {
1314 	mach_port_t qos_send_port;
1315 	mach_port_t special_reply_port;
1316 
1317 	kern_return_t kr = bootstrap_look_up(bootstrap_port,
1318 	    KEVENT_QOS_SERVICE_NAME, &qos_send_port);
1319 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
1320 
1321 	special_reply_port = thread_get_special_reply_port();
1322 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port), "get_thread_special_reply_port");
1323 
1324 	/* Send the message to msg port */
1325 	send(qos_send_port, special_reply_port, MACH_PORT_NULL,
1326 	    g_expected_qos[ENV_QOS_AFTER_OVERRIDE], 0);
1327 
1328 	/* wait for the reply */
1329 	receive(special_reply_port, qos_send_port);
1330 
1331 	T_LOG("Client done sending messages, now waiting for server to end the test");
1332 	sleep(2 * SEND_TIMEOUT_SECS);
1333 
1334 	T_ASSERT_FAIL("client timed out");
1335 	return NULL;
1336 }
1337 
1338 T_HELPER_DECL(qos_client_send_sync_msg_with_pri,
1339     "Send sync message and wait for reply")
1340 {
1341 	thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE], qos_client_send_sync_msg);
1342 	sleep(HELPER_TIMEOUT_SECS);
1343 }
1344 
1345 static void *
qos_client_kernel_upcall_send_sync_msg(void * arg __unused)1346 qos_client_kernel_upcall_send_sync_msg(void *arg __unused)
1347 {
1348 	mach_port_t qos_send_port;
1349 
1350 	kern_return_t kr = bootstrap_look_up(bootstrap_port,
1351 	    KEVENT_QOS_SERVICE_NAME, &qos_send_port);
1352 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
1353 
1354 	/* Call task_test_sync_upcall to perform a sync kernel upcall */
1355 	kr = task_test_sync_upcall(mach_task_self(), qos_send_port);
1356 	if (kr == KERN_NOT_SUPPORTED) {
1357 		T_QUIET; T_SKIP("QOS Client Kernel Upcall test called on release kernel, skipping\n");
1358 	}
1359 
1360 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "task_test_sync_upcall");
1361 
1362 	T_LOG("Client done doing upcall, now waiting for server to end the test");
1363 	sleep(2 * SEND_TIMEOUT_SECS);
1364 
1365 	T_ASSERT_FAIL("client timed out");
1366 	return NULL;
1367 }
1368 
1369 T_HELPER_DECL(qos_client_send_kernel_upcall_sync_msg_with_pri,
1370     "Send Kernel upcall sync message and wait for reply")
1371 {
1372 	thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE], qos_client_kernel_upcall_send_sync_msg);
1373 	sleep(HELPER_TIMEOUT_SECS);
1374 }
1375 
1376 static void *
qos_client_kernel_upcall_send_async_msg(void * arg __unused)1377 qos_client_kernel_upcall_send_async_msg(void *arg __unused)
1378 {
1379 	mach_port_t qos_send_port;
1380 
1381 	kern_return_t kr = bootstrap_look_up(bootstrap_port,
1382 	    KEVENT_QOS_SERVICE_NAME, &qos_send_port);
1383 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
1384 
1385 	/* Call task_test_async_upcall_propagation to perform an async kernel upcall */
1386 	kr = task_test_async_upcall_propagation(mach_task_self(), qos_send_port, THREAD_QOS_UTILITY, USR_THROTTLE_LEVEL_TIER0);
1387 	if (kr == KERN_NOT_SUPPORTED) {
1388 		T_QUIET; T_SKIP("QOS Client Kernel Upcall test called on release kernel, skipping\n");
1389 	}
1390 
1391 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "task_test_async_upcall_propagation");
1392 
1393 	T_LOG("Client done doing upcall, now waiting for server to end the test");
1394 	sleep(2 * SEND_TIMEOUT_SECS);
1395 
1396 	T_ASSERT_FAIL("client timed out");
1397 	return NULL;
1398 }
1399 
1400 T_HELPER_DECL(qos_iotier_client_send_kernel_upcall_async_msg,
1401     "Send Kernel upcall async message")
1402 {
1403 	thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE], qos_client_kernel_upcall_send_async_msg);
1404 	sleep(HELPER_TIMEOUT_SECS);
1405 }
1406 
1407 static void *
qos_client_send_two_sync_msg_high_qos(void * arg __unused)1408 qos_client_send_two_sync_msg_high_qos(void *arg __unused)
1409 {
1410 	mach_port_t qos_send_port;
1411 	mach_port_t special_reply_port;
1412 
1413 	kern_return_t kr = bootstrap_look_up(bootstrap_port,
1414 	    KEVENT_QOS_SERVICE_NAME, &qos_send_port);
1415 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
1416 
1417 	special_reply_port = thread_get_special_reply_port();
1418 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port), "get_thread_special_reply_port");
1419 
1420 	/* Send the message to msg port */
1421 	send(qos_send_port, special_reply_port, MACH_PORT_NULL,
1422 	    g_expected_qos[ENV_QOS_AFTER_OVERRIDE], 0);
1423 
1424 	/* wait for the reply */
1425 	receive(special_reply_port, qos_send_port);
1426 
1427 	T_LOG("Client done sending messages, now waiting for server to end the test");
1428 	sleep(SEND_TIMEOUT_SECS);
1429 
1430 	T_ASSERT_FAIL("client timed out");
1431 	return NULL;
1432 }
1433 
1434 static void *
qos_client_send_two_sync_msg_low_qos(void * arg __unused)1435 qos_client_send_two_sync_msg_low_qos(void *arg __unused)
1436 {
1437 	mach_port_t qos_send_port;
1438 	mach_port_t special_reply_port;
1439 
1440 	kern_return_t kr = bootstrap_look_up(bootstrap_port,
1441 	    KEVENT_QOS_SERVICE_NAME, &qos_send_port);
1442 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
1443 
1444 	special_reply_port = thread_get_special_reply_port();
1445 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port), "get_thread_special_reply_port");
1446 
1447 	/* Send the message to msg port */
1448 	send(qos_send_port, special_reply_port, MACH_PORT_NULL,
1449 	    g_expected_qos[ENV_QOS_BEFORE_OVERRIDE], 0);
1450 
1451 	/* wait for the reply */
1452 	receive(special_reply_port, qos_send_port);
1453 
1454 	T_LOG("Client done sending messages, now waiting for server to end the test");
1455 	sleep(SEND_TIMEOUT_SECS);
1456 
1457 	T_ASSERT_FAIL("client timed out");
1458 	return NULL;
1459 }
1460 
1461 T_HELPER_DECL(qos_client_send_two_sync_msg_with_thr_pri,
1462     "Send messages sync msgs from 2 threads at given thread pri")
1463 {
1464 	thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE], qos_client_send_two_sync_msg_high_qos);
1465 	sleep(INTERMITTENT_TIMEOUT_SEC);
1466 	thread_create_at_qos(g_expected_qos[ENV_QOS_BEFORE_OVERRIDE], qos_client_send_two_sync_msg_low_qos);
1467 	sleep(HELPER_TIMEOUT_SECS);
1468 }
1469 
1470 static mach_port_t other_thread_reply_port = MACH_PORT_NULL;
1471 static void *
qos_client_destroy_other_threads_port(void * arg __unused)1472 qos_client_destroy_other_threads_port(void *arg __unused)
1473 {
1474 	T_LOG("Waiting 6 seconds before destroying other thread's reply port");
1475 	sleep(SEND_TIMEOUT_SECS);
1476 
1477 	T_LOG("Destroying other thread's special reply port ");
1478 	mach_port_destroy(mach_task_self(), other_thread_reply_port);
1479 
1480 	T_LOG("Other thread done destroying ");
1481 	sleep(3 * SEND_TIMEOUT_SECS);
1482 
1483 	T_ASSERT_FAIL("client timed out");
1484 	return NULL;
1485 }
1486 
1487 static void *
qos_client_create_sepcial_reply_and_spawn_thread(void * arg __unused)1488 qos_client_create_sepcial_reply_and_spawn_thread(void *arg __unused)
1489 {
1490 	mach_port_t qos_send_port;
1491 	mach_port_t special_reply_port;
1492 
1493 	kern_return_t kr = bootstrap_look_up(bootstrap_port,
1494 	    KEVENT_QOS_SERVICE_NAME, &qos_send_port);
1495 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
1496 
1497 	special_reply_port = thread_get_special_reply_port();
1498 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port), "get_thread_special_reply_port");
1499 
1500 	other_thread_reply_port = special_reply_port;
1501 
1502 	/* Send an async message */
1503 	send(qos_send_port, MACH_PORT_NULL, MACH_PORT_NULL,
1504 	    g_expected_qos[ENV_QOS_BEFORE_OVERRIDE], 0);
1505 
1506 	/* Send the sync ipc message */
1507 	send(qos_send_port, special_reply_port, MACH_PORT_NULL,
1508 	    g_expected_qos[ENV_QOS_BEFORE_OVERRIDE], 0);
1509 
1510 	/* Create a new thread to send the sync message on our special reply port */
1511 	thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE], qos_client_destroy_other_threads_port);
1512 
1513 	/* Client starting to receive message */
1514 	receive(special_reply_port, qos_send_port);
1515 
1516 	sleep(3 * SEND_TIMEOUT_SECS);
1517 
1518 	T_ASSERT_FAIL("client timed out");
1519 	return NULL;
1520 }
1521 
1522 T_HELPER_DECL(qos_client_send_two_msg_and_destroy,
1523     "Send a message with another threads special reply port while that thread destroys the port")
1524 {
1525 	thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE], qos_client_create_sepcial_reply_and_spawn_thread);
1526 	sleep(HELPER_TIMEOUT_SECS);
1527 }
1528 
1529 static mach_port_t send_complex_connection_port = MACH_PORT_NULL;
1530 
1531 static void *
qos_client_send_complex_msg_to_service_port(void * arg __unused)1532 qos_client_send_complex_msg_to_service_port(void *arg __unused)
1533 {
1534 	mach_port_t svc_port, tsr_port, conn_port;
1535 	kern_return_t kr;
1536 
1537 	kr = bootstrap_look_up(bootstrap_port, KEVENT_QOS_SERVICE_NAME, &svc_port);
1538 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
1539 
1540 	tsr_port = thread_get_special_reply_port();
1541 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(tsr_port), "get_thread_special_reply_port");
1542 
1543 	conn_port = send_complex_connection_port;
1544 
1545 	T_LOG("Sending to the service port with a sync IPC");
1546 	send(svc_port, tsr_port, conn_port,
1547 	    g_expected_qos[ENV_QOS_BEFORE_OVERRIDE],
1548 	    MACH_SEND_PROPAGATE_QOS);
1549 
1550 	receive(tsr_port, svc_port);
1551 
1552 	sleep(3 * SEND_TIMEOUT_SECS);
1553 
1554 	T_ASSERT_FAIL("client timed out");
1555 	return NULL;
1556 }
1557 
1558 static void *
qos_client_send_to_connection_then_service_port(void * arg __unused)1559 qos_client_send_to_connection_then_service_port(void *arg __unused)
1560 {
1561 	mach_port_t tsr_port, conn_port;
1562 	mach_port_options_t opts = {
1563 		.flags = MPO_INSERT_SEND_RIGHT,
1564 	};
1565 	kern_return_t kr;
1566 
1567 	kr = mach_port_construct(mach_task_self(), &opts, 0ull, &conn_port);
1568 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct");
1569 	send_complex_connection_port = conn_port;
1570 
1571 	tsr_port = thread_get_special_reply_port();
1572 	T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(tsr_port), "get_thread_special_reply_port");
1573 
1574 	T_LOG("Sending to the connection port with a sync IPC");
1575 	send(conn_port, tsr_port, MACH_PORT_NULL,
1576 	    g_expected_qos[ENV_QOS_BEFORE_OVERRIDE],
1577 	    MACH_SEND_PROPAGATE_QOS);
1578 
1579 	thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE],
1580 	    qos_client_send_complex_msg_to_service_port);
1581 
1582 	receive(tsr_port, conn_port);
1583 
1584 	sleep(3 * SEND_TIMEOUT_SECS);
1585 
1586 	T_ASSERT_FAIL("client timed out");
1587 	return NULL;
1588 }
1589 
1590 T_HELPER_DECL(qos_client_send_complex_msg_with_pri,
1591     "Send a message with several ports causing links")
1592 {
1593 	thread_create_at_qos(g_expected_qos[ENV_QOS_BEFORE_OVERRIDE],
1594 	    qos_client_send_to_connection_then_service_port);
1595 	sleep(HELPER_TIMEOUT_SECS);
1596 }
1597 
1598 static void
run_client_server(const char * server_name,const char * client_name,qos_class_t qos[],const char * qos_name[],const char * wl_function)1599 run_client_server(const char *server_name, const char *client_name, qos_class_t qos[],
1600     const char *qos_name[], const char *wl_function)
1601 {
1602 	char *env[2 * ENV_VAR_QOS + ENV_VAR_FUNCTION + 1];
1603 	env_set_qos(env, qos, qos_name, wl_function);
1604 
1605 	for (int i = 0; i < ENV_VAR_QOS; i++) {
1606 		g_expected_qos[i] = qos[i];
1607 		g_expected_qos_name[i] = qos_name[i];
1608 	}
1609 
1610 	dt_helper_t helpers[] = {
1611 		dt_launchd_helper_domain("com.apple.xnu.test.kevent_qos.plist",
1612 	    server_name, env, LAUNCH_SYSTEM_DOMAIN),
1613 		dt_fork_helper(client_name)
1614 	};
1615 	dt_run_helpers(helpers, 2, HELPER_TIMEOUT_SECS);
1616 }
1617 
1618 #pragma mark Mach receive - kevent_qos
1619 
1620 static void
expect_kevent_id_recv(mach_port_t port,qos_class_t qos[],const char * qos_name[],const char * wl_function)1621 expect_kevent_id_recv(mach_port_t port, qos_class_t qos[], const char *qos_name[], const char *wl_function)
1622 {
1623 	int r;
1624 
1625 	/* Qos expected by workloop thread */
1626 	for (int i = 0; i < ENV_VAR_QOS; i++) {
1627 		g_expected_qos[i] = qos[i];
1628 		g_expected_qos_name[i] = qos_name[i];
1629 	}
1630 
1631 	if (strcmp(wl_function, "workloop_cb_test_intransit") == 0) {
1632 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1633 			    worker_cb, event_cb,
1634 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_intransit, 0, 0), NULL);
1635 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send") == 0) {
1636 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1637 			    worker_cb, event_cb,
1638 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send, 0, 0), NULL);
1639 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_and_enable") == 0) {
1640 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1641 			    worker_cb, event_cb,
1642 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_and_enable, 0, 0), NULL);
1643 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_and_enable_handoff") == 0) {
1644 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1645 			    worker_cb, event_cb,
1646 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_and_enable_handoff, 0, 0), NULL);
1647 	} else if (strcmp(wl_function, "workloop_cb_test_send_two_sync") == 0) {
1648 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1649 			    worker_cb, event_cb,
1650 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_send_two_sync, 0, 0), NULL);
1651 	} else if (strcmp(wl_function, "workloop_cb_test_two_send_and_destroy") == 0) {
1652 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1653 			    worker_cb, event_cb,
1654 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_two_send_and_destroy, 0, 0), NULL);
1655 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_reply") == 0) {
1656 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1657 			    worker_cb, event_cb,
1658 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_reply, 0, 0), NULL);
1659 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_deallocate") == 0) {
1660 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1661 			    worker_cb, event_cb,
1662 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_deallocate, 0, 0), NULL);
1663 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_reply_kevent") == 0) {
1664 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1665 			    worker_cb, event_cb,
1666 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_reply_kevent, 0, 0), NULL);
1667 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_reply_kevent_pthread") == 0) {
1668 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1669 			    worker_cb, event_cb,
1670 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_reply_kevent_pthread, 0, 0), NULL);
1671 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_kevent_reply") == 0) {
1672 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1673 			    worker_cb, event_cb,
1674 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_kevent_reply, 0, 0), NULL);
1675 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_do_nothing") == 0) {
1676 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1677 			    worker_cb, event_cb,
1678 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_do_nothing, 0, 0), NULL);
1679 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_do_nothing_kevent_pthread") == 0) {
1680 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1681 			    worker_cb, event_cb,
1682 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_do_nothing_kevent_pthread, 0, 0), NULL);
1683 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_do_nothing_exit") == 0) {
1684 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1685 			    worker_cb, event_cb,
1686 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_do_nothing_exit, 0, 0), NULL);
1687 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_reply_kevent_reply_kevent") == 0) {
1688 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1689 			    worker_cb, event_cb,
1690 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_reply_kevent_reply_kevent, 0, 0), NULL);
1691 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_kevent_reply_reply_kevent") == 0) {
1692 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1693 			    worker_cb, event_cb,
1694 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_kevent_reply_reply_kevent, 0, 0), NULL);
1695 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_kevent_reply_kevent_reply") == 0) {
1696 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1697 			    worker_cb, event_cb,
1698 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_kevent_reply_kevent_reply, 0, 0), NULL);
1699 	} else if (strcmp(wl_function, "workloop_cb_test_sync_send_reply_kevent_kevent_reply") == 0) {
1700 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1701 			    worker_cb, event_cb,
1702 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_sync_send_reply_kevent_kevent_reply, 0, 0), NULL);
1703 	} else if (strcmp(wl_function, "workloop_cb_test_kernel_sync_send") == 0) {
1704 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1705 			    worker_cb, event_cb,
1706 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_kernel_sync_send, 0, 0), NULL);
1707 	} else if (strcmp(wl_function, "workloop_cb_test_kernel_async_send") == 0) {
1708 		T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1709 			    worker_cb, event_cb,
1710 			    (pthread_workqueue_function_workloop_t)workloop_cb_test_kernel_async_send, 0, 0), NULL);
1711 	} else {
1712 		T_ASSERT_FAIL("no workloop function specified \n");
1713 	}
1714 
1715 	struct kevent_qos_s kev = {
1716 		.ident = port,
1717 		.filter = EVFILT_MACHPORT,
1718 		.flags = EV_ADD | EV_UDATA_SPECIFIC | EV_DISPATCH | EV_VANISHED,
1719 		.fflags = (MACH_RCV_MSG | MACH_RCV_VOUCHER | MACH_RCV_LARGE | MACH_RCV_LARGE_IDENTITY |
1720 	    MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV) |
1721 	    MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)),
1722 		.data = 1,
1723 		.qos = (int32_t)_pthread_qos_class_encode(qos[ENV_QOS_QUEUE_OVERRIDE], 0, 0)
1724 	};
1725 
1726 	struct kevent_qos_s kev_err = { 0 };
1727 
1728 	/* Setup workloop for mach msg rcv */
1729 	r = kevent_id(25, &kev, 1, &kev_err, 1, NULL,
1730 	    NULL, KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_ERROR_EVENTS);
1731 
1732 	T_QUIET; T_ASSERT_POSIX_SUCCESS(r, "kevent_id");
1733 	T_QUIET; T_ASSERT_EQ(r, 0, "no errors returned from kevent_id");
1734 	sleep(HELPER_TIMEOUT_SECS);
1735 }
1736 
1737 T_HELPER_DECL(server_kevent_id,
1738     "Reply with the QoS that a dispatch source event handler ran with")
1739 {
1740 	qos_class_t qos[ENV_VAR_QOS];
1741 	const char *qos_name[ENV_VAR_QOS];
1742 	const char *wl_function;
1743 	environ_get_qos(qos, qos_name, &wl_function);
1744 
1745 	expect_kevent_id_recv(get_server_port(), qos, qos_name, wl_function);
1746 	sleep(HELPER_TIMEOUT_SECS);
1747 	T_ASSERT_FAIL("should receive a message within %d seconds",
1748 	    RECV_TIMEOUT_SECS);
1749 }
1750 
1751 static void *
special_reply_port_thread(void * ctxt)1752 special_reply_port_thread(void *ctxt)
1753 {
1754 	kern_return_t ret;
1755 	mach_port_t rcv_port = *(mach_port_t *)ctxt;
1756 	struct test_msg rcv_msg = {
1757 		.header = {
1758 			.msgh_remote_port = MACH_PORT_NULL,
1759 			.msgh_local_port  = rcv_port,
1760 			.msgh_size        = sizeof(rcv_msg),
1761 		},
1762 	};
1763 
1764 	ret = mach_msg(&rcv_msg.header, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0,
1765 	    rcv_msg.header.msgh_size, rcv_port, 1000, MACH_PORT_NULL);
1766 
1767 	T_EXPECT_EQ(ret, MACH_RCV_TIMED_OUT, "receive should not panic");
1768 
1769 	*(mach_port_t *)ctxt = MACH_PORT_NULL;
1770 
1771 	sleep(1); // give some time to pthread_exit
1772 
1773 	ret = mach_msg(&rcv_msg.header, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0,
1774 	    rcv_msg.header.msgh_size, rcv_port, 1000, MACH_PORT_NULL);
1775 
1776 	T_EXPECT_EQ(ret, MACH_RCV_TIMED_OUT, "receive should not panic");
1777 
1778 	T_END;
1779 }
1780 
1781 T_DECL(special_reply_port, "basic special reply port robustness checks",
1782     T_META_RUN_CONCURRENTLY(true), T_META_TAG_VM_PREFERRED)
1783 {
1784 	pthread_t thread;
1785 	mach_port_t srp = thread_get_special_reply_port();
1786 
1787 	pthread_create(&thread, NULL, special_reply_port_thread, &srp);
1788 
1789 	while (srp) {
1790 		usleep(1000);
1791 	}
1792 
1793 	pthread_exit(NULL);
1794 }
1795 
1796 #define TEST_QOS(server_name, client_name, name, wl_function_name, qos_bo, qos_bo_name, qos_qo, qos_qo_name, qos_ao, qos_ao_name) \
1797 	T_DECL(server_kevent_id_##name, \
1798 	                "Event delivery at " qos_ao_name " QoS using a kevent_id", \
1799 	                T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED) \
1800 	{ \
1801 	        qos_class_t qos_array[ENV_VAR_QOS] = {qos_bo, qos_qo, qos_ao};  \
1802 	        const char *qos_name_array[ENV_VAR_QOS] = {qos_bo_name, qos_qo_name, qos_ao_name}; \
1803 	        run_client_server(server_name, client_name, qos_array, qos_name_array, wl_function_name); \
1804 	}
1805 /*
1806  * Test 1: Test special reply port SPI
1807  *
1808  * Create thread special reply port and check any subsequent calls to
1809  * the same should return MACH_PORT_NULL, unless the reply port is destroyed.
1810  */
1811 TEST_QOS("server_kevent_id", "qos_get_special_reply_port", special_reply_port, "workloop_cb_test_intransit",
1812     QOS_CLASS_DEFAULT, "default",
1813     QOS_CLASS_DEFAULT, "default",
1814     QOS_CLASS_DEFAULT, "default")
1815 
1816 /*
1817  * Test 2: Test sync ipc send to an in-transit port
1818  *
1819  * Send a sync ipc message (at IN qos) to an in-transit port enqueued in a port
1820  * attached to a workloop. Test that the servicer of the workloop gets
1821  * sync ipc override.
1822  */
1823 TEST_QOS("server_kevent_id", "qos_client_send_to_intransit_with_thr_pri", transit_IN, "workloop_cb_test_intransit",
1824     QOS_CLASS_DEFAULT, "default",
1825     QOS_CLASS_MAINTENANCE, "maintenance",
1826     QOS_CLASS_USER_INITIATED, "user initiated")
1827 
1828 /*
1829  * Test 3: Test sync ipc send to an in-transit port
1830  *
1831  * Send a sync ipc message (at UI qos) to an in-transit port enqueued in a port
1832  * attached to a workloop. Test that the servicer of the workloop gets
1833  * sync ipc override.
1834  */
1835 TEST_QOS("server_kevent_id", "qos_client_send_to_intransit_with_thr_pri", transit_UI, "workloop_cb_test_intransit",
1836     QOS_CLASS_USER_INITIATED, "user initiated",
1837     QOS_CLASS_MAINTENANCE, "maintenance",
1838     QOS_CLASS_USER_INTERACTIVE, "user initiated with 47 basepri promotion")
1839 
1840 /*
1841  * Test 4: Test starting a sync rcv overrides the servicer
1842  *
1843  * Send an async message to a port and then start waiting on
1844  * the port in mach msg rcv (at IN qos) with sync wait and test if the
1845  * servicer of the workloop gets sync ipc override.
1846  */
1847 TEST_QOS("server_kevent_id", "qos_client_send_sync_and_sync_rcv", rcv_IN, "workloop_cb_test_intransit",
1848     QOS_CLASS_DEFAULT, "default",
1849     QOS_CLASS_MAINTENANCE, "maintenance",
1850     QOS_CLASS_USER_INITIATED, "user initiated")
1851 
1852 /*
1853  * Test 5: Test starting a sync rcv overrides the servicer
1854  *
1855  * Send an async message to a port and then start waiting on
1856  * the port in mach msg rcv (at UI qos) with sync wait and test if the
1857  * servicer of the workloop gets sync ipc override.
1858  */
1859 TEST_QOS("server_kevent_id", "qos_client_send_sync_and_sync_rcv", rcv_UI, "workloop_cb_test_intransit",
1860     QOS_CLASS_DEFAULT, "default",
1861     QOS_CLASS_MAINTENANCE, "maintenance",
1862     QOS_CLASS_USER_INTERACTIVE, "user interactive with 47 basepri promotion")
1863 
1864 /*
1865  * Test 6: test sending sync ipc message (at IN qos) to port will override the servicer
1866  *
1867  * Send a message with sync ipc override to a port and check if the servicer
1868  * of the workloop on other side gets sync ipc override.
1869  */
1870 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_pri", send_sync_IN, "workloop_cb_test_sync_send",
1871     QOS_CLASS_DEFAULT, "default",
1872     QOS_CLASS_MAINTENANCE, "maintenance",
1873     QOS_CLASS_USER_INITIATED, "user initiated")
1874 
1875 /*
1876  * Test 7: test sending sync ipc message (at UI qos) to port will override the servicer
1877  *
1878  * Send a message with sync ipc override to a port and check if the servicer
1879  * of the workloop on other side gets sync ipc override.
1880  */
1881 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_pri", send_sync_UI, "workloop_cb_test_sync_send",
1882     QOS_CLASS_MAINTENANCE, "maintenance",
1883     QOS_CLASS_MAINTENANCE, "maintenance",
1884     QOS_CLASS_USER_INTERACTIVE, "user initiated with 47 basepri promotion")
1885 
1886 /*
1887  * Test 8: test enabling a knote in workloop handler will drop the sync ipc override of delivered message
1888  *
1889  * Send a sync ipc message to port and check the servicer of the workloop
1890  * on other side gets sync ipc override and once the handler enables the knote,
1891  * that sync ipc override is dropped.
1892  */
1893 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_pri", send_sync_UI_and_enable, "workloop_cb_test_sync_send_and_enable",
1894     QOS_CLASS_DEFAULT, "default",
1895     QOS_CLASS_DEFAULT, "default",
1896     QOS_CLASS_USER_INTERACTIVE, "user initiated with 47 basepri promotion")
1897 
1898 /*
1899  * Test 9: test returning to begin processing drops sync ipc override of delivered message
1900  *
1901  * Send a sync ipc message and check if enabling the knote clears the override of
1902  * the delivered message, but should still have the override of an enqueued message.
1903  */
1904 TEST_QOS("server_kevent_id", "qos_client_send_two_sync_msg_with_thr_pri", send_two_sync_UI, "workloop_cb_test_send_two_sync",
1905     QOS_CLASS_BACKGROUND, "background",
1906     QOS_CLASS_MAINTENANCE, "maintenance",
1907     QOS_CLASS_USER_INTERACTIVE, "user initiated with 47 basepri promotion")
1908 
1909 /*
1910  * Test 10: test destroying the special reply port drops the override
1911  *
1912  * Send an async messages and a sync ipc message, the workloop handler
1913  * should get a sync ipc override, now test if destroying the special
1914  * reply port drops the sync ipc override on the servicer.
1915  */
1916 TEST_QOS("server_kevent_id", "qos_client_send_two_msg_and_destroy", send_two_UI_and_destroy, "workloop_cb_test_two_send_and_destroy",
1917     QOS_CLASS_BACKGROUND, "background",
1918     QOS_CLASS_MAINTENANCE, "maintenance",
1919     QOS_CLASS_USER_INTERACTIVE, "user initiated with 47 basepri promotion")
1920 
1921 /*
1922  * Test 11: test sending two ports with chaining
1923  *
1924  * Send a sync IPC to a connection port, which itself is embedded in a message
1925  * sent as a sync IPC to a service port.
1926  */
1927 TEST_QOS("server_kevent_id", "qos_client_send_complex_msg_with_pri", send_complex_sync_UI_and_enable, "workloop_cb_test_sync_send_and_enable",
1928     QOS_CLASS_USER_INITIATED, "user initiated",
1929     QOS_CLASS_USER_INITIATED, "user initiated",
1930     QOS_CLASS_USER_INTERACTIVE, "user initiated with 47 basepri promotion")
1931 
1932 /*
1933  * Test 12: test sending two ports with chaining
1934  *
1935  * Send a sync IPC to a connection port, which itself is embedded in a message
1936  * sent as a sync IPC to a service port.
1937  */
1938 TEST_QOS("server_kevent_id", "qos_client_send_complex_msg_with_pri", send_complex_sync_UI_and_enable_and_handoff, "workloop_cb_test_sync_send_and_enable_handoff",
1939     QOS_CLASS_USER_INITIATED, "user initiated",
1940     QOS_CLASS_USER_INITIATED, "user initiated",
1941     QOS_CLASS_USER_INTERACTIVE, "user initiated with 47 basepri promotion")
1942 
1943 /*
1944  * Test 13: test changing qos of a thread to trigger turnstile push
1945  *
1946  * Send a sync IPC to a service port and change the qos of the blocked thread
1947  * to verify that changing qos triggers a turnstile push.
1948  */
1949 TEST_QOS("server_kevent_id", "qos_client_sync_rcv_qos_change", qos_change_to_IN, "workloop_cb_test_intransit",
1950     QOS_CLASS_DEFAULT, "default",
1951     QOS_CLASS_MAINTENANCE, "maintenance",
1952     QOS_CLASS_USER_INITIATED, "user initiated")
1953 
1954 /*
1955  * Test 14 - 21
1956  *
1957  * Test single sync ipc link with server that breaks/preserves the link in different ways.
1958  */
1959 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_link_check_correct_server", send_sync_link_correct_server_s, "workloop_cb_test_sync_send_reply",
1960     QOS_CLASS_DEFAULT, "default",
1961     QOS_CLASS_DEFAULT, "default",
1962     QOS_CLASS_DEFAULT, "default")
1963 
1964 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_link_check_correct_server", send_sync_link_correct_server_d, "workloop_cb_test_sync_send_deallocate",
1965     QOS_CLASS_DEFAULT, "default",
1966     QOS_CLASS_DEFAULT, "default",
1967     QOS_CLASS_DEFAULT, "default")
1968 
1969 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_link_check_correct_server", send_sync_link_correct_server_sk, "workloop_cb_test_sync_send_reply_kevent",
1970     QOS_CLASS_DEFAULT, "default",
1971     QOS_CLASS_DEFAULT, "default",
1972     QOS_CLASS_DEFAULT, "default")
1973 
1974 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_link_check_correct_server", send_sync_link_correct_server_skp, "workloop_cb_test_sync_send_reply_kevent_pthread",
1975     QOS_CLASS_DEFAULT, "default",
1976     QOS_CLASS_DEFAULT, "default",
1977     QOS_CLASS_DEFAULT, "default")
1978 
1979 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_link_check_incorrect_server", send_sync_link_incorrect_server_ks, "workloop_cb_test_sync_send_kevent_reply",
1980     QOS_CLASS_DEFAULT, "default",
1981     QOS_CLASS_DEFAULT, "default",
1982     QOS_CLASS_DEFAULT, "default")
1983 
1984 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_link_check_correct_server", send_sync_link_correct_server_n, "workloop_cb_test_sync_send_do_nothing",
1985     QOS_CLASS_DEFAULT, "default",
1986     QOS_CLASS_DEFAULT, "default",
1987     QOS_CLASS_DEFAULT, "default")
1988 
1989 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_link_check_incorrect_server", send_sync_link_incorrect_server_kp, "workloop_cb_test_sync_send_do_nothing_kevent_pthread",
1990     QOS_CLASS_DEFAULT, "default",
1991     QOS_CLASS_DEFAULT, "default",
1992     QOS_CLASS_DEFAULT, "default")
1993 
1994 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_link_check_correct_server", send_sync_link_correct_server_e, "workloop_cb_test_sync_send_do_nothing_exit",
1995     QOS_CLASS_DEFAULT, "default",
1996     QOS_CLASS_DEFAULT, "default",
1997     QOS_CLASS_DEFAULT, "default")
1998 
1999 /*
2000  * Test 22 - 25
2001  *
2002  * Test sequential sync ipc link with server that breaks/preserves the link.
2003  */
2004 TEST_QOS("server_kevent_id", "qos_client_send_2sync_msg_with_link_check_correct_server", send_2sync_link_correct_server_sksk, "workloop_cb_test_sync_send_reply_kevent_reply_kevent",
2005     QOS_CLASS_DEFAULT, "default",
2006     QOS_CLASS_DEFAULT, "default",
2007     QOS_CLASS_DEFAULT, "default")
2008 
2009 TEST_QOS("server_kevent_id", "qos_client_send_2sync_msg_with_link_check_incorrect_server", send_2sync_link_incorrect_server_kssk, "workloop_cb_test_sync_send_kevent_reply_reply_kevent",
2010     QOS_CLASS_DEFAULT, "default",
2011     QOS_CLASS_DEFAULT, "default",
2012     QOS_CLASS_DEFAULT, "default")
2013 
2014 TEST_QOS("server_kevent_id", "qos_client_send_2sync_msg_with_link_check_incorrect_server", send_2sync_link_incorrect_server_ksks, "workloop_cb_test_sync_send_kevent_reply_kevent_reply",
2015     QOS_CLASS_DEFAULT, "default",
2016     QOS_CLASS_DEFAULT, "default",
2017     QOS_CLASS_DEFAULT, "default")
2018 
2019 TEST_QOS("server_kevent_id", "qos_client_send_2sync_msg_with_link_check_incorrect_server", send_2sync_link_incorrect_server_skks, "workloop_cb_test_sync_send_reply_kevent_kevent_reply",
2020     QOS_CLASS_DEFAULT, "default",
2021     QOS_CLASS_DEFAULT, "default",
2022     QOS_CLASS_DEFAULT, "default")
2023 
2024 /*
2025  * Test 26: test sending sync ipc from kernel (at IN qos) to port will override the servicer
2026  *
2027  * Do a kernel upcall at IN qos to a port and check if the servicer
2028  * of the workloop on other side gets sync ipc override.
2029  */
2030 TEST_QOS("server_kevent_id", "qos_client_send_kernel_upcall_sync_msg_with_pri", kernel_send_sync_IN, "workloop_cb_test_kernel_sync_send",
2031     QOS_CLASS_MAINTENANCE, "maintenance",
2032     QOS_CLASS_MAINTENANCE, "maintenance",
2033     QOS_CLASS_USER_INITIATED, "user initiated")
2034 
2035 /*
2036  * Test 27: test sending async ipc from kernel (at IN qos and Tier 0 iotier) to port will override the servicer
2037  *
2038  * Do a kernel upcall at IN qos and Tier 0 iotier to a port and check if
2039  * the servicer of the workloop on the other side gets the ipc override.
2040  */
2041 TEST_QOS("server_kevent_id", "qos_iotier_client_send_kernel_upcall_async_msg", kernel_send_async_IN, "workloop_cb_test_kernel_async_send",
2042     QOS_CLASS_MAINTENANCE, "maintenance",
2043     QOS_CLASS_MAINTENANCE, "maintenance",
2044     QOS_CLASS_UTILITY, "utility")
2045