]>
Commit | Line | Data |
---|---|---|
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 | ||
30 | #define ARRAYLEN(arr) (sizeof(arr) / sizeof(arr[0])) | |
31 | ||
32 | #define INTERMITTENT_TIMEOUT_SEC (3) | |
33 | #define RECV_TIMEOUT_SECS (4) | |
34 | #define SEND_TIMEOUT_SECS (6) | |
35 | #define HELPER_TIMEOUT_SECS (15) | |
36 | ||
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"}; | |
40 | ||
41 | #define ENV_VAR_FUNCTION (1) | |
42 | static const char *wl_function_name = "XNU_TEST_WL_FUNCTION"; | |
43 | ||
44 | static qos_class_t g_expected_qos[ENV_VAR_QOS]; | |
45 | static const char *g_expected_qos_name[ENV_VAR_QOS]; | |
46 | ||
47 | #define ENV_QOS_BEFORE_OVERRIDE (0) | |
48 | #define ENV_QOS_QUEUE_OVERRIDE (1) | |
49 | #define ENV_QOS_AFTER_OVERRIDE (2) | |
50 | ||
51 | struct test_msg { | |
52 | mach_msg_header_t header; | |
53 | mach_msg_body_t body; | |
54 | mach_msg_port_descriptor_t port_descriptor; | |
55 | mach_msg_option_t opts; | |
56 | mach_msg_priority_t qos; | |
57 | }; | |
58 | ||
59 | #pragma mark pthread callbacks | |
60 | ||
61 | static pthread_t | |
62 | thread_create_at_qos(qos_class_t qos, void * (*function)(void *)); | |
63 | static 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); | |
65 | static void | |
66 | enable_kevent(uint64_t *workloop_id, unsigned long long port); | |
67 | static void | |
68 | populate_kevent(struct kevent_qos_s *kev, unsigned long long port); | |
69 | ||
70 | static void | |
71 | worker_cb(pthread_priority_t __unused priority) | |
72 | { | |
73 | T_FAIL("a worker thread was created"); | |
74 | } | |
75 | ||
76 | static void | |
77 | event_cb(void ** __unused events, int * __unused nevents) | |
78 | { | |
79 | T_FAIL("a kevent routine was called instead of workloop"); | |
80 | } | |
81 | ||
82 | static uint32_t | |
83 | get_user_promotion_basepri(void) | |
84 | { | |
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()); | |
89 | ||
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; | |
94 | } | |
95 | ||
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__); \ | |
100 | } else { \ | |
101 | T_EXPECT_EFFECTIVE_QOS_EQ(qos, __VA_ARGS__); \ | |
102 | } \ | |
103 | } while (0) | |
104 | ||
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"); \ | |
114 | } \ | |
115 | } while (0) | |
116 | ||
117 | /* | |
118 | * Basic WL handler callback, it sleeps for n seconds and then checks the | |
119 | * effective Qos of the servicer thread. | |
120 | */ | |
121 | static void | |
122 | workloop_cb_test_intransit(uint64_t *workloop_id __unused, void **eventslist, int *events) | |
123 | { | |
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); | |
127 | ||
128 | EXPECT_TEST_MSG(*eventslist); | |
129 | ||
130 | /* Wait for the client to send the high priority message to override the qos */ | |
131 | sleep(2 * RECV_TIMEOUT_SECS); | |
132 | ||
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."); | |
136 | } | |
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 | |
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 | if (geteuid() != 0) { | |
157 | T_SKIP("kevent_qos test requires root privileges to run."); | |
158 | } | |
159 | ||
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]); | |
163 | ||
164 | *events = 0; | |
165 | T_END; | |
166 | } | |
167 | ||
168 | /* | |
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. | |
171 | */ | |
172 | static void | |
173 | workloop_cb_test_sync_send_and_enable(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events) | |
174 | { | |
175 | unsigned override_priority; | |
176 | unsigned reenable_priority; | |
177 | ||
178 | T_LOG("Workloop handler workloop_cb_test_sync_send_and_enable called"); | |
179 | ||
180 | EXPECT_TEST_MSG(*eventslist); | |
181 | ||
182 | if (geteuid() != 0) { | |
183 | T_SKIP("kevent_qos test requires root privileges to run."); | |
184 | } | |
185 | ||
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]); | |
189 | ||
190 | /* Snapshot the current override priority */ | |
191 | override_priority = get_user_promotion_basepri(); | |
192 | ||
193 | /* Enable the knote */ | |
194 | struct kevent_qos_s *kev = *eventslist; | |
195 | enable_kevent(workloop_id, kev->ident); | |
196 | ||
197 | /* | |
198 | * Check if the override has been dropped, check for priority instead of qos since | |
199 | * there will be async qos push. | |
200 | */ | |
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); | |
205 | ||
206 | *events = 0; | |
207 | T_END; | |
208 | } | |
209 | ||
210 | /* | |
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. | |
213 | */ | |
214 | static void | |
215 | workloop_cb_test_sync_send_and_enable_handoff(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events) | |
216 | { | |
217 | unsigned override_priority; | |
218 | int error; | |
219 | ||
220 | T_LOG("Workloop handler workloop_cb_test_sync_send_and_enable_handoff called"); | |
221 | ||
222 | EXPECT_TEST_MSG(*eventslist); | |
223 | ||
224 | if (geteuid() != 0) { | |
225 | T_SKIP("kevent_qos test requires root privileges to run."); | |
226 | } | |
227 | ||
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]); | |
232 | ||
233 | /* Snapshot the current override priority */ | |
234 | override_priority = get_user_promotion_basepri(); | |
235 | ||
236 | struct kevent_qos_s *kev = *eventslist; | |
237 | mach_msg_header_t *hdr = (mach_msg_header_t *)kev->ext[0]; | |
238 | ||
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, | |
245 | }; | |
246 | ||
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"); | |
251 | ||
252 | /* Enable the knote */ | |
253 | enable_kevent(workloop_id, kev->ident); | |
254 | ||
255 | /* | |
256 | * Check if the override has not been dropped. | |
257 | */ | |
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]); | |
261 | ||
262 | *events = 0; | |
263 | T_END; | |
264 | } | |
265 | ||
266 | /* | |
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. | |
269 | */ | |
270 | static int send_two_sync_handler_called = 0; | |
271 | static void | |
272 | workloop_cb_test_send_two_sync(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events) | |
273 | { | |
274 | T_LOG("Workloop handler workloop_cb_test_send_two_sync called for %d time", send_two_sync_handler_called + 1); | |
275 | ||
276 | EXPECT_TEST_MSG(*eventslist); | |
277 | ||
278 | if (geteuid() != 0) { | |
279 | T_SKIP("kevent_qos test requires root privileges to run."); | |
280 | } | |
281 | ||
282 | T_LOG("Number of events received is %d\n", *events); | |
283 | ||
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]); | |
288 | ||
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); | |
293 | *events = 1; | |
294 | } else { | |
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]); | |
297 | *events = 0; | |
298 | T_END; | |
299 | } | |
300 | send_two_sync_handler_called++; | |
301 | } | |
302 | ||
303 | /* | |
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. | |
306 | */ | |
307 | static boolean_t two_send_and_destroy_test_passed = FALSE; | |
308 | static int two_send_and_destroy_handler = 0; | |
309 | static void | |
310 | workloop_cb_test_two_send_and_destroy(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist __unused, int *events) | |
311 | { | |
312 | T_LOG("Workloop handler workloop_cb_test_two_send_and_destroy called %d times", two_send_and_destroy_handler + 1); | |
313 | ||
314 | EXPECT_TEST_MSG(*eventslist); | |
315 | ||
316 | if (geteuid() != 0) { | |
317 | T_SKIP("kevent_qos test requires root privileges to run."); | |
318 | } | |
319 | ||
320 | if (two_send_and_destroy_handler == 0) { | |
321 | /* Sleep to make sure the mqueue gets full */ | |
322 | sleep(RECV_TIMEOUT_SECS); | |
323 | ||
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]); | |
327 | ||
328 | sleep(SEND_TIMEOUT_SECS); | |
329 | ||
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]); | |
333 | ||
334 | two_send_and_destroy_test_passed = TRUE; | |
335 | } else { | |
336 | if (two_send_and_destroy_test_passed) { | |
337 | T_END; | |
338 | } | |
339 | } | |
340 | ||
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); | |
345 | *events = 1; | |
346 | two_send_and_destroy_handler++; | |
347 | T_LOG("Handler returning \n"); | |
348 | } | |
349 | ||
350 | static mach_port_type_t | |
351 | get_reply_port(struct kevent_qos_s *kev) | |
352 | { | |
353 | mach_msg_header_t *hdr; | |
354 | mach_port_t reply_port; | |
355 | mach_port_type_t type; | |
356 | kern_return_t kr; | |
357 | ||
358 | hdr = (void*)kev->ext[0]; | |
359 | T_QUIET; T_ASSERT_NOTNULL(hdr, "msg hdr"); | |
360 | ||
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"); | |
366 | ||
367 | return reply_port; | |
368 | } | |
369 | ||
370 | static void | |
371 | send_reply(mach_port_t reply_port) | |
372 | { | |
373 | kern_return_t kr; | |
374 | ||
375 | struct { | |
376 | mach_msg_header_t header; | |
377 | } send_msg = { | |
378 | .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), | |
382 | .msgh_id = 0x100, | |
383 | .msgh_size = sizeof(send_msg), | |
384 | }, | |
385 | }; | |
386 | ||
387 | kr = mach_msg(&(send_msg.header), | |
388 | MACH_SEND_MSG, | |
389 | send_msg.header.msgh_size, | |
390 | 0, | |
391 | MACH_PORT_NULL, | |
392 | 0, | |
393 | 0); | |
394 | ||
395 | T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "server mach_msg"); | |
396 | } | |
397 | ||
398 | static void | |
399 | populate_kevent(struct kevent_qos_s *kev, unsigned long long port) | |
400 | { | |
401 | memset(kev, 0, sizeof(struct kevent_qos_s)); | |
402 | kev->ident = port; | |
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_CTX) | | |
407 | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)); | |
408 | kev->data = 1; | |
409 | } | |
410 | ||
411 | static void | |
412 | enable_kevent(uint64_t *workloop_id, unsigned long long port) | |
413 | { | |
414 | struct kevent_qos_s kev; | |
415 | int error; | |
416 | ||
417 | populate_kevent(&kev, port); | |
418 | struct kevent_qos_s kev_err[] = {{ 0 }}; | |
419 | ||
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"); | |
423 | } | |
424 | ||
425 | /* | |
426 | * WL handler which sends a msg to the client from handler. | |
427 | */ | |
428 | static void | |
429 | workloop_cb_test_sync_send_reply(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events) | |
430 | { | |
431 | T_LOG("Workloop handler workloop_cb_test_sync_send_reply called"); | |
432 | ||
433 | if (geteuid() != 0) { | |
434 | T_SKIP("kevent_qos test requires root privileges to run."); | |
435 | } | |
436 | ||
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"); | |
439 | ||
440 | /* send reply */ | |
441 | send_reply(get_reply_port(*eventslist)); | |
442 | ||
443 | *events = 0; | |
444 | } | |
445 | ||
446 | /* | |
447 | * WL handler which deallocates reply port. | |
448 | */ | |
449 | static void | |
450 | workloop_cb_test_sync_send_deallocate(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events) | |
451 | { | |
452 | mach_port_t reply_port; | |
453 | kern_return_t kr; | |
454 | ||
455 | T_LOG("Workloop handler workloop_cb_test_sync_send_deallocate called"); | |
456 | ||
457 | if (geteuid() != 0) { | |
458 | T_SKIP("kevent_qos test requires root privileges to run."); | |
459 | } | |
460 | ||
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"); | |
463 | ||
464 | reply_port = get_reply_port(*eventslist); | |
465 | ||
466 | /* deallocate port */ | |
467 | kr = mach_port_deallocate(mach_task_self(), reply_port); | |
468 | ||
469 | T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_deallocate"); | |
470 | ||
471 | *events = 0; | |
472 | ||
473 | T_LOG("Handler returning \n"); | |
474 | } | |
475 | ||
476 | ||
477 | /* | |
478 | * WL handler which sends a msg to the client before enabling the event from handler. | |
479 | */ | |
480 | static void | |
481 | workloop_cb_test_sync_send_reply_kevent(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events) | |
482 | { | |
483 | T_LOG("Workloop handler workloop_cb_test_sync_send_reply_kevent called"); | |
484 | ||
485 | if (geteuid() != 0) { | |
486 | T_SKIP("kevent_qos test requires root privileges to run."); | |
487 | } | |
488 | ||
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"); | |
491 | ||
492 | struct kevent_qos_s *kev = *eventslist; | |
493 | ||
494 | /* send reply */ | |
495 | send_reply(get_reply_port(kev)); | |
496 | ||
497 | /* Enable the knote */ | |
498 | enable_kevent(workloop_id, kev->ident); | |
499 | ||
500 | *events = 0; | |
501 | ||
502 | T_LOG("Handler returning \n"); | |
503 | } | |
504 | ||
505 | /* | |
506 | * WL handler which sends a msg to the client before enabling the event from pthread. | |
507 | */ | |
508 | static void | |
509 | workloop_cb_test_sync_send_reply_kevent_pthread(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events) | |
510 | { | |
511 | T_LOG("Workloop handler workloop_cb_test_sync_send_reply_kevent_pthread called"); | |
512 | ||
513 | if (geteuid() != 0) { | |
514 | T_SKIP("kevent_qos test requires root privileges to run."); | |
515 | } | |
516 | ||
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"); | |
519 | ||
520 | struct kevent_qos_s *kev = *eventslist; | |
521 | ||
522 | /* send reply */ | |
523 | send_reply(get_reply_port(kev)); | |
524 | ||
525 | populate_kevent(kev, kev->ident); | |
526 | ||
527 | *events = 1; | |
528 | ||
529 | T_LOG("Handler returning \n"); | |
530 | } | |
531 | ||
532 | /* | |
533 | * WL handler which sends a msg to the client after reenabling the event. | |
534 | */ | |
535 | static void | |
536 | workloop_cb_test_sync_send_kevent_reply(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events) | |
537 | { | |
538 | T_LOG("workloop handler workloop_cb_test_sync_send_kevent_reply called"); | |
539 | ||
540 | if (geteuid() != 0) { | |
541 | T_SKIP("kevent_qos test requires root privileges to run."); | |
542 | } | |
543 | ||
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"); | |
546 | ||
547 | struct kevent_qos_s *kev = *eventslist; | |
548 | mach_port_t reply_port = get_reply_port(*eventslist); | |
549 | ||
550 | /* Enable the knote */ | |
551 | enable_kevent(workloop_id, kev->ident); | |
552 | ||
553 | /* send reply */ | |
554 | send_reply(reply_port); | |
555 | ||
556 | *events = 0; | |
557 | ||
558 | T_LOG("Handler returning \n"); | |
559 | } | |
560 | ||
561 | /* | |
562 | * WL handler that does nothing. | |
563 | */ | |
564 | static void | |
565 | workloop_cb_test_sync_send_do_nothing(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events) | |
566 | { | |
567 | T_LOG("Workloop handler workloop_cb_test_sync_send_do_nothing called"); | |
568 | ||
569 | if (geteuid() != 0) { | |
570 | T_SKIP("kevent_qos test requires root privileges to run."); | |
571 | } | |
572 | ||
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"); | |
575 | ||
576 | /* do nothing */ | |
577 | ||
578 | *events = 0; | |
579 | ||
580 | T_LOG("Handler returning \n"); | |
581 | } | |
582 | ||
583 | /* | |
584 | * WL handler that returns the event to reenable. | |
585 | */ | |
586 | static void | |
587 | workloop_cb_test_sync_send_do_nothing_kevent_pthread(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events) | |
588 | { | |
589 | T_LOG("Workloop handler workloop_cb_test_sync_send_do_nothing_kevent_pthread called"); | |
590 | ||
591 | if (geteuid() != 0) { | |
592 | T_SKIP("kevent_qos test requires root privileges to run."); | |
593 | } | |
594 | ||
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"); | |
597 | ||
598 | struct kevent_qos_s *kev = *eventslist; | |
599 | populate_kevent(kev, kev->ident); | |
600 | ||
601 | *events = 1; | |
602 | ||
603 | T_LOG("handler returning \n"); | |
604 | } | |
605 | ||
606 | /* | |
607 | * WL handler that exits. | |
608 | */ | |
609 | static void | |
610 | workloop_cb_test_sync_send_do_nothing_exit(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, __unused int *events) | |
611 | { | |
612 | T_LOG("workloop handler workloop_cb_test_sync_send_do_nothing_exit called"); | |
613 | ||
614 | if (geteuid() != 0) { | |
615 | T_SKIP("kevent_qos test requires root privileges to run."); | |
616 | } | |
617 | ||
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"); | |
620 | ||
621 | /* call exit */ | |
622 | exit(0); | |
623 | } | |
624 | ||
625 | /* | |
626 | * WL handler which: | |
627 | * first sync sends a msg to the client and reenables kevent after | |
628 | * second sync sends a msg and reenables kevent after. | |
629 | */ | |
630 | static void | |
631 | workloop_cb_test_sync_send_reply_kevent_reply_kevent(uint64_t *workloop_id __unused, struct kevent_qos_s **eventslist, int *events) | |
632 | { | |
633 | T_LOG("Workloop handler workloop_cb_test_sync_send_reply_kevent_reply_kevent called"); | |
634 | ||
635 | if (geteuid() != 0) { | |
636 | T_SKIP("kevent_qos test requires root privileges to run."); | |
637 | } | |
638 | ||
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"); | |
641 | ||
642 | struct kevent_qos_s *kev = *eventslist; | |
643 | ||
644 | /* send reply */ | |
645 | send_reply(get_reply_port(kev)); | |
646 | ||
647 | populate_kevent(kev, kev->ident); | |
648 | ||
649 | *events = 1; | |
650 | ||
651 | T_LOG("Handler returning \n"); | |
652 | } | |
653 | ||
654 | /* | |
655 | * WL handler which: | |
656 | * first sync reenables kevent and after sends a msg | |
657 | * second sync sends a msg and reenables kevent after. | |
658 | */ | |
659 | static int workloop_cb_test_sync_send_kevent_reply_reply_kevent_handler_called = 0; | |
660 | static void | |
661 | workloop_cb_test_sync_send_kevent_reply_reply_kevent(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events) | |
662 | { | |
663 | T_LOG("workloop handler workloop_cb_test_sync_send_kevent_reply_reply_kevent called"); | |
664 | ||
665 | if (geteuid() != 0) { | |
666 | T_SKIP("kevent_qos test requires root privileges to run."); | |
667 | } | |
668 | ||
669 | T_QUIET; T_ASSERT_EQ_INT(*events, 1, "events received"); | |
670 | T_QUIET; T_ASSERT_EQ_INT((*eventslist)->filter, EVFILT_MACHPORT, "received EVFILT_MACHPORT"); | |
671 | ||
672 | struct kevent_qos_s *kev = *eventslist; | |
673 | mach_port_t reply_port = get_reply_port(kev); | |
674 | ||
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; | |
677 | ||
678 | /* Enable the knote */ | |
679 | enable_kevent(workloop_id, kev->ident); | |
680 | ||
681 | /* send reply */ | |
682 | send_reply(reply_port); | |
683 | ||
684 | *events = 0; | |
685 | } else { | |
686 | /* send reply */ | |
687 | send_reply(reply_port); | |
688 | ||
689 | /* Enable the knote */ | |
690 | enable_kevent(workloop_id, kev->ident); | |
691 | ||
692 | *events = 0; | |
693 | } | |
694 | ||
695 | T_LOG("Handler returning \n"); | |
696 | } | |
697 | ||
698 | /* | |
699 | * WL handler which: | |
700 | * first sync reenables kevent and after sends a msg | |
701 | * second sync reenables kevent and after sends a msg | |
702 | */ | |
703 | static void | |
704 | workloop_cb_test_sync_send_kevent_reply_kevent_reply(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events) | |
705 | { | |
706 | T_LOG("workloop handler workloop_cb_test_sync_send_kevent_reply_kevent_reply called"); | |
707 | ||
708 | if (geteuid() != 0) { | |
709 | T_SKIP("kevent_qos test requires root privileges to run."); | |
710 | } | |
711 | ||
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"); | |
714 | ||
715 | struct kevent_qos_s *kev = *eventslist; | |
716 | mach_port_t reply_port = get_reply_port(kev); | |
717 | ||
718 | /* Enable the knote */ | |
719 | enable_kevent(workloop_id, kev->ident); | |
720 | ||
721 | /* send reply */ | |
722 | send_reply(reply_port); | |
723 | ||
724 | *events = 0; | |
725 | T_LOG("Handler returning \n"); | |
726 | } | |
727 | ||
728 | /* | |
729 | * WL handler which: | |
730 | * first sync ends a msg and reenables kevent after | |
731 | * second sync reenables kevent and sends a msg after | |
732 | */ | |
733 | static int workloop_cb_test_sync_send_reply_kevent_kevent_reply_handler_called = 0; | |
734 | static void | |
735 | workloop_cb_test_sync_send_reply_kevent_kevent_reply(uint64_t *workloop_id, struct kevent_qos_s **eventslist, int *events) | |
736 | { | |
737 | T_LOG("workloop handler workloop_cb_test_sync_send_reply_kevent_kevent_reply called"); | |
738 | ||
739 | if (geteuid() != 0) { | |
740 | T_SKIP("kevent_qos test requires root privileges to run."); | |
741 | } | |
742 | ||
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"); | |
745 | ||
746 | struct kevent_qos_s *kev = *eventslist; | |
747 | mach_port_t reply_port = get_reply_port(kev); | |
748 | ||
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; | |
751 | ||
752 | /* send reply */ | |
753 | send_reply(reply_port); | |
754 | ||
755 | populate_kevent(kev, kev->ident); | |
756 | ||
757 | *events = 1; | |
758 | } else { | |
759 | /* Enable the knote */ | |
760 | enable_kevent(workloop_id, kev->ident); | |
761 | /* send reply */ | |
762 | send_reply(reply_port); | |
763 | ||
764 | *events = 0; | |
765 | } | |
766 | ||
767 | T_LOG("Handler returning \n"); | |
768 | } | |
769 | #pragma mark Mach receive | |
770 | ||
771 | #define KEVENT_QOS_SERVICE_NAME "com.apple.xnu.test.kevent_qos" | |
772 | ||
773 | static mach_port_t | |
774 | get_server_port(void) | |
775 | { | |
776 | mach_port_t port; | |
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"); | |
780 | return port; | |
781 | } | |
782 | ||
783 | static void | |
784 | env_set_qos(char **env, qos_class_t qos[], const char *qos_name[], const char *wl_function) | |
785 | { | |
786 | int i; | |
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]), | |
790 | NULL); | |
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; | |
795 | } | |
796 | T_QUIET; T_ASSERT_POSIX_SUCCESS(asprintf(&env[2 * i], "%s=%s", wl_function_name, wl_function), | |
797 | NULL); | |
798 | env[2 * i + 1] = NULL; | |
799 | } | |
800 | ||
801 | static void | |
802 | environ_get_qos(qos_class_t qos[], const char *qos_name[], const char **wl_function) | |
803 | { | |
804 | char *qos_str; | |
805 | char *qos_end; | |
806 | int i; | |
807 | ||
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]); | |
811 | ||
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); | |
815 | ||
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); | |
818 | ||
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]); | |
822 | } | |
823 | *wl_function = getenv(wl_function_name); | |
824 | T_QUIET; T_ASSERT_NOTNULL(*wl_function, "getenv(%s)", wl_function_name); | |
825 | } | |
826 | ||
827 | static mach_voucher_t | |
828 | create_pthpriority_voucher(mach_msg_priority_t qos) | |
829 | { | |
830 | char voucher_buf[sizeof(mach_voucher_attr_recipe_data_t) + sizeof(ipc_pthread_priority_value_t)]; | |
831 | ||
832 | mach_voucher_t voucher = MACH_PORT_NULL; | |
833 | kern_return_t ret; | |
834 | ipc_pthread_priority_value_t ipc_pthread_priority_value = | |
835 | (ipc_pthread_priority_value_t)qos; | |
836 | ||
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]; | |
841 | ||
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; | |
848 | ||
849 | recipes = (mach_voucher_attr_raw_recipe_array_t)&voucher_buf[0]; | |
850 | ||
851 | ret = host_create_mach_voucher(mach_host_self(), | |
852 | recipes, | |
853 | recipe_size, | |
854 | &voucher); | |
855 | ||
856 | T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "client host_create_mach_voucher"); | |
857 | return voucher; | |
858 | } | |
859 | ||
860 | static void | |
861 | send( | |
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) | |
867 | { | |
868 | kern_return_t ret = 0; | |
869 | ||
870 | struct test_msg send_msg = { | |
871 | .header = { | |
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), | |
878 | .msgh_id = 0x100, | |
879 | .msgh_size = sizeof(send_msg), | |
880 | }, | |
881 | .body = { | |
882 | .msgh_descriptor_count = 1, | |
883 | }, | |
884 | .port_descriptor = { | |
885 | .name = msg_port, | |
886 | .disposition = MACH_MSG_TYPE_MOVE_RECEIVE, | |
887 | .type = MACH_MSG_PORT_DESCRIPTOR, | |
888 | }, | |
889 | .opts = options, | |
890 | }; | |
891 | ||
892 | if (msg_port == MACH_PORT_NULL) { | |
893 | send_msg.body.msgh_descriptor_count = 0; | |
894 | } | |
895 | ||
896 | if ((options & MACH_SEND_PROPAGATE_QOS) == 0) { | |
897 | send_msg.header.msgh_voucher_port = create_pthpriority_voucher(qos); | |
898 | send_msg.qos = qos; | |
899 | } else { | |
900 | qos_class_t qc; | |
901 | int relpri; | |
902 | pthread_get_qos_class_np(pthread_self(), &qc, &relpri); | |
903 | send_msg.qos = (uint32_t)_pthread_qos_class_encode(qc, relpri, 0); | |
904 | } | |
905 | ||
906 | mach_msg_option_t send_opts = options; | |
907 | if (reply_port) { | |
908 | send_opts |= MACH_SEND_SYNC_OVERRIDE; | |
909 | } | |
910 | send_opts |= MACH_SEND_MSG | MACH_SEND_TIMEOUT | MACH_SEND_OVERRIDE; | |
911 | ||
912 | ret = mach_msg(&send_msg.header, send_opts, send_msg.header.msgh_size, | |
913 | 0, MACH_PORT_NULL, 10000, qos); | |
914 | ||
915 | T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "client mach_msg"); | |
916 | } | |
917 | ||
918 | static kern_return_t | |
919 | receive( | |
920 | mach_port_t rcv_port, | |
921 | mach_port_t notify_port) | |
922 | { | |
923 | kern_return_t ret = 0; | |
924 | ||
925 | struct test_msg rcv_msg = { | |
926 | .header = { | |
927 | .msgh_remote_port = MACH_PORT_NULL, | |
928 | .msgh_local_port = rcv_port, | |
929 | .msgh_size = sizeof(rcv_msg), | |
930 | }, | |
931 | }; | |
932 | ||
933 | T_LOG("Client: Starting sync receive\n"); | |
934 | ||
935 | ret = mach_msg(&(rcv_msg.header), | |
936 | MACH_RCV_MSG | | |
937 | MACH_RCV_TIMEOUT | | |
938 | MACH_RCV_SYNC_WAIT, | |
939 | 0, | |
940 | rcv_msg.header.msgh_size, | |
941 | rcv_port, | |
942 | SEND_TIMEOUT_SECS * 1000, | |
943 | notify_port); | |
944 | ||
945 | return ret; | |
946 | } | |
947 | ||
948 | T_HELPER_DECL(qos_get_special_reply_port, | |
949 | "Test get_special_reply_port and it's corner cases.") | |
950 | { | |
951 | mach_port_t special_reply_port; | |
952 | mach_port_t new_special_reply_port; | |
953 | ||
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"); | |
956 | ||
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"); | |
959 | ||
960 | mach_port_destroy(mach_task_self(), special_reply_port); | |
961 | mach_port_destroy(mach_task_self(), new_special_reply_port); | |
962 | ||
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"); | |
965 | ||
966 | T_END; | |
967 | } | |
968 | ||
969 | static void * | |
970 | qos_client_send_to_intransit(void *arg __unused) | |
971 | { | |
972 | mach_port_t qos_send_port; | |
973 | mach_port_t msg_port; | |
974 | mach_port_t special_reply_port; | |
975 | ||
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"); | |
979 | ||
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"); | |
982 | ||
983 | /* Create a rcv right to send in a msg */ | |
984 | kr = mach_port_allocate(mach_task_self(), | |
985 | MACH_PORT_RIGHT_RECEIVE, | |
986 | &msg_port); | |
987 | ||
988 | T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client mach_port_allocate"); | |
989 | ||
990 | kr = mach_port_insert_right(mach_task_self(), | |
991 | msg_port, | |
992 | msg_port, | |
993 | MACH_MSG_TYPE_MAKE_SEND); | |
994 | ||
995 | T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client mach_port_insert_right"); | |
996 | ||
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); | |
1000 | ||
1001 | /* Sleep 3 seconds for the server to start */ | |
1002 | sleep(3); | |
1003 | ||
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); | |
1007 | ||
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); | |
1012 | } | |
1013 | ||
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"); | |
1019 | ||
1020 | T_ASSERT_FAIL("client timed out"); | |
1021 | return NULL; | |
1022 | } | |
1023 | ||
1024 | T_HELPER_DECL(qos_client_send_to_intransit_with_thr_pri, | |
1025 | "Send synchronous messages from a pri thread to an intransit port") | |
1026 | { | |
1027 | thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE], qos_client_send_to_intransit); | |
1028 | sleep(HELPER_TIMEOUT_SECS); | |
1029 | } | |
1030 | ||
1031 | static pthread_t | |
1032 | thread_create_at_qos(qos_class_t qos, void * (*function)(void *)) | |
1033 | { | |
1034 | qos_class_t qos_thread; | |
1035 | pthread_t thread; | |
1036 | pthread_attr_t attr; | |
1037 | int ret; | |
1038 | ||
1039 | ret = setpriority(PRIO_DARWIN_ROLE, 0, PRIO_DARWIN_ROLE_UI_FOCAL); | |
1040 | if (ret != 0) { | |
1041 | T_LOG("set priority failed\n"); | |
1042 | } | |
1043 | ||
1044 | pthread_attr_init(&attr); | |
1045 | pthread_attr_set_qos_class_np(&attr, qos, 0); | |
1046 | pthread_create(&thread, &attr, function, NULL); | |
1047 | ||
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); | |
1051 | return thread; | |
1052 | } | |
1053 | ||
1054 | static void * | |
1055 | qos_send_and_sync_rcv(void *arg __unused) | |
1056 | { | |
1057 | mach_port_t qos_send_port; | |
1058 | mach_port_t special_reply_port; | |
1059 | ||
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]); | |
1063 | ||
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"); | |
1067 | ||
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"); | |
1070 | ||
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); | |
1074 | ||
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); | |
1077 | ||
1078 | sleep(SEND_TIMEOUT_SECS); | |
1079 | ||
1080 | /* sync wait on msg port */ | |
1081 | receive(special_reply_port, qos_send_port); | |
1082 | ||
1083 | T_LOG("Client done doing sync rcv, now waiting for server to end the test"); | |
1084 | sleep(SEND_TIMEOUT_SECS); | |
1085 | ||
1086 | T_ASSERT_FAIL("client timed out"); | |
1087 | return NULL; | |
1088 | } | |
1089 | ||
1090 | static void * | |
1091 | qos_sync_rcv(void *arg __unused) | |
1092 | { | |
1093 | mach_port_t qos_send_port; | |
1094 | mach_port_t special_reply_port; | |
1095 | ||
1096 | T_LOG("Client: from created thread\n"); | |
1097 | ||
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"); | |
1101 | ||
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"); | |
1104 | ||
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); | |
1108 | ||
1109 | sleep(RECV_TIMEOUT_SECS); | |
1110 | ||
1111 | /* sync wait on msg port */ | |
1112 | receive(special_reply_port, qos_send_port); | |
1113 | ||
1114 | T_LOG("Client done doing sync rcv, now waiting for server to end the test"); | |
1115 | sleep(SEND_TIMEOUT_SECS); | |
1116 | ||
1117 | T_ASSERT_FAIL("client timed out"); | |
1118 | return NULL; | |
1119 | } | |
1120 | ||
1121 | static void | |
1122 | thread_wait_to_block(mach_port_t thread_port) | |
1123 | { | |
1124 | thread_extended_info_data_t extended_info; | |
1125 | kern_return_t kr; | |
1126 | ||
1127 | while (1) { | |
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); | |
1131 | ||
1132 | T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_info"); | |
1133 | ||
1134 | if (extended_info.pth_run_state == TH_STATE_WAITING) { | |
1135 | T_LOG("Target thread blocked\n"); | |
1136 | break; | |
1137 | } | |
1138 | thread_switch(thread_port, SWITCH_OPTION_DEPRESS, 0); | |
1139 | } | |
1140 | } | |
1141 | ||
1142 | T_HELPER_DECL(qos_client_send_sync_and_sync_rcv, | |
1143 | "Send messages and syncronously wait for rcv") | |
1144 | { | |
1145 | thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE], qos_send_and_sync_rcv); | |
1146 | sleep(HELPER_TIMEOUT_SECS); | |
1147 | } | |
1148 | ||
1149 | T_HELPER_DECL(qos_client_sync_rcv_qos_change, | |
1150 | "Send messages and syncronously wait for rcv and change qos of waiting thread") | |
1151 | { | |
1152 | pthread_t rcv_thread; | |
1153 | ||
1154 | rcv_thread = thread_create_at_qos(g_expected_qos[ENV_QOS_BEFORE_OVERRIDE], qos_sync_rcv); | |
1155 | ||
1156 | T_LOG("Waiting for %d seconds before changing qos of rcv thread", SEND_TIMEOUT_SECS); | |
1157 | sleep(SEND_TIMEOUT_SECS); | |
1158 | ||
1159 | /* Wait for the thread to block */ | |
1160 | thread_wait_to_block(pthread_mach_thread_np(rcv_thread)); | |
1161 | ||
1162 | /* Update the rcv thread's qos */ | |
1163 | pthread_override_qos_class_start_np(rcv_thread, g_expected_qos[ENV_QOS_AFTER_OVERRIDE], 0); | |
1164 | ||
1165 | sleep(HELPER_TIMEOUT_SECS); | |
1166 | } | |
1167 | ||
1168 | static void * | |
1169 | qos_client_send_sync_msg_and_test_link(void *arg) | |
1170 | { | |
1171 | mach_port_t qos_send_port; | |
1172 | mach_port_t special_reply_port; | |
1173 | boolean_t in_effect = FALSE; | |
1174 | kern_return_t kr; | |
1175 | unsigned long expected_result = (unsigned long) arg; | |
1176 | ||
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"); | |
1180 | ||
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"); | |
1184 | ||
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); | |
1188 | ||
1189 | /* | |
1190 | * wait for the reply | |
1191 | * some tests do not send a msg back so the receive | |
1192 | * might fail | |
1193 | */ | |
1194 | receive(special_reply_port, qos_send_port); | |
1195 | ||
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"); | |
1199 | ||
1200 | if (!in_effect) { | |
1201 | T_LOG("Link was broken"); | |
1202 | } else { | |
1203 | T_LOG("Link correct"); | |
1204 | } | |
1205 | ||
1206 | if (expected_result == 1) { | |
1207 | T_ASSERT_TRUE(in_effect, "special reply port link after rcv"); | |
1208 | } else { | |
1209 | T_ASSERT_FALSE(in_effect, "special reply port link after rcv"); | |
1210 | } | |
1211 | T_END; | |
1212 | } | |
1213 | ||
1214 | static void * | |
1215 | qos_client_send_2sync_msg_and_test_link(void *arg) | |
1216 | { | |
1217 | mach_port_t qos_send_port; | |
1218 | mach_port_t special_reply_port; | |
1219 | boolean_t in_effect = FALSE; | |
1220 | kern_return_t kr; | |
1221 | unsigned long expected_result = (unsigned long) arg; | |
1222 | ||
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"); | |
1226 | ||
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"); | |
1230 | ||
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); | |
1234 | ||
1235 | /* wait for the reply */ | |
1236 | kr = receive(special_reply_port, qos_send_port); | |
1237 | T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "receive"); | |
1238 | ||
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); | |
1242 | ||
1243 | /* wait for the reply */ | |
1244 | kr = receive(special_reply_port, qos_send_port); | |
1245 | T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "receive"); | |
1246 | ||
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"); | |
1250 | ||
1251 | if (!in_effect) { | |
1252 | T_LOG("Link was broken"); | |
1253 | } else { | |
1254 | T_LOG("Link correct"); | |
1255 | } | |
1256 | ||
1257 | if (expected_result == 1) { | |
1258 | T_ASSERT_TRUE(in_effect, "special reply port link after rcv"); | |
1259 | } else { | |
1260 | T_ASSERT_FALSE(in_effect, "special reply port link after rcv"); | |
1261 | } | |
1262 | T_END; | |
1263 | } | |
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") | |
1266 | { | |
1267 | pthread_t thread; | |
1268 | pthread_attr_t attr; | |
1269 | unsigned long expected_result = 1; | |
1270 | ||
1271 | pthread_attr_init(&attr); | |
1272 | pthread_create(&thread, &attr, qos_client_send_sync_msg_and_test_link, (void *)expected_result); | |
1273 | ||
1274 | sleep(HELPER_TIMEOUT_SECS); | |
1275 | } | |
1276 | ||
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") | |
1279 | { | |
1280 | pthread_t thread; | |
1281 | pthread_attr_t attr; | |
1282 | unsigned long expected_result = 0; | |
1283 | ||
1284 | pthread_attr_init(&attr); | |
1285 | pthread_create(&thread, &attr, qos_client_send_sync_msg_and_test_link, (void *)expected_result); | |
1286 | ||
1287 | sleep(HELPER_TIMEOUT_SECS); | |
1288 | } | |
1289 | ||
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") | |
1292 | { | |
1293 | pthread_t thread; | |
1294 | pthread_attr_t attr; | |
1295 | unsigned long expected_result = 1; | |
1296 | ||
1297 | pthread_attr_init(&attr); | |
1298 | pthread_create(&thread, &attr, qos_client_send_2sync_msg_and_test_link, (void *)expected_result); | |
1299 | ||
1300 | sleep(HELPER_TIMEOUT_SECS); | |
1301 | } | |
1302 | ||
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") | |
1305 | { | |
1306 | pthread_t thread; | |
1307 | pthread_attr_t attr; | |
1308 | unsigned long expected_result = 0; | |
1309 | ||
1310 | pthread_attr_init(&attr); | |
1311 | pthread_create(&thread, &attr, qos_client_send_2sync_msg_and_test_link, (void *)expected_result); | |
1312 | ||
1313 | sleep(HELPER_TIMEOUT_SECS); | |
1314 | } | |
1315 | ||
1316 | static void * | |
1317 | qos_client_send_sync_msg(void *arg __unused) | |
1318 | { | |
1319 | mach_port_t qos_send_port; | |
1320 | mach_port_t special_reply_port; | |
1321 | ||
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"); | |
1325 | ||
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"); | |
1328 | ||
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); | |
1332 | ||
1333 | /* wait for the reply */ | |
1334 | receive(special_reply_port, qos_send_port); | |
1335 | ||
1336 | T_LOG("Client done sending messages, now waiting for server to end the test"); | |
1337 | sleep(2 * SEND_TIMEOUT_SECS); | |
1338 | ||
1339 | T_ASSERT_FAIL("client timed out"); | |
1340 | return NULL; | |
1341 | } | |
1342 | ||
1343 | T_HELPER_DECL(qos_client_send_sync_msg_with_pri, | |
1344 | "Send sync message and wait for reply") | |
1345 | { | |
1346 | thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE], qos_client_send_sync_msg); | |
1347 | sleep(HELPER_TIMEOUT_SECS); | |
1348 | } | |
1349 | ||
1350 | static void * | |
1351 | qos_client_send_two_sync_msg_high_qos(void *arg __unused) | |
1352 | { | |
1353 | mach_port_t qos_send_port; | |
1354 | mach_port_t special_reply_port; | |
1355 | ||
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"); | |
1359 | ||
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"); | |
1362 | ||
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); | |
1366 | ||
1367 | /* wait for the reply */ | |
1368 | receive(special_reply_port, qos_send_port); | |
1369 | ||
1370 | T_LOG("Client done sending messages, now waiting for server to end the test"); | |
1371 | sleep(SEND_TIMEOUT_SECS); | |
1372 | ||
1373 | T_ASSERT_FAIL("client timed out"); | |
1374 | return NULL; | |
1375 | } | |
1376 | ||
1377 | static void * | |
1378 | qos_client_send_two_sync_msg_low_qos(void *arg __unused) | |
1379 | { | |
1380 | mach_port_t qos_send_port; | |
1381 | mach_port_t special_reply_port; | |
1382 | ||
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"); | |
1386 | ||
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"); | |
1389 | ||
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); | |
1393 | ||
1394 | /* wait for the reply */ | |
1395 | receive(special_reply_port, qos_send_port); | |
1396 | ||
1397 | T_LOG("Client done sending messages, now waiting for server to end the test"); | |
1398 | sleep(SEND_TIMEOUT_SECS); | |
1399 | ||
1400 | T_ASSERT_FAIL("client timed out"); | |
1401 | return NULL; | |
1402 | } | |
1403 | ||
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") | |
1406 | { | |
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); | |
1411 | } | |
1412 | ||
1413 | static mach_port_t other_thread_reply_port = MACH_PORT_NULL; | |
1414 | static void * | |
1415 | qos_client_destroy_other_threads_port(void *arg __unused) | |
1416 | { | |
1417 | T_LOG("Waiting 6 seconds before destroying other thread's reply port"); | |
1418 | sleep(SEND_TIMEOUT_SECS); | |
1419 | ||
1420 | T_LOG("Destroying other thread's special reply port "); | |
1421 | mach_port_destroy(mach_task_self(), other_thread_reply_port); | |
1422 | ||
1423 | T_LOG("Other thread done destroying "); | |
1424 | sleep(3 * SEND_TIMEOUT_SECS); | |
1425 | ||
1426 | T_ASSERT_FAIL("client timed out"); | |
1427 | return NULL; | |
1428 | } | |
1429 | ||
1430 | static void * | |
1431 | qos_client_create_sepcial_reply_and_spawn_thread(void *arg __unused) | |
1432 | { | |
1433 | mach_port_t qos_send_port; | |
1434 | mach_port_t special_reply_port; | |
1435 | ||
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"); | |
1439 | ||
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"); | |
1442 | ||
1443 | other_thread_reply_port = special_reply_port; | |
1444 | ||
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); | |
1448 | ||
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); | |
1452 | ||
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); | |
1455 | ||
1456 | /* Client starting to receive message */ | |
1457 | receive(special_reply_port, qos_send_port); | |
1458 | ||
1459 | sleep(3 * SEND_TIMEOUT_SECS); | |
1460 | ||
1461 | T_ASSERT_FAIL("client timed out"); | |
1462 | return NULL; | |
1463 | } | |
1464 | ||
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") | |
1467 | { | |
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); | |
1470 | } | |
1471 | ||
1472 | static mach_port_t send_complex_connection_port = MACH_PORT_NULL; | |
1473 | ||
1474 | static void * | |
1475 | qos_client_send_complex_msg_to_service_port(void *arg __unused) | |
1476 | { | |
1477 | mach_port_t svc_port, tsr_port, conn_port; | |
1478 | kern_return_t kr; | |
1479 | ||
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"); | |
1482 | ||
1483 | tsr_port = thread_get_special_reply_port(); | |
1484 | T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(tsr_port), "get_thread_special_reply_port"); | |
1485 | ||
1486 | conn_port = send_complex_connection_port; | |
1487 | ||
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); | |
1492 | ||
1493 | receive(tsr_port, svc_port); | |
1494 | ||
1495 | sleep(3 * SEND_TIMEOUT_SECS); | |
1496 | ||
1497 | T_ASSERT_FAIL("client timed out"); | |
1498 | return NULL; | |
1499 | } | |
1500 | ||
1501 | static void * | |
1502 | qos_client_send_to_connection_then_service_port(void *arg __unused) | |
1503 | { | |
1504 | mach_port_t tsr_port, conn_port; | |
1505 | mach_port_options_t opts = { | |
1506 | .flags = MPO_INSERT_SEND_RIGHT, | |
1507 | }; | |
1508 | kern_return_t kr; | |
1509 | ||
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; | |
1513 | ||
1514 | tsr_port = thread_get_special_reply_port(); | |
1515 | T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(tsr_port), "get_thread_special_reply_port"); | |
1516 | ||
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); | |
1521 | ||
1522 | thread_create_at_qos(g_expected_qos[ENV_QOS_AFTER_OVERRIDE], | |
1523 | qos_client_send_complex_msg_to_service_port); | |
1524 | ||
1525 | receive(tsr_port, conn_port); | |
1526 | ||
1527 | sleep(3 * SEND_TIMEOUT_SECS); | |
1528 | ||
1529 | T_ASSERT_FAIL("client timed out"); | |
1530 | return NULL; | |
1531 | } | |
1532 | ||
1533 | T_HELPER_DECL(qos_client_send_complex_msg_with_pri, | |
1534 | "Send a message with several ports causing links") | |
1535 | { | |
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); | |
1539 | } | |
1540 | ||
1541 | static void | |
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) | |
1544 | { | |
1545 | char *env[2 * ENV_VAR_QOS + ENV_VAR_FUNCTION + 1]; | |
1546 | env_set_qos(env, qos, qos_name, wl_function); | |
1547 | ||
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]; | |
1551 | } | |
1552 | ||
1553 | dt_helper_t helpers[] = { | |
1554 | dt_launchd_helper_env("com.apple.xnu.test.kevent_qos.plist", | |
1555 | server_name, env), | |
1556 | dt_fork_helper(client_name) | |
1557 | }; | |
1558 | dt_run_helpers(helpers, 2, HELPER_TIMEOUT_SECS); | |
1559 | } | |
1560 | ||
1561 | #pragma mark Mach receive - kevent_qos | |
1562 | ||
1563 | static void | |
1564 | expect_kevent_id_recv(mach_port_t port, qos_class_t qos[], const char *qos_name[], const char *wl_function) | |
1565 | { | |
1566 | int r; | |
1567 | ||
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]; | |
1572 | } | |
1573 | ||
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); | |
1646 | } else { | |
1647 | T_ASSERT_FAIL("no workloop function specified \n"); | |
1648 | } | |
1649 | ||
1650 | struct kevent_qos_s kev[] = {{ | |
1651 | .ident = port, | |
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_CTX) | | |
1656 | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)), | |
1657 | .data = 1, | |
1658 | .qos = (int32_t)_pthread_qos_class_encode(qos[ENV_QOS_QUEUE_OVERRIDE], 0, 0) | |
1659 | }}; | |
1660 | ||
1661 | struct kevent_qos_s kev_err[] = {{ 0 }}; | |
1662 | ||
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); | |
1666 | ||
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); | |
1670 | } | |
1671 | ||
1672 | T_HELPER_DECL(server_kevent_id, | |
1673 | "Reply with the QoS that a dispatch source event handler ran with") | |
1674 | { | |
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); | |
1679 | ||
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", | |
1683 | RECV_TIMEOUT_SECS); | |
1684 | } | |
1685 | ||
1686 | static void * | |
1687 | special_reply_port_thread(void *ctxt) | |
1688 | { | |
1689 | kern_return_t ret; | |
1690 | mach_port_t rcv_port = *(mach_port_t *)ctxt; | |
1691 | struct test_msg rcv_msg = { | |
1692 | .header = { | |
1693 | .msgh_remote_port = MACH_PORT_NULL, | |
1694 | .msgh_local_port = rcv_port, | |
1695 | .msgh_size = sizeof(rcv_msg), | |
1696 | }, | |
1697 | }; | |
1698 | ||
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); | |
1701 | ||
1702 | T_EXPECT_EQ(ret, MACH_RCV_TIMED_OUT, "receive should not panic"); | |
1703 | ||
1704 | *(mach_port_t *)ctxt = MACH_PORT_NULL; | |
1705 | ||
1706 | sleep(1); // give some time to pthread_exit | |
1707 | ||
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); | |
1710 | ||
1711 | T_EXPECT_EQ(ret, MACH_RCV_TIMED_OUT, "receive should not panic"); | |
1712 | ||
1713 | T_END; | |
1714 | } | |
1715 | ||
1716 | T_DECL(special_reply_port, "basic special reply port robustness checks", | |
1717 | T_META_RUN_CONCURRENTLY(true)) | |
1718 | { | |
1719 | pthread_t thread; | |
1720 | mach_port_t srp = thread_get_special_reply_port(); | |
1721 | ||
1722 | pthread_create(&thread, NULL, special_reply_port_thread, &srp); | |
1723 | ||
1724 | while (srp) { | |
1725 | usleep(1000); | |
1726 | } | |
1727 | ||
1728 | pthread_exit(NULL); | |
1729 | } | |
1730 | ||
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)) \ | |
1735 | { \ | |
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); \ | |
1739 | } | |
1740 | /* | |
1741 | * Test 1: Test special reply port SPI | |
1742 | * | |
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. | |
1745 | */ | |
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") | |
1750 | ||
1751 | /* | |
1752 | * Test 2: Test sync ipc send to an in-transit port | |
1753 | * | |
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. | |
1757 | */ | |
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") | |
1762 | ||
1763 | /* | |
1764 | * Test 3: Test sync ipc send to an in-transit port | |
1765 | * | |
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. | |
1769 | */ | |
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") | |
1774 | ||
1775 | /* | |
1776 | * Test 4: Test starting a sync rcv overrides the servicer | |
1777 | * | |
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. | |
1781 | */ | |
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") | |
1786 | ||
1787 | /* | |
1788 | * Test 5: Test starting a sync rcv overrides the servicer | |
1789 | * | |
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. | |
1793 | */ | |
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") | |
1798 | ||
1799 | /* | |
1800 | * Test 6: test sending sync ipc message (at IN qos) to port will override the servicer | |
1801 | * | |
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. | |
1804 | */ | |
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") | |
1809 | ||
1810 | /* | |
1811 | * Test 7: test sending sync ipc message (at UI qos) to port will override the servicer | |
1812 | * | |
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. | |
1815 | */ | |
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") | |
1820 | ||
1821 | /* | |
1822 | * Test 8: test enabling a knote in workloop handler will drop the sync ipc override of delivered message | |
1823 | * | |
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. | |
1827 | */ | |
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") | |
1832 | ||
1833 | /* | |
1834 | * Test 9: test returning to begin processing drops sync ipc override of delivered message | |
1835 | * | |
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. | |
1838 | */ | |
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") | |
1843 | ||
1844 | /* | |
1845 | * Test 10: test destroying the special reply port drops the override | |
1846 | * | |
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. | |
1850 | */ | |
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") | |
1855 | ||
1856 | /* | |
1857 | * Test 11: test sending two ports with chaining | |
1858 | * | |
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. | |
1861 | */ | |
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") | |
1866 | ||
1867 | /* | |
1868 | * Test 12: test sending two ports with chaining | |
1869 | * | |
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. | |
1872 | */ | |
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") | |
1877 | ||
1878 | /* | |
1879 | * Test 13: test changing qos of a thread to trigger turnstile push | |
1880 | * | |
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. | |
1883 | */ | |
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") | |
1888 | ||
1889 | /* | |
1890 | * Test 14 - 21 | |
1891 | * | |
1892 | * Test single sync ipc link with server that breaks/preserves the link in different ways. | |
1893 | */ | |
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") | |
1898 | ||
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") | |
1903 | ||
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") | |
1908 | ||
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") | |
1913 | ||
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") | |
1918 | ||
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") | |
1923 | ||
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") | |
1928 | ||
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") | |
1933 | ||
1934 | /* | |
1935 | * Test 22 - 25 | |
1936 | * | |
1937 | * Test sequential sync ipc link with server that breaks/preserves the link. | |
1938 | */ | |
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") | |
1943 | ||
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") | |
1948 | ||
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") | |
1953 | ||
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") |