2 * kevent_qos: Tests Synchronous IPC QOS override.
9 #include <darwintest.h>
10 #include <darwintest_multiprocess.h>
12 #include <dispatch/dispatch.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>
22 #include <sys/event.h>
24 #include <crt_externs.h>
25 #include <mach/mach_port.h>
26 #include <mach/mach_sync_ipc.h>
28 T_GLOBAL_META(T_META_NAMESPACE("xnu.kevent_qos"));
30 #define ARRAYLEN(arr) (sizeof(arr) / sizeof(arr[0]))
32 #define INTERMITTENT_TIMEOUT_SEC (3)
33 #define RECV_TIMEOUT_SECS (4)
34 #define SEND_TIMEOUT_SECS (6)
35 #define HELPER_TIMEOUT_SECS (15)
37 #define ENV_VAR_QOS (3)
38 static const char *qos_env
[ENV_VAR_QOS
] = {"XNU_TEST_QOS_BO", "XNU_TEST_QOS_QO", "XNU_TEST_QOS_AO"};
39 static const char *qos_name_env
[ENV_VAR_QOS
] = {"XNU_TEST_QOS_NAME_BO", "XNU_TEST_QOS_NAME_QO", "XNU_TEST_QOS_NAME_AO"};
41 #define ENV_VAR_FUNCTION (1)
42 static const char *wl_function_name
= "XNU_TEST_WL_FUNCTION";
44 static qos_class_t g_expected_qos
[ENV_VAR_QOS
];
45 static const char *g_expected_qos_name
[ENV_VAR_QOS
];
47 #define ENV_QOS_BEFORE_OVERRIDE (0)
48 #define ENV_QOS_QUEUE_OVERRIDE (1)
49 #define ENV_QOS_AFTER_OVERRIDE (2)
52 mach_msg_header_t header
;
54 mach_msg_port_descriptor_t port_descriptor
;
55 mach_msg_option_t opts
;
56 mach_msg_priority_t qos
;
59 #pragma mark pthread callbacks
62 thread_create_at_qos(qos_class_t qos
, void * (*function
)(void *));
64 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
);
66 enable_kevent(uint64_t *workloop_id
, unsigned long long port
);
68 populate_kevent(struct kevent_qos_s
*kev
, unsigned long long port
);
71 worker_cb(pthread_priority_t __unused priority
)
73 T_FAIL("a worker thread was created");
77 event_cb(void ** __unused events
, int * __unused nevents
)
79 T_FAIL("a kevent routine was called instead of workloop");
83 get_user_promotion_basepri(void)
85 mach_msg_type_number_t count
= THREAD_POLICY_STATE_COUNT
;
86 struct thread_policy_state thread_policy
;
87 boolean_t get_default
= FALSE
;
88 mach_port_t thread_port
= pthread_mach_thread_np(pthread_self());
90 kern_return_t kr
= thread_policy_get(thread_port
, THREAD_POLICY_STATE
,
91 (thread_policy_t
)&thread_policy
, &count
, &get_default
);
92 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "thread_policy_get");
93 return thread_policy
.thps_user_promotion_basepri
;
96 #define EXPECT_QOS_EQ(qos, ...) do { \
97 if ((qos) == QOS_CLASS_USER_INTERACTIVE) { \
98 T_EXPECT_EFFECTIVE_QOS_EQ(QOS_CLASS_USER_INITIATED, __VA_ARGS__); \
99 T_EXPECT_EQ(47u, get_user_promotion_basepri(), __VA_ARGS__); \
101 T_EXPECT_EFFECTIVE_QOS_EQ(qos, __VA_ARGS__); \
105 #define EXPECT_TEST_MSG(_ke) do { \
106 struct kevent_qos_s *ke = _ke; \
107 mach_msg_header_t *hdr = (mach_msg_header_t *)ke->ext[0]; \
108 T_ASSERT_NOTNULL(hdr, "has a message"); \
109 T_ASSERT_EQ(hdr->msgh_size, (uint32_t)sizeof(struct test_msg), "of the right size"); \
110 struct test_msg *tmsg = (struct test_msg *)hdr; \
111 if (tmsg->opts & MACH_SEND_PROPAGATE_QOS) { \
112 T_EXPECT_EQ(tmsg->qos, ((uint32_t)(ke->ext[2] >> 32)), \
113 "propagation works"); \
118 * Basic WL handler callback, it sleeps for n seconds and then checks the
119 * effective Qos of the servicer thread.
122 workloop_cb_test_intransit(uint64_t *workloop_id __unused
, void **eventslist
, int *events
)
124 T_LOG("Workloop handler workloop_cb_test_intransit called. "
125 "Will wait for %d seconds to make sure client enqueues the sync msg \n",
126 2 * RECV_TIMEOUT_SECS
);
128 EXPECT_TEST_MSG(*eventslist
);
130 /* Wait for the client to send the high priority message to override the qos */
131 sleep(2 * RECV_TIMEOUT_SECS
);
133 /* Skip the test if we can't check Qos */
134 if (geteuid() != 0) {
135 T_SKIP("kevent_qos test requires root privileges to run.");
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
]);
147 * WL handler which checks if the servicer thread has correct Qos.
150 workloop_cb_test_sync_send(uint64_t *workloop_id __unused
, void **eventslist
, int *events
)
152 T_LOG("Workloop handler workloop_cb_test_sync_send called");
154 EXPECT_TEST_MSG(*eventslist
);
156 if (geteuid() != 0) {
157 T_SKIP("kevent_qos test requires root privileges to run.");
160 /* The effective Qos should be the one expected after override */
161 EXPECT_QOS_EQ(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
],
162 "dispatch_source event handler QoS should be %s", g_expected_qos_name
[ENV_QOS_AFTER_OVERRIDE
]);
169 * WL handler which checks the overridden Qos and then enables the knote and checks
170 * for the Qos again if that dropped the sync ipc override.
173 workloop_cb_test_sync_send_and_enable(uint64_t *workloop_id
, struct kevent_qos_s
**eventslist
, int *events
)
175 unsigned override_priority
;
176 unsigned reenable_priority
;
178 T_LOG("Workloop handler workloop_cb_test_sync_send_and_enable called");
180 EXPECT_TEST_MSG(*eventslist
);
182 if (geteuid() != 0) {
183 T_SKIP("kevent_qos test requires root privileges to run.");
186 /* The effective Qos should be the one expected after override */
187 EXPECT_QOS_EQ(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
],
188 "dispatch_source event handler QoS should be %s", g_expected_qos_name
[ENV_QOS_AFTER_OVERRIDE
]);
190 /* Snapshot the current override priority */
191 override_priority
= get_user_promotion_basepri();
193 /* Enable the knote */
194 struct kevent_qos_s
*kev
= *eventslist
;
195 enable_kevent(workloop_id
, kev
->ident
);
198 * Check if the override has been dropped, check for priority instead of qos since
199 * there will be async qos push.
201 reenable_priority
= get_user_promotion_basepri();
202 T_EXPECT_LT(reenable_priority
, override_priority
,
203 "thread's current override priority %d should be less than override priority prior to enabling knote %d",
204 reenable_priority
, override_priority
);
211 * WL handler which checks the overridden Qos and then handoffs the IPC,
212 * enables the knote and checks for the Qos again that it hasn't dropped the sync ipc override.
215 workloop_cb_test_sync_send_and_enable_handoff(uint64_t *workloop_id
, struct kevent_qos_s
**eventslist
, int *events
)
217 unsigned override_priority
;
220 T_LOG("Workloop handler workloop_cb_test_sync_send_and_enable_handoff called");
222 EXPECT_TEST_MSG(*eventslist
);
224 if (geteuid() != 0) {
225 T_SKIP("kevent_qos test requires root privileges to run.");
228 /* The effective Qos should be the one expected after override */
229 EXPECT_QOS_EQ(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
],
230 "dispatch_source event handler QoS should be %s",
231 g_expected_qos_name
[ENV_QOS_AFTER_OVERRIDE
]);
233 /* Snapshot the current override priority */
234 override_priority
= get_user_promotion_basepri();
236 struct kevent_qos_s
*kev
= *eventslist
;
237 mach_msg_header_t
*hdr
= (mach_msg_header_t
*)kev
->ext
[0];
239 /* handoff the IPC */
240 struct kevent_qos_s handoff_kev
= {
241 .filter
= EVFILT_WORKLOOP
,
242 .ident
= hdr
->msgh_remote_port
,
243 .flags
= EV_ADD
| EV_DISABLE
,
244 .fflags
= 0x80000000,
247 error
= kevent_id(*workloop_id
, &handoff_kev
, 1, &handoff_kev
, 1, NULL
,
248 NULL
, KEVENT_FLAG_WORKLOOP
| KEVENT_FLAG_ERROR_EVENTS
| KEVENT_FLAG_DYNAMIC_KQ_MUST_EXIST
);
249 T_QUIET
; T_ASSERT_POSIX_SUCCESS(error
, "kevent_id");
250 T_ASSERT_EQ(0, error
, "Handed off the sync IPC");
252 /* Enable the knote */
253 enable_kevent(workloop_id
, kev
->ident
);
256 * Check if the override has not been dropped.
258 EXPECT_QOS_EQ(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
],
259 "dispatch_source event handler QoS should still be %s",
260 g_expected_qos_name
[ENV_QOS_AFTER_OVERRIDE
]);
267 * WL handler receives the first message and checks sync ipc override, then enables the knote
268 * and receives 2nd message and checks it sync ipc override.
270 static int send_two_sync_handler_called
= 0;
272 workloop_cb_test_send_two_sync(uint64_t *workloop_id __unused
, struct kevent_qos_s
**eventslist
, int *events
)
274 T_LOG("Workloop handler workloop_cb_test_send_two_sync called for %d time", send_two_sync_handler_called
+ 1);
276 EXPECT_TEST_MSG(*eventslist
);
278 if (geteuid() != 0) {
279 T_SKIP("kevent_qos test requires root privileges to run.");
282 T_LOG("Number of events received is %d\n", *events
);
284 if (send_two_sync_handler_called
== 0) {
285 /* The effective Qos should be the one expected after override */
286 EXPECT_QOS_EQ(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
],
287 "dispatch_source event handler QoS should be %s", g_expected_qos_name
[ENV_QOS_AFTER_OVERRIDE
]);
289 /* Enable the knote to get 2nd message */
290 struct kevent_qos_s
*kev
= *eventslist
;
291 uint64_t port
= kev
->ident
;
292 populate_kevent(kev
, port
);
295 EXPECT_QOS_EQ(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
],
296 "dispatch_source event handler QoS should be %s", g_expected_qos_name
[ENV_QOS_BEFORE_OVERRIDE
]);
300 send_two_sync_handler_called
++;
304 * Checks the sync ipc override and then waits for client to destroy the
305 * special reply port and checks if that removes the sync ipc override.
307 static boolean_t two_send_and_destroy_test_passed
= FALSE
;
308 static int two_send_and_destroy_handler
= 0;
310 workloop_cb_test_two_send_and_destroy(uint64_t *workloop_id __unused
, struct kevent_qos_s
**eventslist __unused
, int *events
)
312 T_LOG("Workloop handler workloop_cb_test_two_send_and_destroy called %d times", two_send_and_destroy_handler
+ 1);
314 EXPECT_TEST_MSG(*eventslist
);
316 if (geteuid() != 0) {
317 T_SKIP("kevent_qos test requires root privileges to run.");
320 if (two_send_and_destroy_handler
== 0) {
321 /* Sleep to make sure the mqueue gets full */
322 sleep(RECV_TIMEOUT_SECS
);
324 /* The effective Qos should be the one expected after override */
325 EXPECT_QOS_EQ(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
],
326 "dispatch_source event handler QoS should be %s", g_expected_qos_name
[ENV_QOS_AFTER_OVERRIDE
]);
328 sleep(SEND_TIMEOUT_SECS
);
330 /* Special reply port should have been destroyed, check Qos again */
331 EXPECT_QOS_EQ(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
],
332 "dispatch_source event handler QoS should be %s", g_expected_qos_name
[ENV_QOS_BEFORE_OVERRIDE
]);
334 two_send_and_destroy_test_passed
= TRUE
;
336 if (two_send_and_destroy_test_passed
) {
341 /* Enable the knote to get next message */
342 struct kevent_qos_s
*kev
= *eventslist
;
343 uint64_t port
= kev
->ident
;
344 populate_kevent(kev
, port
);
346 two_send_and_destroy_handler
++;
347 T_LOG("Handler returning \n");
350 static mach_port_type_t
351 get_reply_port(struct kevent_qos_s
*kev
)
353 mach_msg_header_t
*hdr
;
354 mach_port_t reply_port
;
355 mach_port_type_t type
;
358 hdr
= (void*)kev
->ext
[0];
359 T_QUIET
; T_ASSERT_NOTNULL(hdr
, "msg hdr");
361 reply_port
= hdr
->msgh_remote_port
;
362 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(reply_port
), "reply port valid");
363 kr
= mach_port_type(mach_task_self(), reply_port
, &type
);
364 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "mach_port_type");
365 T_QUIET
; T_ASSERT_TRUE(type
& MACH_PORT_TYPE_SEND_ONCE
, "send once received");
371 send_reply(mach_port_t reply_port
)
376 mach_msg_header_t header
;
379 .msgh_remote_port
= reply_port
,
380 .msgh_local_port
= MACH_PORT_NULL
,
381 .msgh_bits
= MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE
, 0),
383 .msgh_size
= sizeof(send_msg
),
387 kr
= mach_msg(&(send_msg
.header
),
389 send_msg
.header
.msgh_size
,
395 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "server mach_msg");
399 populate_kevent(struct kevent_qos_s
*kev
, unsigned long long port
)
401 memset(kev
, 0, sizeof(struct kevent_qos_s
));
403 kev
->filter
= EVFILT_MACHPORT
;
404 kev
->flags
= EV_ADD
| EV_ENABLE
| EV_UDATA_SPECIFIC
| EV_DISPATCH
| EV_VANISHED
;
405 kev
->fflags
= (MACH_RCV_MSG
| MACH_RCV_VOUCHER
| MACH_RCV_LARGE
| MACH_RCV_LARGE_IDENTITY
|
406 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV
) |
407 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
));
412 enable_kevent(uint64_t *workloop_id
, unsigned long long port
)
414 struct kevent_qos_s kev
;
417 populate_kevent(&kev
, port
);
418 struct kevent_qos_s kev_err
[] = {{ 0 }};
420 error
= kevent_id(*workloop_id
, &kev
, 1, kev_err
, 1, NULL
,
421 NULL
, KEVENT_FLAG_WORKLOOP
| KEVENT_FLAG_ERROR_EVENTS
| KEVENT_FLAG_DYNAMIC_KQ_MUST_EXIST
);
422 T_QUIET
; T_ASSERT_POSIX_SUCCESS(error
, "kevent_id");
426 * WL handler which sends a msg to the client from handler.
429 workloop_cb_test_sync_send_reply(uint64_t *workloop_id __unused
, struct kevent_qos_s
**eventslist
, int *events
)
431 T_LOG("Workloop handler workloop_cb_test_sync_send_reply called");
433 if (geteuid() != 0) {
434 T_SKIP("kevent_qos test requires root privileges to run.");
437 T_QUIET
; T_ASSERT_EQ_INT(*events
, 1, "events received");
438 T_QUIET
; T_ASSERT_EQ_INT((*eventslist
)->filter
, EVFILT_MACHPORT
, "received EVFILT_MACHPORT");
441 send_reply(get_reply_port(*eventslist
));
447 * WL handler which deallocates reply port.
450 workloop_cb_test_sync_send_deallocate(uint64_t *workloop_id __unused
, struct kevent_qos_s
**eventslist
, int *events
)
452 mach_port_t reply_port
;
455 T_LOG("Workloop handler workloop_cb_test_sync_send_deallocate called");
457 if (geteuid() != 0) {
458 T_SKIP("kevent_qos test requires root privileges to run.");
461 T_QUIET
; T_ASSERT_EQ_INT(*events
, 1, "events received");
462 T_QUIET
; T_ASSERT_EQ_INT((*eventslist
)->filter
, EVFILT_MACHPORT
, "received EVFILT_MACHPORT");
464 reply_port
= get_reply_port(*eventslist
);
466 /* deallocate port */
467 kr
= mach_port_deallocate(mach_task_self(), reply_port
);
469 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "mach_deallocate");
473 T_LOG("Handler returning \n");
478 * WL handler which sends a msg to the client before enabling the event from handler.
481 workloop_cb_test_sync_send_reply_kevent(uint64_t *workloop_id
, struct kevent_qos_s
**eventslist
, int *events
)
483 T_LOG("Workloop handler workloop_cb_test_sync_send_reply_kevent called");
485 if (geteuid() != 0) {
486 T_SKIP("kevent_qos test requires root privileges to run.");
489 T_QUIET
; T_ASSERT_EQ_INT(*events
, 1, "events received");
490 T_QUIET
; T_ASSERT_EQ_INT(((*eventslist
)->filter
), EVFILT_MACHPORT
, "received EVFILT_MACHPORT");
492 struct kevent_qos_s
*kev
= *eventslist
;
495 send_reply(get_reply_port(kev
));
497 /* Enable the knote */
498 enable_kevent(workloop_id
, kev
->ident
);
502 T_LOG("Handler returning \n");
506 * WL handler which sends a msg to the client before enabling the event from pthread.
509 workloop_cb_test_sync_send_reply_kevent_pthread(uint64_t *workloop_id __unused
, struct kevent_qos_s
**eventslist
, int *events
)
511 T_LOG("Workloop handler workloop_cb_test_sync_send_reply_kevent_pthread called");
513 if (geteuid() != 0) {
514 T_SKIP("kevent_qos test requires root privileges to run.");
517 T_QUIET
; T_ASSERT_EQ_INT(*events
, 1, "events received");
518 T_QUIET
; T_ASSERT_EQ_INT((*eventslist
)->filter
, EVFILT_MACHPORT
, "received EVFILT_MACHPORT");
520 struct kevent_qos_s
*kev
= *eventslist
;
523 send_reply(get_reply_port(kev
));
525 populate_kevent(kev
, kev
->ident
);
529 T_LOG("Handler returning \n");
533 * WL handler which sends a msg to the client after reenabling the event.
536 workloop_cb_test_sync_send_kevent_reply(uint64_t *workloop_id
, struct kevent_qos_s
**eventslist
, int *events
)
538 T_LOG("workloop handler workloop_cb_test_sync_send_kevent_reply called");
540 if (geteuid() != 0) {
541 T_SKIP("kevent_qos test requires root privileges to run.");
544 T_QUIET
; T_ASSERT_EQ_INT(*events
, 1, "events received");
545 T_QUIET
; T_ASSERT_EQ_INT((*eventslist
)->filter
, EVFILT_MACHPORT
, "received EVFILT_MACHPORT");
547 struct kevent_qos_s
*kev
= *eventslist
;
548 mach_port_t reply_port
= get_reply_port(*eventslist
);
550 /* Enable the knote */
551 enable_kevent(workloop_id
, kev
->ident
);
554 send_reply(reply_port
);
558 T_LOG("Handler returning \n");
562 * WL handler that does nothing.
565 workloop_cb_test_sync_send_do_nothing(uint64_t *workloop_id __unused
, struct kevent_qos_s
**eventslist
, int *events
)
567 T_LOG("Workloop handler workloop_cb_test_sync_send_do_nothing called");
569 if (geteuid() != 0) {
570 T_SKIP("kevent_qos test requires root privileges to run.");
573 T_QUIET
; T_ASSERT_EQ_INT(*events
, 1, "events received");
574 T_QUIET
; T_ASSERT_EQ_INT((*eventslist
)->filter
, EVFILT_MACHPORT
, "received EVFILT_MACHPORT");
580 T_LOG("Handler returning \n");
584 * WL handler that returns the event to reenable.
587 workloop_cb_test_sync_send_do_nothing_kevent_pthread(uint64_t *workloop_id __unused
, struct kevent_qos_s
**eventslist
, int *events
)
589 T_LOG("Workloop handler workloop_cb_test_sync_send_do_nothing_kevent_pthread called");
591 if (geteuid() != 0) {
592 T_SKIP("kevent_qos test requires root privileges to run.");
595 T_QUIET
; T_ASSERT_EQ_INT(*events
, 1, "events received");
596 T_QUIET
; T_ASSERT_EQ_INT((*eventslist
)->filter
, EVFILT_MACHPORT
, "received EVFILT_MACHPORT");
598 struct kevent_qos_s
*kev
= *eventslist
;
599 populate_kevent(kev
, kev
->ident
);
603 T_LOG("handler returning \n");
607 * WL handler that exits.
610 workloop_cb_test_sync_send_do_nothing_exit(uint64_t *workloop_id __unused
, struct kevent_qos_s
**eventslist
, __unused
int *events
)
612 T_LOG("workloop handler workloop_cb_test_sync_send_do_nothing_exit called");
614 if (geteuid() != 0) {
615 T_SKIP("kevent_qos test requires root privileges to run.");
618 T_QUIET
; T_ASSERT_EQ_INT(*events
, 1, "events received");
619 T_QUIET
; T_ASSERT_EQ_INT((*eventslist
)->filter
, EVFILT_MACHPORT
, "received EVFILT_MACHPORT");
627 * first sync sends a msg to the client and reenables kevent after
628 * second sync sends a msg and reenables kevent after.
631 workloop_cb_test_sync_send_reply_kevent_reply_kevent(uint64_t *workloop_id __unused
, struct kevent_qos_s
**eventslist
, int *events
)
633 T_LOG("Workloop handler workloop_cb_test_sync_send_reply_kevent_reply_kevent called");
635 if (geteuid() != 0) {
636 T_SKIP("kevent_qos test requires root privileges to run.");
639 T_QUIET
; T_ASSERT_EQ_INT(*events
, 1, "events received");
640 T_QUIET
; T_ASSERT_EQ_INT((*eventslist
)->filter
, EVFILT_MACHPORT
, "received EVFILT_MACHPORT");
642 struct kevent_qos_s
*kev
= *eventslist
;
645 send_reply(get_reply_port(kev
));
647 populate_kevent(kev
, kev
->ident
);
651 T_LOG("Handler returning \n");
656 * first sync reenables kevent and after sends a msg
657 * second sync sends a msg and reenables kevent after.
659 static int workloop_cb_test_sync_send_kevent_reply_reply_kevent_handler_called
= 0;
661 workloop_cb_test_sync_send_kevent_reply_reply_kevent(uint64_t *workloop_id
, struct kevent_qos_s
**eventslist
, int *events
)
663 T_LOG("workloop handler workloop_cb_test_sync_send_kevent_reply_reply_kevent called");
665 if (geteuid() != 0) {
666 T_SKIP("kevent_qos test requires root privileges to run.");
669 T_QUIET
; T_ASSERT_EQ_INT(*events
, 1, "events received");
670 T_QUIET
; T_ASSERT_EQ_INT((*eventslist
)->filter
, EVFILT_MACHPORT
, "received EVFILT_MACHPORT");
672 struct kevent_qos_s
*kev
= *eventslist
;
673 mach_port_t reply_port
= get_reply_port(kev
);
675 if (workloop_cb_test_sync_send_kevent_reply_reply_kevent_handler_called
== 0) {
676 workloop_cb_test_sync_send_kevent_reply_reply_kevent_handler_called
= 1;
678 /* Enable the knote */
679 enable_kevent(workloop_id
, kev
->ident
);
682 send_reply(reply_port
);
687 send_reply(reply_port
);
689 /* Enable the knote */
690 enable_kevent(workloop_id
, kev
->ident
);
695 T_LOG("Handler returning \n");
700 * first sync reenables kevent and after sends a msg
701 * second sync reenables kevent and after sends a msg
704 workloop_cb_test_sync_send_kevent_reply_kevent_reply(uint64_t *workloop_id
, struct kevent_qos_s
**eventslist
, int *events
)
706 T_LOG("workloop handler workloop_cb_test_sync_send_kevent_reply_kevent_reply called");
708 if (geteuid() != 0) {
709 T_SKIP("kevent_qos test requires root privileges to run.");
712 T_QUIET
; T_ASSERT_EQ_INT(*events
, 1, "events received");
713 T_QUIET
; T_ASSERT_EQ_INT((*eventslist
)->filter
, EVFILT_MACHPORT
, "received EVFILT_MACHPORT");
715 struct kevent_qos_s
*kev
= *eventslist
;
716 mach_port_t reply_port
= get_reply_port(kev
);
718 /* Enable the knote */
719 enable_kevent(workloop_id
, kev
->ident
);
722 send_reply(reply_port
);
725 T_LOG("Handler returning \n");
730 * first sync ends a msg and reenables kevent after
731 * second sync reenables kevent and sends a msg after
733 static int workloop_cb_test_sync_send_reply_kevent_kevent_reply_handler_called
= 0;
735 workloop_cb_test_sync_send_reply_kevent_kevent_reply(uint64_t *workloop_id
, struct kevent_qos_s
**eventslist
, int *events
)
737 T_LOG("workloop handler workloop_cb_test_sync_send_reply_kevent_kevent_reply called");
739 if (geteuid() != 0) {
740 T_SKIP("kevent_qos test requires root privileges to run.");
743 T_QUIET
; T_ASSERT_EQ_INT(*events
, 1, "events received");
744 T_QUIET
; T_ASSERT_EQ_INT((*eventslist
)->filter
, EVFILT_MACHPORT
, "received EVFILT_MACHPORT");
746 struct kevent_qos_s
*kev
= *eventslist
;
747 mach_port_t reply_port
= get_reply_port(kev
);
749 if (workloop_cb_test_sync_send_reply_kevent_kevent_reply_handler_called
== 0) {
750 workloop_cb_test_sync_send_reply_kevent_kevent_reply_handler_called
= 1;
753 send_reply(reply_port
);
755 populate_kevent(kev
, kev
->ident
);
759 /* Enable the knote */
760 enable_kevent(workloop_id
, kev
->ident
);
762 send_reply(reply_port
);
767 T_LOG("Handler returning \n");
769 #pragma mark Mach receive
771 #define KEVENT_QOS_SERVICE_NAME "com.apple.xnu.test.kevent_qos"
774 get_server_port(void)
777 kern_return_t kr
= bootstrap_check_in(bootstrap_port
,
778 KEVENT_QOS_SERVICE_NAME
, &port
);
779 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "server bootstrap_check_in");
784 env_set_qos(char **env
, qos_class_t qos
[], const char *qos_name
[], const char *wl_function
)
787 char *qos_str
, *qos_name_str
;
788 for (i
= 0; i
< ENV_VAR_QOS
; i
++) {
789 T_QUIET
; T_ASSERT_POSIX_SUCCESS(asprintf(&qos_str
, "%s=%d", qos_env
[i
], qos
[i
]),
791 T_QUIET
; T_ASSERT_POSIX_SUCCESS(
792 asprintf(&qos_name_str
, "%s=%s", qos_name_env
[i
], qos_name
[i
]), NULL
);
793 env
[2 * i
] = qos_str
;
794 env
[2 * i
+ 1] = qos_name_str
;
796 T_QUIET
; T_ASSERT_POSIX_SUCCESS(asprintf(&env
[2 * i
], "%s=%s", wl_function_name
, wl_function
),
798 env
[2 * i
+ 1] = NULL
;
802 environ_get_qos(qos_class_t qos
[], const char *qos_name
[], const char **wl_function
)
808 for (i
= 0; i
< ENV_VAR_QOS
; i
++) {
809 qos_str
= getenv(qos_env
[i
]);
810 T_QUIET
; T_ASSERT_NOTNULL(qos_str
, "getenv(%s)", qos_env
[i
]);
812 unsigned long qos_l
= strtoul(qos_str
, &qos_end
, 10);
813 T_QUIET
; T_ASSERT_EQ(*qos_end
, '\0', "getenv(%s) = '%s' should be an "
814 "integer", qos_env
[i
], qos_str
);
816 T_QUIET
; T_ASSERT_LT(qos_l
, (unsigned long)100, "getenv(%s) = '%s' should "
817 "be less than 100", qos_env
[i
], qos_str
);
819 qos
[i
] = (qos_class_t
)qos_l
;
820 qos_name
[i
] = getenv(qos_name_env
[i
]);
821 T_QUIET
; T_ASSERT_NOTNULL(qos_name
[i
], "getenv(%s)", qos_name_env
[i
]);
823 *wl_function
= getenv(wl_function_name
);
824 T_QUIET
; T_ASSERT_NOTNULL(*wl_function
, "getenv(%s)", wl_function_name
);
827 static mach_voucher_t
828 create_pthpriority_voucher(mach_msg_priority_t qos
)
830 char voucher_buf
[sizeof(mach_voucher_attr_recipe_data_t
) + sizeof(ipc_pthread_priority_value_t
)];
832 mach_voucher_t voucher
= MACH_PORT_NULL
;
834 ipc_pthread_priority_value_t ipc_pthread_priority_value
=
835 (ipc_pthread_priority_value_t
)qos
;
837 mach_voucher_attr_raw_recipe_array_t recipes
;
838 mach_voucher_attr_raw_recipe_size_t recipe_size
= 0;
839 mach_voucher_attr_recipe_t recipe
=
840 (mach_voucher_attr_recipe_t
)&voucher_buf
[recipe_size
];
842 recipe
->key
= MACH_VOUCHER_ATTR_KEY_PTHPRIORITY
;
843 recipe
->command
= MACH_VOUCHER_ATTR_PTHPRIORITY_CREATE
;
844 recipe
->previous_voucher
= MACH_VOUCHER_NULL
;
845 memcpy((char *)&recipe
->content
[0], &ipc_pthread_priority_value
, sizeof(ipc_pthread_priority_value
));
846 recipe
->content_size
= sizeof(ipc_pthread_priority_value_t
);
847 recipe_size
+= sizeof(mach_voucher_attr_recipe_data_t
) + recipe
->content_size
;
849 recipes
= (mach_voucher_attr_raw_recipe_array_t
)&voucher_buf
[0];
851 ret
= host_create_mach_voucher(mach_host_self(),
856 T_QUIET
; T_ASSERT_MACH_SUCCESS(ret
, "client host_create_mach_voucher");
862 mach_port_t send_port
,
863 mach_port_t reply_port
,
864 mach_port_t msg_port
,
865 mach_msg_priority_t qos
,
866 mach_msg_option_t options
)
868 kern_return_t ret
= 0;
870 struct test_msg send_msg
= {
872 .msgh_remote_port
= send_port
,
873 .msgh_local_port
= reply_port
,
874 .msgh_bits
= MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND
,
875 reply_port
? MACH_MSG_TYPE_MAKE_SEND_ONCE
: 0,
876 MACH_MSG_TYPE_MOVE_SEND
,
877 MACH_MSGH_BITS_COMPLEX
),
879 .msgh_size
= sizeof(send_msg
),
882 .msgh_descriptor_count
= 1,
886 .disposition
= MACH_MSG_TYPE_MOVE_RECEIVE
,
887 .type
= MACH_MSG_PORT_DESCRIPTOR
,
892 if (msg_port
== MACH_PORT_NULL
) {
893 send_msg
.body
.msgh_descriptor_count
= 0;
896 if ((options
& MACH_SEND_PROPAGATE_QOS
) == 0) {
897 send_msg
.header
.msgh_voucher_port
= create_pthpriority_voucher(qos
);
902 pthread_get_qos_class_np(pthread_self(), &qc
, &relpri
);
903 send_msg
.qos
= (uint32_t)_pthread_qos_class_encode(qc
, relpri
, 0);
906 mach_msg_option_t send_opts
= options
;
908 send_opts
|= MACH_SEND_SYNC_OVERRIDE
;
910 send_opts
|= MACH_SEND_MSG
| MACH_SEND_TIMEOUT
| MACH_SEND_OVERRIDE
;
912 ret
= mach_msg(&send_msg
.header
, send_opts
, send_msg
.header
.msgh_size
,
913 0, MACH_PORT_NULL
, 10000, qos
);
915 T_QUIET
; T_ASSERT_MACH_SUCCESS(ret
, "client mach_msg");
920 mach_port_t rcv_port
,
921 mach_port_t notify_port
)
923 kern_return_t ret
= 0;
925 struct test_msg rcv_msg
= {
927 .msgh_remote_port
= MACH_PORT_NULL
,
928 .msgh_local_port
= rcv_port
,
929 .msgh_size
= sizeof(rcv_msg
),
933 T_LOG("Client: Starting sync receive\n");
935 ret
= mach_msg(&(rcv_msg
.header
),
940 rcv_msg
.header
.msgh_size
,
942 SEND_TIMEOUT_SECS
* 1000,
948 T_HELPER_DECL(qos_get_special_reply_port
,
949 "Test get_special_reply_port and it's corner cases.")
951 mach_port_t special_reply_port
;
952 mach_port_t new_special_reply_port
;
954 special_reply_port
= thread_get_special_reply_port();
955 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port
), "get_thread_special_reply_port");
957 new_special_reply_port
= thread_get_special_reply_port();
958 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(new_special_reply_port
), "get_thread_special_reply_port");
960 mach_port_destroy(mach_task_self(), special_reply_port
);
961 mach_port_destroy(mach_task_self(), new_special_reply_port
);
963 new_special_reply_port
= thread_get_special_reply_port();
964 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(new_special_reply_port
), "get_thread_special_reply_port");
970 qos_client_send_to_intransit(void *arg __unused
)
972 mach_port_t qos_send_port
;
973 mach_port_t msg_port
;
974 mach_port_t special_reply_port
;
976 kern_return_t kr
= bootstrap_look_up(bootstrap_port
,
977 KEVENT_QOS_SERVICE_NAME
, &qos_send_port
);
978 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "client bootstrap_look_up");
980 special_reply_port
= thread_get_special_reply_port();
981 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port
), "get_thread_special_reply_port");
983 /* Create a rcv right to send in a msg */
984 kr
= mach_port_allocate(mach_task_self(),
985 MACH_PORT_RIGHT_RECEIVE
,
988 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "client mach_port_allocate");
990 kr
= mach_port_insert_right(mach_task_self(),
993 MACH_MSG_TYPE_MAKE_SEND
);
995 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "client mach_port_insert_right");
997 /* Send an empty msg on the port to fire the WL thread */
998 send(qos_send_port
, MACH_PORT_NULL
, MACH_PORT_NULL
,
999 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
], 0, 0), 0);
1001 /* Sleep 3 seconds for the server to start */
1004 /* Send the message with msg port as in-transit port, this msg will not be dequeued */
1005 send(qos_send_port
, MACH_PORT_NULL
, msg_port
,
1006 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
], 0, 0), 0);
1008 /* Send 5 messages to msg port to make sure the port is full */
1009 for (int i
= 0; i
< 5; i
++) {
1010 send(msg_port
, MACH_PORT_NULL
, MACH_PORT_NULL
,
1011 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
], 0, 0), 0);
1014 T_LOG("Sent 5 msgs, now trying to send sync ipc message, which will block with a timeout\n");
1015 /* Send the message to the in-transit port, it should block and override the rcv's workloop */
1016 send(msg_port
, special_reply_port
, MACH_PORT_NULL
,
1017 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], 0, 0), 0);
1018 T_LOG("Client done sending messages, now waiting for server to end the test");
1020 T_ASSERT_FAIL("client timed out");
1024 T_HELPER_DECL(qos_client_send_to_intransit_with_thr_pri
,
1025 "Send synchronous messages from a pri thread to an intransit port")
1027 thread_create_at_qos(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], qos_client_send_to_intransit
);
1028 sleep(HELPER_TIMEOUT_SECS
);
1032 thread_create_at_qos(qos_class_t qos
, void * (*function
)(void *))
1034 qos_class_t qos_thread
;
1036 pthread_attr_t attr
;
1039 ret
= setpriority(PRIO_DARWIN_ROLE
, 0, PRIO_DARWIN_ROLE_UI_FOCAL
);
1041 T_LOG("set priority failed\n");
1044 pthread_attr_init(&attr
);
1045 pthread_attr_set_qos_class_np(&attr
, qos
, 0);
1046 pthread_create(&thread
, &attr
, function
, NULL
);
1048 T_LOG("pthread created\n");
1049 pthread_get_qos_class_np(thread
, &qos_thread
, NULL
);
1050 T_EXPECT_EQ(qos_thread
, (qos_class_t
)qos
, NULL
);
1055 qos_send_and_sync_rcv(void *arg __unused
)
1057 mach_port_t qos_send_port
;
1058 mach_port_t special_reply_port
;
1060 T_LOG("Client: from created thread\n");
1061 T_EXPECT_EFFECTIVE_QOS_EQ(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
],
1062 "pthread QoS should be %s", g_expected_qos_name
[ENV_QOS_AFTER_OVERRIDE
]);
1064 kern_return_t kr
= bootstrap_look_up(bootstrap_port
,
1065 KEVENT_QOS_SERVICE_NAME
, &qos_send_port
);
1066 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "client bootstrap_look_up");
1068 special_reply_port
= thread_get_special_reply_port();
1069 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port
), "get_thread_special_reply_port");
1071 /* enqueue two messages to make sure that mqueue is not empty */
1072 send(qos_send_port
, MACH_PORT_NULL
, MACH_PORT_NULL
,
1073 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_QUEUE_OVERRIDE
], 0, 0), 0);
1075 send(qos_send_port
, MACH_PORT_NULL
, MACH_PORT_NULL
,
1076 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_QUEUE_OVERRIDE
], 0, 0), 0);
1078 sleep(SEND_TIMEOUT_SECS
);
1080 /* sync wait on msg port */
1081 receive(special_reply_port
, qos_send_port
);
1083 T_LOG("Client done doing sync rcv, now waiting for server to end the test");
1084 sleep(SEND_TIMEOUT_SECS
);
1086 T_ASSERT_FAIL("client timed out");
1091 qos_sync_rcv(void *arg __unused
)
1093 mach_port_t qos_send_port
;
1094 mach_port_t special_reply_port
;
1096 T_LOG("Client: from created thread\n");
1098 kern_return_t kr
= bootstrap_look_up(bootstrap_port
,
1099 KEVENT_QOS_SERVICE_NAME
, &qos_send_port
);
1100 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "client bootstrap_look_up");
1102 special_reply_port
= thread_get_special_reply_port();
1103 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port
), "get_thread_special_reply_port");
1105 /* enqueue two messages to make sure that mqueue is not empty */
1106 send(qos_send_port
, MACH_PORT_NULL
, MACH_PORT_NULL
,
1107 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_QUEUE_OVERRIDE
], 0, 0), 0);
1109 sleep(RECV_TIMEOUT_SECS
);
1111 /* sync wait on msg port */
1112 receive(special_reply_port
, qos_send_port
);
1114 T_LOG("Client done doing sync rcv, now waiting for server to end the test");
1115 sleep(SEND_TIMEOUT_SECS
);
1117 T_ASSERT_FAIL("client timed out");
1122 thread_wait_to_block(mach_port_t thread_port
)
1124 thread_extended_info_data_t extended_info
;
1128 mach_msg_type_number_t count
= THREAD_EXTENDED_INFO_COUNT
;
1129 kr
= thread_info(thread_port
, THREAD_EXTENDED_INFO
,
1130 (thread_info_t
)&extended_info
, &count
);
1132 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "thread_info");
1134 if (extended_info
.pth_run_state
== TH_STATE_WAITING
) {
1135 T_LOG("Target thread blocked\n");
1138 thread_switch(thread_port
, SWITCH_OPTION_DEPRESS
, 0);
1142 T_HELPER_DECL(qos_client_send_sync_and_sync_rcv
,
1143 "Send messages and syncronously wait for rcv")
1145 thread_create_at_qos(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], qos_send_and_sync_rcv
);
1146 sleep(HELPER_TIMEOUT_SECS
);
1149 T_HELPER_DECL(qos_client_sync_rcv_qos_change
,
1150 "Send messages and syncronously wait for rcv and change qos of waiting thread")
1152 pthread_t rcv_thread
;
1154 rcv_thread
= thread_create_at_qos(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
], qos_sync_rcv
);
1156 T_LOG("Waiting for %d seconds before changing qos of rcv thread", SEND_TIMEOUT_SECS
);
1157 sleep(SEND_TIMEOUT_SECS
);
1159 /* Wait for the thread to block */
1160 thread_wait_to_block(pthread_mach_thread_np(rcv_thread
));
1162 /* Update the rcv thread's qos */
1163 pthread_override_qos_class_start_np(rcv_thread
, g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], 0);
1165 sleep(HELPER_TIMEOUT_SECS
);
1169 qos_client_send_sync_msg_and_test_link(void *arg
)
1171 mach_port_t qos_send_port
;
1172 mach_port_t special_reply_port
;
1173 boolean_t in_effect
= FALSE
;
1175 unsigned long expected_result
= (unsigned long) arg
;
1177 kr
= bootstrap_look_up(bootstrap_port
,
1178 KEVENT_QOS_SERVICE_NAME
, &qos_send_port
);
1179 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "client bootstrap_look_up");
1181 /* start monitoring sync ipc link */
1182 kr
= mach_sync_ipc_link_monitoring_start(&special_reply_port
);
1183 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "mach_sync_ipc_link_monitoring_start");
1185 /* Send the message to msg port */
1186 send(qos_send_port
, special_reply_port
, MACH_PORT_NULL
,
1187 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], 0, 0), 0);
1190 * wait for the reply
1191 * some tests do not send a msg back so the receive
1194 receive(special_reply_port
, qos_send_port
);
1196 /* stop monitoring link */
1197 kr
= mach_sync_ipc_link_monitoring_stop(special_reply_port
, &in_effect
);
1198 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "mach_sync_ipc_link_monitoring_stop");
1201 T_LOG("Link was broken");
1203 T_LOG("Link correct");
1206 if (expected_result
== 1) {
1207 T_ASSERT_TRUE(in_effect
, "special reply port link after rcv");
1209 T_ASSERT_FALSE(in_effect
, "special reply port link after rcv");
1215 qos_client_send_2sync_msg_and_test_link(void *arg
)
1217 mach_port_t qos_send_port
;
1218 mach_port_t special_reply_port
;
1219 boolean_t in_effect
= FALSE
;
1221 unsigned long expected_result
= (unsigned long) arg
;
1223 kr
= bootstrap_look_up(bootstrap_port
,
1224 KEVENT_QOS_SERVICE_NAME
, &qos_send_port
);
1225 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "client bootstrap_look_up");
1227 /* start monitoring sync ipc link */
1228 kr
= mach_sync_ipc_link_monitoring_start(&special_reply_port
);
1229 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "mach_sync_ipc_link_monitoring_start");
1231 /* Send the first message to msg port */
1232 send(qos_send_port
, special_reply_port
, MACH_PORT_NULL
,
1233 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], 0, 0), 0);
1235 /* wait for the reply */
1236 kr
= receive(special_reply_port
, qos_send_port
);
1237 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "receive");
1239 /* Send the second message to msg port */
1240 send(qos_send_port
, special_reply_port
, MACH_PORT_NULL
,
1241 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], 0, 0), 0);
1243 /* wait for the reply */
1244 kr
= receive(special_reply_port
, qos_send_port
);
1245 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "receive");
1247 /* stop monitoring link */
1248 kr
= mach_sync_ipc_link_monitoring_stop(special_reply_port
, &in_effect
);
1249 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "mach_sync_ipc_link_monitoring_stop");
1252 T_LOG("Link was broken");
1254 T_LOG("Link correct");
1257 if (expected_result
== 1) {
1258 T_ASSERT_TRUE(in_effect
, "special reply port link after rcv");
1260 T_ASSERT_FALSE(in_effect
, "special reply port link after rcv");
1264 T_HELPER_DECL(qos_client_send_sync_msg_with_link_check_correct_server
,
1265 "Send sync message, wait for reply and check sync ipc link")
1268 pthread_attr_t attr
;
1269 unsigned long expected_result
= 1;
1271 pthread_attr_init(&attr
);
1272 pthread_create(&thread
, &attr
, qos_client_send_sync_msg_and_test_link
, (void *)expected_result
);
1274 sleep(HELPER_TIMEOUT_SECS
);
1277 T_HELPER_DECL(qos_client_send_sync_msg_with_link_check_incorrect_server
,
1278 "Send sync message, wait for reply and check sync ipc link")
1281 pthread_attr_t attr
;
1282 unsigned long expected_result
= 0;
1284 pthread_attr_init(&attr
);
1285 pthread_create(&thread
, &attr
, qos_client_send_sync_msg_and_test_link
, (void *)expected_result
);
1287 sleep(HELPER_TIMEOUT_SECS
);
1290 T_HELPER_DECL(qos_client_send_2sync_msg_with_link_check_correct_server
,
1291 "Send sync message, wait for reply and check sync ipc link")
1294 pthread_attr_t attr
;
1295 unsigned long expected_result
= 1;
1297 pthread_attr_init(&attr
);
1298 pthread_create(&thread
, &attr
, qos_client_send_2sync_msg_and_test_link
, (void *)expected_result
);
1300 sleep(HELPER_TIMEOUT_SECS
);
1303 T_HELPER_DECL(qos_client_send_2sync_msg_with_link_check_incorrect_server
,
1304 "Send sync message, wait for reply and check sync ipc link")
1307 pthread_attr_t attr
;
1308 unsigned long expected_result
= 0;
1310 pthread_attr_init(&attr
);
1311 pthread_create(&thread
, &attr
, qos_client_send_2sync_msg_and_test_link
, (void *)expected_result
);
1313 sleep(HELPER_TIMEOUT_SECS
);
1317 qos_client_send_sync_msg(void *arg __unused
)
1319 mach_port_t qos_send_port
;
1320 mach_port_t special_reply_port
;
1322 kern_return_t kr
= bootstrap_look_up(bootstrap_port
,
1323 KEVENT_QOS_SERVICE_NAME
, &qos_send_port
);
1324 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "client bootstrap_look_up");
1326 special_reply_port
= thread_get_special_reply_port();
1327 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port
), "get_thread_special_reply_port");
1329 /* Send the message to msg port */
1330 send(qos_send_port
, special_reply_port
, MACH_PORT_NULL
,
1331 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], 0, 0), 0);
1333 /* wait for the reply */
1334 receive(special_reply_port
, qos_send_port
);
1336 T_LOG("Client done sending messages, now waiting for server to end the test");
1337 sleep(2 * SEND_TIMEOUT_SECS
);
1339 T_ASSERT_FAIL("client timed out");
1343 T_HELPER_DECL(qos_client_send_sync_msg_with_pri
,
1344 "Send sync message and wait for reply")
1346 thread_create_at_qos(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], qos_client_send_sync_msg
);
1347 sleep(HELPER_TIMEOUT_SECS
);
1351 qos_client_send_two_sync_msg_high_qos(void *arg __unused
)
1353 mach_port_t qos_send_port
;
1354 mach_port_t special_reply_port
;
1356 kern_return_t kr
= bootstrap_look_up(bootstrap_port
,
1357 KEVENT_QOS_SERVICE_NAME
, &qos_send_port
);
1358 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "client bootstrap_look_up");
1360 special_reply_port
= thread_get_special_reply_port();
1361 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port
), "get_thread_special_reply_port");
1363 /* Send the message to msg port */
1364 send(qos_send_port
, special_reply_port
, MACH_PORT_NULL
,
1365 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], 0, 0), 0);
1367 /* wait for the reply */
1368 receive(special_reply_port
, qos_send_port
);
1370 T_LOG("Client done sending messages, now waiting for server to end the test");
1371 sleep(SEND_TIMEOUT_SECS
);
1373 T_ASSERT_FAIL("client timed out");
1378 qos_client_send_two_sync_msg_low_qos(void *arg __unused
)
1380 mach_port_t qos_send_port
;
1381 mach_port_t special_reply_port
;
1383 kern_return_t kr
= bootstrap_look_up(bootstrap_port
,
1384 KEVENT_QOS_SERVICE_NAME
, &qos_send_port
);
1385 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "client bootstrap_look_up");
1387 special_reply_port
= thread_get_special_reply_port();
1388 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port
), "get_thread_special_reply_port");
1390 /* Send the message to msg port */
1391 send(qos_send_port
, special_reply_port
, MACH_PORT_NULL
,
1392 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
], 0, 0), 0);
1394 /* wait for the reply */
1395 receive(special_reply_port
, qos_send_port
);
1397 T_LOG("Client done sending messages, now waiting for server to end the test");
1398 sleep(SEND_TIMEOUT_SECS
);
1400 T_ASSERT_FAIL("client timed out");
1404 T_HELPER_DECL(qos_client_send_two_sync_msg_with_thr_pri
,
1405 "Send messages sync msgs from 2 threads at given thread pri")
1407 thread_create_at_qos(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], qos_client_send_two_sync_msg_high_qos
);
1408 sleep(INTERMITTENT_TIMEOUT_SEC
);
1409 thread_create_at_qos(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
], qos_client_send_two_sync_msg_low_qos
);
1410 sleep(HELPER_TIMEOUT_SECS
);
1413 static mach_port_t other_thread_reply_port
= MACH_PORT_NULL
;
1415 qos_client_destroy_other_threads_port(void *arg __unused
)
1417 T_LOG("Waiting 6 seconds before destroying other thread's reply port");
1418 sleep(SEND_TIMEOUT_SECS
);
1420 T_LOG("Destroying other thread's special reply port ");
1421 mach_port_destroy(mach_task_self(), other_thread_reply_port
);
1423 T_LOG("Other thread done destroying ");
1424 sleep(3 * SEND_TIMEOUT_SECS
);
1426 T_ASSERT_FAIL("client timed out");
1431 qos_client_create_sepcial_reply_and_spawn_thread(void *arg __unused
)
1433 mach_port_t qos_send_port
;
1434 mach_port_t special_reply_port
;
1436 kern_return_t kr
= bootstrap_look_up(bootstrap_port
,
1437 KEVENT_QOS_SERVICE_NAME
, &qos_send_port
);
1438 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "client bootstrap_look_up");
1440 special_reply_port
= thread_get_special_reply_port();
1441 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port
), "get_thread_special_reply_port");
1443 other_thread_reply_port
= special_reply_port
;
1445 /* Send an async message */
1446 send(qos_send_port
, MACH_PORT_NULL
, MACH_PORT_NULL
,
1447 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
], 0, 0), 0);
1449 /* Send the sync ipc message */
1450 send(qos_send_port
, special_reply_port
, MACH_PORT_NULL
,
1451 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
], 0, 0), 0);
1453 /* Create a new thread to send the sync message on our special reply port */
1454 thread_create_at_qos(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], qos_client_destroy_other_threads_port
);
1456 /* Client starting to receive message */
1457 receive(special_reply_port
, qos_send_port
);
1459 sleep(3 * SEND_TIMEOUT_SECS
);
1461 T_ASSERT_FAIL("client timed out");
1465 T_HELPER_DECL(qos_client_send_two_msg_and_destroy
,
1466 "Send a message with another threads special reply port while that thread destroys the port")
1468 thread_create_at_qos(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
], qos_client_create_sepcial_reply_and_spawn_thread
);
1469 sleep(HELPER_TIMEOUT_SECS
);
1472 static mach_port_t send_complex_connection_port
= MACH_PORT_NULL
;
1475 qos_client_send_complex_msg_to_service_port(void *arg __unused
)
1477 mach_port_t svc_port
, tsr_port
, conn_port
;
1480 kr
= bootstrap_look_up(bootstrap_port
, KEVENT_QOS_SERVICE_NAME
, &svc_port
);
1481 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "client bootstrap_look_up");
1483 tsr_port
= thread_get_special_reply_port();
1484 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(tsr_port
), "get_thread_special_reply_port");
1486 conn_port
= send_complex_connection_port
;
1488 T_LOG("Sending to the service port with a sync IPC");
1489 send(svc_port
, tsr_port
, conn_port
,
1490 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
], 0, 0),
1491 MACH_SEND_PROPAGATE_QOS
);
1493 receive(tsr_port
, svc_port
);
1495 sleep(3 * SEND_TIMEOUT_SECS
);
1497 T_ASSERT_FAIL("client timed out");
1502 qos_client_send_to_connection_then_service_port(void *arg __unused
)
1504 mach_port_t tsr_port
, conn_port
;
1505 mach_port_options_t opts
= {
1506 .flags
= MPO_INSERT_SEND_RIGHT
,
1510 kr
= mach_port_construct(mach_task_self(), &opts
, 0ull, &conn_port
);
1511 T_QUIET
; T_ASSERT_MACH_SUCCESS(kr
, "mach_port_construct");
1512 send_complex_connection_port
= conn_port
;
1514 tsr_port
= thread_get_special_reply_port();
1515 T_QUIET
; T_ASSERT_TRUE(MACH_PORT_VALID(tsr_port
), "get_thread_special_reply_port");
1517 T_LOG("Sending to the connection port with a sync IPC");
1518 send(conn_port
, tsr_port
, MACH_PORT_NULL
,
1519 (uint32_t)_pthread_qos_class_encode(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
], 0, 0),
1520 MACH_SEND_PROPAGATE_QOS
);
1522 thread_create_at_qos(g_expected_qos
[ENV_QOS_AFTER_OVERRIDE
],
1523 qos_client_send_complex_msg_to_service_port
);
1525 receive(tsr_port
, conn_port
);
1527 sleep(3 * SEND_TIMEOUT_SECS
);
1529 T_ASSERT_FAIL("client timed out");
1533 T_HELPER_DECL(qos_client_send_complex_msg_with_pri
,
1534 "Send a message with several ports causing links")
1536 thread_create_at_qos(g_expected_qos
[ENV_QOS_BEFORE_OVERRIDE
],
1537 qos_client_send_to_connection_then_service_port
);
1538 sleep(HELPER_TIMEOUT_SECS
);
1542 run_client_server(const char *server_name
, const char *client_name
, qos_class_t qos
[],
1543 const char *qos_name
[], const char *wl_function
)
1545 char *env
[2 * ENV_VAR_QOS
+ ENV_VAR_FUNCTION
+ 1];
1546 env_set_qos(env
, qos
, qos_name
, wl_function
);
1548 for (int i
= 0; i
< ENV_VAR_QOS
; i
++) {
1549 g_expected_qos
[i
] = qos
[i
];
1550 g_expected_qos_name
[i
] = qos_name
[i
];
1553 dt_helper_t helpers
[] = {
1554 dt_launchd_helper_env("com.apple.xnu.test.kevent_qos.plist",
1556 dt_fork_helper(client_name
)
1558 dt_run_helpers(helpers
, 2, HELPER_TIMEOUT_SECS
);
1561 #pragma mark Mach receive - kevent_qos
1564 expect_kevent_id_recv(mach_port_t port
, qos_class_t qos
[], const char *qos_name
[], const char *wl_function
)
1568 /* Qos expected by workloop thread */
1569 for (int i
= 0; i
< ENV_VAR_QOS
; i
++) {
1570 g_expected_qos
[i
] = qos
[i
];
1571 g_expected_qos_name
[i
] = qos_name
[i
];
1574 if (strcmp(wl_function
, "workloop_cb_test_intransit") == 0) {
1575 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1576 worker_cb
, event_cb
,
1577 (pthread_workqueue_function_workloop_t
)workloop_cb_test_intransit
, 0, 0), NULL
);
1578 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send") == 0) {
1579 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1580 worker_cb
, event_cb
,
1581 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send
, 0, 0), NULL
);
1582 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_and_enable") == 0) {
1583 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1584 worker_cb
, event_cb
,
1585 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_and_enable
, 0, 0), NULL
);
1586 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_and_enable_handoff") == 0) {
1587 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1588 worker_cb
, event_cb
,
1589 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_and_enable_handoff
, 0, 0), NULL
);
1590 } else if (strcmp(wl_function
, "workloop_cb_test_send_two_sync") == 0) {
1591 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1592 worker_cb
, event_cb
,
1593 (pthread_workqueue_function_workloop_t
)workloop_cb_test_send_two_sync
, 0, 0), NULL
);
1594 } else if (strcmp(wl_function
, "workloop_cb_test_two_send_and_destroy") == 0) {
1595 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1596 worker_cb
, event_cb
,
1597 (pthread_workqueue_function_workloop_t
)workloop_cb_test_two_send_and_destroy
, 0, 0), NULL
);
1598 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_reply") == 0) {
1599 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1600 worker_cb
, event_cb
,
1601 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_reply
, 0, 0), NULL
);
1602 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_deallocate") == 0) {
1603 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1604 worker_cb
, event_cb
,
1605 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_deallocate
, 0, 0), NULL
);
1606 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_reply_kevent") == 0) {
1607 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1608 worker_cb
, event_cb
,
1609 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_reply_kevent
, 0, 0), NULL
);
1610 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_reply_kevent_pthread") == 0) {
1611 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1612 worker_cb
, event_cb
,
1613 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_reply_kevent_pthread
, 0, 0), NULL
);
1614 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_kevent_reply") == 0) {
1615 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1616 worker_cb
, event_cb
,
1617 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_kevent_reply
, 0, 0), NULL
);
1618 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_do_nothing") == 0) {
1619 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1620 worker_cb
, event_cb
,
1621 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_do_nothing
, 0, 0), NULL
);
1622 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_do_nothing_kevent_pthread") == 0) {
1623 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1624 worker_cb
, event_cb
,
1625 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_do_nothing_kevent_pthread
, 0, 0), NULL
);
1626 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_do_nothing_exit") == 0) {
1627 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1628 worker_cb
, event_cb
,
1629 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_do_nothing_exit
, 0, 0), NULL
);
1630 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_reply_kevent_reply_kevent") == 0) {
1631 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1632 worker_cb
, event_cb
,
1633 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_reply_kevent_reply_kevent
, 0, 0), NULL
);
1634 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_kevent_reply_reply_kevent") == 0) {
1635 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1636 worker_cb
, event_cb
,
1637 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_kevent_reply_reply_kevent
, 0, 0), NULL
);
1638 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_kevent_reply_kevent_reply") == 0) {
1639 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1640 worker_cb
, event_cb
,
1641 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_kevent_reply_kevent_reply
, 0, 0), NULL
);
1642 } else if (strcmp(wl_function
, "workloop_cb_test_sync_send_reply_kevent_kevent_reply") == 0) {
1643 T_QUIET
; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
1644 worker_cb
, event_cb
,
1645 (pthread_workqueue_function_workloop_t
)workloop_cb_test_sync_send_reply_kevent_kevent_reply
, 0, 0), NULL
);
1647 T_ASSERT_FAIL("no workloop function specified \n");
1650 struct kevent_qos_s kev
[] = {{
1652 .filter
= EVFILT_MACHPORT
,
1653 .flags
= EV_ADD
| EV_UDATA_SPECIFIC
| EV_DISPATCH
| EV_VANISHED
,
1654 .fflags
= (MACH_RCV_MSG
| MACH_RCV_VOUCHER
| MACH_RCV_LARGE
| MACH_RCV_LARGE_IDENTITY
|
1655 MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AV
) |
1656 MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0
)),
1658 .qos
= (int32_t)_pthread_qos_class_encode(qos
[ENV_QOS_QUEUE_OVERRIDE
], 0, 0)
1661 struct kevent_qos_s kev_err
[] = {{ 0 }};
1663 /* Setup workloop for mach msg rcv */
1664 r
= kevent_id(25, kev
, 1, kev_err
, 1, NULL
,
1665 NULL
, KEVENT_FLAG_WORKLOOP
| KEVENT_FLAG_ERROR_EVENTS
);
1667 T_QUIET
; T_ASSERT_POSIX_SUCCESS(r
, "kevent_id");
1668 T_QUIET
; T_ASSERT_EQ(r
, 0, "no errors returned from kevent_id");
1669 sleep(HELPER_TIMEOUT_SECS
);
1672 T_HELPER_DECL(server_kevent_id
,
1673 "Reply with the QoS that a dispatch source event handler ran with")
1675 qos_class_t qos
[ENV_VAR_QOS
];
1676 const char *qos_name
[ENV_VAR_QOS
];
1677 const char *wl_function
;
1678 environ_get_qos(qos
, qos_name
, &wl_function
);
1680 expect_kevent_id_recv(get_server_port(), qos
, qos_name
, wl_function
);
1681 sleep(HELPER_TIMEOUT_SECS
);
1682 T_ASSERT_FAIL("should receive a message within %d seconds",
1687 special_reply_port_thread(void *ctxt
)
1690 mach_port_t rcv_port
= *(mach_port_t
*)ctxt
;
1691 struct test_msg rcv_msg
= {
1693 .msgh_remote_port
= MACH_PORT_NULL
,
1694 .msgh_local_port
= rcv_port
,
1695 .msgh_size
= sizeof(rcv_msg
),
1699 ret
= mach_msg(&rcv_msg
.header
, MACH_RCV_MSG
| MACH_RCV_TIMEOUT
, 0,
1700 rcv_msg
.header
.msgh_size
, rcv_port
, 1000, MACH_PORT_NULL
);
1702 T_EXPECT_EQ(ret
, MACH_RCV_TIMED_OUT
, "receive should not panic");
1704 *(mach_port_t
*)ctxt
= MACH_PORT_NULL
;
1706 sleep(1); // give some time to pthread_exit
1708 ret
= mach_msg(&rcv_msg
.header
, MACH_RCV_MSG
| MACH_RCV_TIMEOUT
, 0,
1709 rcv_msg
.header
.msgh_size
, rcv_port
, 1000, MACH_PORT_NULL
);
1711 T_EXPECT_EQ(ret
, MACH_RCV_TIMED_OUT
, "receive should not panic");
1716 T_DECL(special_reply_port
, "basic special reply port robustness checks",
1717 T_META_RUN_CONCURRENTLY(true))
1720 mach_port_t srp
= thread_get_special_reply_port();
1722 pthread_create(&thread
, NULL
, special_reply_port_thread
, &srp
);
1731 #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) \
1732 T_DECL(server_kevent_id_##name, \
1733 "Event delivery at " qos_ao_name " QoS using a kevent_id", \
1734 T_META_ASROOT(YES)) \
1736 qos_class_t qos_array[ENV_VAR_QOS] = {qos_bo, qos_qo, qos_ao}; \
1737 const char *qos_name_array[ENV_VAR_QOS] = {qos_bo_name, qos_qo_name, qos_ao_name}; \
1738 run_client_server(server_name, client_name, qos_array, qos_name_array, wl_function_name); \
1741 * Test 1: Test special reply port SPI
1743 * Create thread special reply port and check any subsequent calls to
1744 * the same should return MACH_PORT_NULL, unless the reply port is destroyed.
1746 TEST_QOS("server_kevent_id", "qos_get_special_reply_port", special_reply_port
, "workloop_cb_test_intransit",
1747 QOS_CLASS_DEFAULT
, "default",
1748 QOS_CLASS_DEFAULT
, "default",
1749 QOS_CLASS_DEFAULT
, "default")
1752 * Test 2: Test sync ipc send to an in-transit port
1754 * Send a sync ipc message (at IN qos) to an in-transit port enqueued in a port
1755 * attached to a workloop. Test that the servicer of the workloop gets
1756 * sync ipc override.
1758 TEST_QOS("server_kevent_id", "qos_client_send_to_intransit_with_thr_pri", transit_IN
, "workloop_cb_test_intransit",
1759 QOS_CLASS_DEFAULT
, "default",
1760 QOS_CLASS_MAINTENANCE
, "maintenance",
1761 QOS_CLASS_USER_INITIATED
, "user initiated")
1764 * Test 3: Test sync ipc send to an in-transit port
1766 * Send a sync ipc message (at UI qos) to an in-transit port enqueued in a port
1767 * attached to a workloop. Test that the servicer of the workloop gets
1768 * sync ipc override.
1770 TEST_QOS("server_kevent_id", "qos_client_send_to_intransit_with_thr_pri", transit_UI
, "workloop_cb_test_intransit",
1771 QOS_CLASS_USER_INITIATED
, "user initiated",
1772 QOS_CLASS_MAINTENANCE
, "maintenance",
1773 QOS_CLASS_USER_INTERACTIVE
, "user initiated with 47 basepri promotion")
1776 * Test 4: Test starting a sync rcv overrides the servicer
1778 * Send an async message to a port and then start waiting on
1779 * the port in mach msg rcv (at IN qos) with sync wait and test if the
1780 * servicer of the workloop gets sync ipc override.
1782 TEST_QOS("server_kevent_id", "qos_client_send_sync_and_sync_rcv", rcv_IN
, "workloop_cb_test_intransit",
1783 QOS_CLASS_DEFAULT
, "default",
1784 QOS_CLASS_MAINTENANCE
, "maintenance",
1785 QOS_CLASS_USER_INITIATED
, "user initiated")
1788 * Test 5: Test starting a sync rcv overrides the servicer
1790 * Send an async message to a port and then start waiting on
1791 * the port in mach msg rcv (at UI qos) with sync wait and test if the
1792 * servicer of the workloop gets sync ipc override.
1794 TEST_QOS("server_kevent_id", "qos_client_send_sync_and_sync_rcv", rcv_UI
, "workloop_cb_test_intransit",
1795 QOS_CLASS_DEFAULT
, "default",
1796 QOS_CLASS_MAINTENANCE
, "maintenance",
1797 QOS_CLASS_USER_INTERACTIVE
, "user interactive with 47 basepri promotion")
1800 * Test 6: test sending sync ipc message (at IN qos) to port will override the servicer
1802 * Send a message with sync ipc override to a port and check if the servicer
1803 * of the workloop on other side gets sync ipc override.
1805 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_pri", send_sync_IN
, "workloop_cb_test_sync_send",
1806 QOS_CLASS_DEFAULT
, "default",
1807 QOS_CLASS_MAINTENANCE
, "maintenance",
1808 QOS_CLASS_USER_INITIATED
, "user initiated")
1811 * Test 7: test sending sync ipc message (at UI qos) to port will override the servicer
1813 * Send a message with sync ipc override to a port and check if the servicer
1814 * of the workloop on other side gets sync ipc override.
1816 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_pri", send_sync_UI
, "workloop_cb_test_sync_send",
1817 QOS_CLASS_MAINTENANCE
, "maintenance",
1818 QOS_CLASS_MAINTENANCE
, "maintenance",
1819 QOS_CLASS_USER_INTERACTIVE
, "user initiated with 47 basepri promotion")
1822 * Test 8: test enabling a knote in workloop handler will drop the sync ipc override of delivered message
1824 * Send a sync ipc message to port and check the servicer of the workloop
1825 * on other side gets sync ipc override and once the handler enables the knote,
1826 * that sync ipc override is dropped.
1828 TEST_QOS("server_kevent_id", "qos_client_send_sync_msg_with_pri", send_sync_UI_and_enable
, "workloop_cb_test_sync_send_and_enable",
1829 QOS_CLASS_DEFAULT
, "default",
1830 QOS_CLASS_DEFAULT
, "default",
1831 QOS_CLASS_USER_INTERACTIVE
, "user initiated with 47 basepri promotion")
1834 * Test 9: test returning to begin processing drops sync ipc override of delivered message
1836 * Send a sync ipc message and check if enabling the knote clears the override of
1837 * the delivered message, but should still have the override of an enqueued message.
1839 TEST_QOS("server_kevent_id", "qos_client_send_two_sync_msg_with_thr_pri", send_two_sync_UI
, "workloop_cb_test_send_two_sync",
1840 QOS_CLASS_BACKGROUND
, "background",
1841 QOS_CLASS_MAINTENANCE
, "maintenance",
1842 QOS_CLASS_USER_INTERACTIVE
, "user initiated with 47 basepri promotion")
1845 * Test 10: test destroying the special reply port drops the override
1847 * Send an async messages and a sync ipc message, the workloop handler
1848 * should get a sync ipc override, now test if destroying the special
1849 * reply port drops the sync ipc override on the servicer.
1851 TEST_QOS("server_kevent_id", "qos_client_send_two_msg_and_destroy", send_two_UI_and_destroy
, "workloop_cb_test_two_send_and_destroy",
1852 QOS_CLASS_BACKGROUND
, "background",
1853 QOS_CLASS_MAINTENANCE
, "maintenance",
1854 QOS_CLASS_USER_INTERACTIVE
, "user initiated with 47 basepri promotion")
1857 * Test 11: test sending two ports with chaining
1859 * Send a sync IPC to a connection port, which itself is embedded in a message
1860 * sent as a sync IPC to a service port.
1862 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",
1863 QOS_CLASS_USER_INITIATED
, "user initiated",
1864 QOS_CLASS_USER_INITIATED
, "user initiated",
1865 QOS_CLASS_USER_INTERACTIVE
, "user initiated with 47 basepri promotion")
1868 * Test 12: test sending two ports with chaining
1870 * Send a sync IPC to a connection port, which itself is embedded in a message
1871 * sent as a sync IPC to a service port.
1873 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",
1874 QOS_CLASS_USER_INITIATED
, "user initiated",
1875 QOS_CLASS_USER_INITIATED
, "user initiated",
1876 QOS_CLASS_USER_INTERACTIVE
, "user initiated with 47 basepri promotion")
1879 * Test 13: test changing qos of a thread to trigger turnstile push
1881 * Send a sync IPC to a service port and change the qos of the blocked thread
1882 * to verify that changing qos triggers a turnstile push.
1884 TEST_QOS("server_kevent_id", "qos_client_sync_rcv_qos_change", qos_change_to_IN
, "workloop_cb_test_intransit",
1885 QOS_CLASS_DEFAULT
, "default",
1886 QOS_CLASS_MAINTENANCE
, "maintenance",
1887 QOS_CLASS_USER_INITIATED
, "user initiated")
1892 * Test single sync ipc link with server that breaks/preserves the link in different ways.
1894 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",
1895 QOS_CLASS_DEFAULT
, "default",
1896 QOS_CLASS_DEFAULT
, "default",
1897 QOS_CLASS_DEFAULT
, "default")
1899 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",
1900 QOS_CLASS_DEFAULT
, "default",
1901 QOS_CLASS_DEFAULT
, "default",
1902 QOS_CLASS_DEFAULT
, "default")
1904 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",
1905 QOS_CLASS_DEFAULT
, "default",
1906 QOS_CLASS_DEFAULT
, "default",
1907 QOS_CLASS_DEFAULT
, "default")
1909 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",
1910 QOS_CLASS_DEFAULT
, "default",
1911 QOS_CLASS_DEFAULT
, "default",
1912 QOS_CLASS_DEFAULT
, "default")
1914 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",
1915 QOS_CLASS_DEFAULT
, "default",
1916 QOS_CLASS_DEFAULT
, "default",
1917 QOS_CLASS_DEFAULT
, "default")
1919 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",
1920 QOS_CLASS_DEFAULT
, "default",
1921 QOS_CLASS_DEFAULT
, "default",
1922 QOS_CLASS_DEFAULT
, "default")
1924 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",
1925 QOS_CLASS_DEFAULT
, "default",
1926 QOS_CLASS_DEFAULT
, "default",
1927 QOS_CLASS_DEFAULT
, "default")
1929 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",
1930 QOS_CLASS_DEFAULT
, "default",
1931 QOS_CLASS_DEFAULT
, "default",
1932 QOS_CLASS_DEFAULT
, "default")
1937 * Test sequential sync ipc link with server that breaks/preserves the link.
1939 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",
1940 QOS_CLASS_DEFAULT
, "default",
1941 QOS_CLASS_DEFAULT
, "default",
1942 QOS_CLASS_DEFAULT
, "default")
1944 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",
1945 QOS_CLASS_DEFAULT
, "default",
1946 QOS_CLASS_DEFAULT
, "default",
1947 QOS_CLASS_DEFAULT
, "default")
1949 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",
1950 QOS_CLASS_DEFAULT
, "default",
1951 QOS_CLASS_DEFAULT
, "default",
1952 QOS_CLASS_DEFAULT
, "default")
1954 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",
1955 QOS_CLASS_DEFAULT
, "default",
1956 QOS_CLASS_DEFAULT
, "default",
1957 QOS_CLASS_DEFAULT
, "default")