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