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