]> git.saurik.com Git - apple/xnu.git/blobdiff - tests/turnstile_multihop.c
xnu-6153.11.26.tar.gz
[apple/xnu.git] / tests / turnstile_multihop.c
index 339cfe8c2bc155581c0337559143b9643838b1dc..65fd2db0711ff7d61b9a35833264ea423248f067 100644 (file)
@@ -34,6 +34,12 @@ T_GLOBAL_META(T_META_NAMESPACE("xnu.turnstile_multihop"));
 
 #define HELPER_TIMEOUT_SECS (3000)
 
+struct test_msg {
+       mach_msg_header_t header;
+       mach_msg_body_t body;
+       mach_msg_port_descriptor_t port_descriptor;
+};
+
 static boolean_t spin_for_ever = false;
 
 static void
@@ -60,7 +66,8 @@ struct load_token_context {
 static struct mach_timebase_info sched_mti;
 static pthread_once_t sched_mti_once_control = PTHREAD_ONCE_INIT;
 
-static void sched_mti_init(void)
+static void
+sched_mti_init(void)
 {
        mach_timebase_info(&sched_mti);
 }
@@ -103,7 +110,9 @@ sched_create_load_at_qos(qos_class_t qos, void **load_token)
        }
 
        context = calloc(1, sizeof(*context));
-       if (context == NULL) { T_QUIET; T_LOG("calloc returned error"); return ENOMEM; }
+       if (context == NULL) {
+               T_QUIET; T_LOG("calloc returned error"); return ENOMEM;
+       }
 
        context->threads_should_exit = 0;
        context->thread_count = nthreads;
@@ -112,7 +121,7 @@ sched_create_load_at_qos(qos_class_t qos, void **load_token)
 
        OSMemoryBarrier();
 
-       for (i=0; i < nthreads; i++) {
+       for (i = 0; i < nthreads; i++) {
                ret = pthread_create(&context->threads[i], &attr, sched_load_thread, context);
                T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "pthread_create");
                T_QUIET; T_LOG("%s: Created thread %d (%p)\n", __FUNCTION__, i, (void *)context->threads[i]);
@@ -137,7 +146,9 @@ sched_load_thread(void *arg)
                uint64_t start = mach_absolute_time();
                uint64_t end = start + nanoseconds_to_absolutetime(900ULL * NSEC_PER_MSEC);
 
-               while ((mach_absolute_time() < end) && !context->threads_should_exit);
+               while ((mach_absolute_time() < end) && !context->threads_should_exit) {
+                       ;
+               }
        }
 
        T_QUIET; T_LOG("%s: Thread terminating %p\n", __FUNCTION__, (void *)pthread_self());
@@ -155,7 +166,7 @@ sched_terminate_load(void *load_token)
        context->threads_should_exit = 1;
        OSMemoryBarrier();
 
-       for (i=0; i < context->thread_count; i++) {
+       for (i = 0; i < context->thread_count; i++) {
                T_QUIET; T_LOG("%s: Joining thread %d (%p)\n", __FUNCTION__, i, (void *)context->threads[i]);
                ret = pthread_join(context->threads[i], NULL);
                T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "pthread_join");
@@ -169,17 +180,18 @@ sched_terminate_load(void *load_token)
 
 
 // Find the first num primes, simply as a means of doing work
-static void do_work(int num)
+static void
+do_work(int num)
 {
        volatile int i = 3, count, c;
 
-       for(count = 2; count <= num; ) {
-               for(c = 2; c <= i; c++) {
-                       if(i%c == 0) {
+       for (count = 2; count <= num;) {
+               for (c = 2; c <= i; c++) {
+                       if (i % c == 0) {
                                break;
                        }
                }
-               if(c == i) {
+               if (c == i) {
                        count++;
                }
                i++;
@@ -209,52 +221,111 @@ get_user_promotion_basepri(void)
        mach_port_t thread_port = pthread_mach_thread_np(pthread_self());
 
        kern_return_t kr = thread_policy_get(thread_port, THREAD_POLICY_STATE,
-                       (thread_policy_t)&thread_policy, &count, &get_default);
+           (thread_policy_t)&thread_policy, &count, &get_default);
        T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_policy_get");
        return thread_policy.thps_user_promotion_basepri;
 }
 
-static int messages_received = 0;
+#define LISTENER_WLID  0x100
+#define CONN_WLID      0x200
+
+static uint32_t
+register_port_options(void)
+{
+       return MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_LARGE_IDENTITY |
+              MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_CTX) |
+              MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
+              MACH_RCV_VOUCHER;
+}
+
+static void
+register_port(uint64_t wlid, mach_port_t port)
+{
+       int r;
+
+       struct kevent_qos_s kev = {
+               .ident  = port,
+               .filter = EVFILT_MACHPORT,
+               .flags  = EV_ADD | EV_UDATA_SPECIFIC | EV_DISPATCH | EV_VANISHED,
+               .fflags = register_port_options(),
+               .data   = 1,
+               .qos    = (int32_t)_pthread_qos_class_encode(QOS_CLASS_MAINTENANCE, 0, 0)
+       };
+
+       struct kevent_qos_s kev_err = { 0 };
+
+       /* Setup workloop for mach msg rcv */
+       r = kevent_id(wlid, &kev, 1, &kev_err, 1, NULL,
+           NULL, KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_ERROR_EVENTS);
+
+       T_QUIET; T_ASSERT_POSIX_SUCCESS(r, "kevent_id");
+       T_QUIET; T_ASSERT_EQ(r, 0, "no errors returned from kevent_id");
+}
+
 /*
  * Basic WL handler callback, it checks the
  * effective Qos of the servicer thread.
  */
 static void
-workloop_cb_test_intransit(uint64_t *workloop_id __unused, void **eventslist __unused, int *events)
+workloop_cb_test_intransit(uint64_t *workloop_id, void **eventslist, int *events)
 {
-       messages_received++;
-       T_LOG("Workloop handler workloop_cb_test_intransit called. Received message no %d",
-               messages_received);
+       static bool got_peer;
+
+       struct kevent_qos_s *kev = eventslist[0];
+       mach_msg_header_t *hdr;
+       struct test_msg *tmsg;
 
+       T_LOG("Workloop handler %s called. Received message on 0x%llx",
+           __func__, *workloop_id);
 
        /* Skip the test if we can't check Qos */
        if (geteuid() != 0) {
                T_SKIP("kevent_qos test requires root privileges to run.");
        }
 
-       if (messages_received == 1) {
+       T_QUIET; T_ASSERT_EQ(*events, 1, "should have one event");
 
-               sleep(5);
-               T_LOG("Do some CPU work.");
-               do_work(5000);
+       hdr = (mach_msg_header_t *)kev->ext[0];
+       T_ASSERT_NOTNULL(hdr, "has a message");
+       T_ASSERT_EQ(hdr->msgh_size, (uint32_t)sizeof(struct test_msg), "of the right size");
+       tmsg = (struct test_msg *)hdr;
 
-               /* Check if the override now is IN + 60 boost */
-               T_EXPECT_EFFECTIVE_QOS_EQ(QOS_CLASS_USER_INITIATED,
-                               "dispatch_source event handler QoS should be QOS_CLASS_USER_INITIATED");
-               T_EXPECT_EQ(get_user_promotion_basepri(), 60u,
-                               "dispatch_source event handler should be overridden at 60");
+       switch (*workloop_id) {
+       case LISTENER_WLID:
+               T_LOG("Registering peer connection");
+               T_QUIET; T_ASSERT_FALSE(got_peer, "Should not have seen peer yet");
+               got_peer = true;
+               break;
+
+       case CONN_WLID:
+               T_LOG("Received message on peer");
+               break;
+
+       default:
+               T_FAIL("???");
+       }
+
+       sleep(5);
+       T_LOG("Do some CPU work.");
+       do_work(5000);
+
+       /* Check if the override now is IN + 60 boost */
+       T_EXPECT_EFFECTIVE_QOS_EQ(QOS_CLASS_USER_INITIATED,
+           "dispatch_source event handler QoS should be QOS_CLASS_USER_INITIATED");
+       T_EXPECT_EQ(get_user_promotion_basepri(), 60u,
+           "dispatch_source event handler should be overridden at 60");
+
+       if (*workloop_id == LISTENER_WLID) {
+               register_port(CONN_WLID, tmsg->port_descriptor.name);
 
-               /* Enable the knote to get 2nd message */
-               struct kevent_qos_s *kev = *eventslist;
                kev->flags = EV_ADD | EV_ENABLE | EV_UDATA_SPECIFIC | EV_DISPATCH | EV_VANISHED;
-               kev->fflags = (MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_LARGE_IDENTITY |
-                               MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_CTX) |
-                               MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
-                               MACH_RCV_VOUCHER);
+               kev->fflags = register_port_options();
+               kev->ext[0] = kev->ext[1] = kev->ext[2] = kev->ext[3] = 0;
                *events = 1;
        } else {
+               /* this will unblock the waiter */
+               mach_msg_destroy(hdr);
                *events = 0;
-               exit(0);
        }
 }
 
@@ -263,7 +334,7 @@ run_client_server(const char *server_name, const char *client_name)
 {
        dt_helper_t helpers[] = {
                dt_launchd_helper_domain("com.apple.xnu.test.turnstile_multihop.plist",
-                               server_name, NULL, LAUNCH_SYSTEM_DOMAIN),
+           server_name, NULL, LAUNCH_SYSTEM_DOMAIN),
                dt_fork_helper(client_name)
        };
        dt_run_helpers(helpers, 2, HELPER_TIMEOUT_SECS);
@@ -278,7 +349,7 @@ get_server_port(void)
 {
        mach_port_t port;
        kern_return_t kr = bootstrap_check_in(bootstrap_port,
-                       TURNSTILE_MULTIHOP_SERVICE_NAME, &port);
+           TURNSTILE_MULTIHOP_SERVICE_NAME, &port);
        T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "server bootstrap_check_in");
        return port;
 }
@@ -291,12 +362,12 @@ create_pthpriority_voucher(mach_msg_priority_t qos)
        mach_voucher_t voucher = MACH_PORT_NULL;
        kern_return_t ret;
        ipc_pthread_priority_value_t ipc_pthread_priority_value =
-                       (ipc_pthread_priority_value_t)qos;
+           (ipc_pthread_priority_value_t)qos;
 
        mach_voucher_attr_raw_recipe_array_t recipes;
        mach_voucher_attr_raw_recipe_size_t recipe_size = 0;
        mach_voucher_attr_recipe_t recipe =
-               (mach_voucher_attr_recipe_t)&voucher_buf[recipe_size];
+           (mach_voucher_attr_recipe_t)&voucher_buf[recipe_size];
 
        recipe->key = MACH_VOUCHER_ATTR_KEY_PTHPRIORITY;
        recipe->command = MACH_VOUCHER_ATTR_PTHPRIORITY_CREATE;
@@ -308,9 +379,9 @@ create_pthpriority_voucher(mach_msg_priority_t qos)
        recipes = (mach_voucher_attr_raw_recipe_array_t)&voucher_buf[0];
 
        ret = host_create_mach_voucher(mach_host_self(),
-                               recipes,
-                               recipe_size,
-                               &voucher);
+           recipes,
+           recipe_size,
+           &voucher);
 
        T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "client host_create_mach_voucher");
        return voucher;
@@ -326,26 +397,22 @@ send(
 {
        kern_return_t ret = 0;
 
-       struct {
-               mach_msg_header_t header;
-               mach_msg_body_t body;
-               mach_msg_port_descriptor_t port_descriptor;
-       } send_msg = {
-           .header = {
-                   .msgh_remote_port = send_port,
-                   .msgh_local_port  = reply_port,
-                   .msgh_bits        = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND,
-                                       reply_port ? MACH_MSG_TYPE_MAKE_SEND_ONCE : 0,
-                                       MACH_MSG_TYPE_MOVE_SEND,
-                                       MACH_MSGH_BITS_COMPLEX),
-                   .msgh_id          = 0x100,
-                   .msgh_size        = sizeof(send_msg),
+       struct test_msg send_msg = {
+               .header = {
+                       .msgh_remote_port = send_port,
+                       .msgh_local_port  = reply_port,
+                       .msgh_bits        = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND,
+           reply_port ? MACH_MSG_TYPE_MAKE_SEND_ONCE : 0,
+           MACH_MSG_TYPE_MOVE_SEND,
+           MACH_MSGH_BITS_COMPLEX),
+                       .msgh_id          = 0x100,
+                       .msgh_size        = sizeof(send_msg),
                },
-           .body = {
-                   .msgh_descriptor_count = 1,
+               .body = {
+                       .msgh_descriptor_count = 1,
                },
-           .port_descriptor = {
-                   .name        = msg_port,
+               .port_descriptor = {
+                       .name        = msg_port,
                        .disposition = MACH_MSG_TYPE_MOVE_RECEIVE,
                        .type        = MACH_MSG_PORT_DESCRIPTOR,
                },
@@ -360,15 +427,15 @@ send(
        }
 
        ret = mach_msg(&(send_msg.header),
-               MACH_SEND_MSG |
-               MACH_SEND_TIMEOUT |
-               MACH_SEND_OVERRIDE|
-               ((reply_port ? MACH_SEND_SYNC_OVERRIDE : 0) | options),
-               send_msg.header.msgh_size,
-               0,
-               MACH_PORT_NULL,
-               10000,
-               0);
+           MACH_SEND_MSG |
+           MACH_SEND_TIMEOUT |
+           MACH_SEND_OVERRIDE |
+           ((reply_port ? MACH_SEND_SYNC_OVERRIDE : 0) | options),
+           send_msg.header.msgh_size,
+           0,
+           MACH_PORT_NULL,
+           10000,
+           0);
 
        T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "client mach_msg");
 }
@@ -385,24 +452,24 @@ receive(
                mach_msg_body_t body;
                mach_msg_port_descriptor_t port_descriptor;
        } rcv_msg = {
-           .header =
+               .header =
                {
-                   .msgh_remote_port = MACH_PORT_NULL,
-                   .msgh_local_port  = rcv_port,
-                   .msgh_size        = sizeof(rcv_msg),
+                       .msgh_remote_port = MACH_PORT_NULL,
+                       .msgh_local_port  = rcv_port,
+                       .msgh_size        = sizeof(rcv_msg),
                },
        };
 
        T_LOG("Client: Starting sync receive\n");
 
        ret = mach_msg(&(rcv_msg.header),
-               MACH_RCV_MSG |
-               MACH_RCV_SYNC_WAIT,
-               0,
-               rcv_msg.header.msgh_size,
-               rcv_port,
-               0,
-               notify_port);
+           MACH_RCV_MSG |
+           MACH_RCV_SYNC_WAIT,
+           0,
+           rcv_msg.header.msgh_size,
+           rcv_port,
+           0,
+           notify_port);
 }
 
 static lock_t lock_DEF;
@@ -417,13 +484,15 @@ static mach_port_t sixty_thread_port;
 
 static uint64_t dispatch_sync_owner;
 
-static int get_pri(thread_t thread_port) {
+static int
+get_pri(thread_t thread_port)
+{
        kern_return_t kr;
 
        thread_extended_info_data_t extended_info;
        mach_msg_type_number_t count = THREAD_EXTENDED_INFO_COUNT;
        kr = thread_info(thread_port, THREAD_EXTENDED_INFO,
-                          (thread_info_t)&extended_info, &count);
+           (thread_info_t)&extended_info, &count);
 
        T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_info");
 
@@ -452,7 +521,7 @@ thread_wait_to_block(mach_port_t thread_port)
        while (1) {
                mach_msg_type_number_t count = THREAD_EXTENDED_INFO_COUNT;
                kr = thread_info(thread_port, THREAD_EXTENDED_INFO,
-                                  (thread_info_t)&extended_info, &count);
+                   (thread_info_t)&extended_info, &count);
 
                T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_info");
 
@@ -473,7 +542,7 @@ thread_wait_to_boost(mach_port_t thread_port, mach_port_t yield_thread, int prio
        while (1) {
                mach_msg_type_number_t count = THREAD_EXTENDED_INFO_COUNT;
                kr = thread_info(thread_port, THREAD_EXTENDED_INFO,
-                                  (thread_info_t)&extended_info, &count);
+                   (thread_info_t)&extended_info, &count);
 
                T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_info");
 
@@ -500,20 +569,20 @@ dispatch_sync_wait(mach_port_t owner_thread, qos_class_t promote_qos)
        dispatch_sync_owner = owner_thread;
 
        struct kevent_qos_s kev[] =  {{
-               .ident = mach_thread_self(),
-               .filter = EVFILT_WORKLOOP,
-               .flags = action,
-               .fflags = fflags,
-               .udata = (uintptr_t) &def_thread_port,
-               .qos = (int32_t)_pthread_qos_class_encode(promote_qos, 0, 0),
-               .ext[EV_EXTIDX_WL_MASK] = mask,
-               .ext[EV_EXTIDX_WL_VALUE] = dispatch_sync_owner,
-               .ext[EV_EXTIDX_WL_ADDR] = (uint64_t)&dispatch_sync_owner,
-       }};
+                                             .ident = mach_thread_self(),
+                                             .filter = EVFILT_WORKLOOP,
+                                             .flags = action,
+                                             .fflags = fflags,
+                                             .udata = (uintptr_t) &def_thread_port,
+                                             .qos = (int32_t)_pthread_qos_class_encode(promote_qos, 0, 0),
+                                             .ext[EV_EXTIDX_WL_MASK] = mask,
+                                             .ext[EV_EXTIDX_WL_VALUE] = dispatch_sync_owner,
+                                             .ext[EV_EXTIDX_WL_ADDR] = (uint64_t)&dispatch_sync_owner,
+                                     }};
 
        /* Setup workloop to fake dispatch sync wait on a workloop */
        r = kevent_id(30, kev, 1, kev_err, 1, NULL,
-                       NULL, KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_ERROR_EVENTS);
+           NULL, KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_ERROR_EVENTS);
        T_QUIET; T_LOG("dispatch_sync_wait returned\n");
 }
 
@@ -532,22 +601,21 @@ dispatch_sync_cancel(mach_port_t owner_thread, qos_class_t promote_qos)
        dispatch_sync_owner = owner_thread;
 
        struct kevent_qos_s kev[] =  {{
-               .ident = def_thread_port,
-               .filter = EVFILT_WORKLOOP,
-               .flags = action,
-               .fflags = fflags,
-               .udata = (uintptr_t) &def_thread_port,
-               .qos = (int32_t)_pthread_qos_class_encode(promote_qos, 0, 0),
-               .ext[EV_EXTIDX_WL_MASK] = mask,
-               .ext[EV_EXTIDX_WL_VALUE] = dispatch_sync_owner,
-               .ext[EV_EXTIDX_WL_ADDR] = (uint64_t)&dispatch_sync_owner,
-       }};
+                                             .ident = def_thread_port,
+                                             .filter = EVFILT_WORKLOOP,
+                                             .flags = action,
+                                             .fflags = fflags,
+                                             .udata = (uintptr_t) &def_thread_port,
+                                             .qos = (int32_t)_pthread_qos_class_encode(promote_qos, 0, 0),
+                                             .ext[EV_EXTIDX_WL_MASK] = mask,
+                                             .ext[EV_EXTIDX_WL_VALUE] = dispatch_sync_owner,
+                                             .ext[EV_EXTIDX_WL_ADDR] = (uint64_t)&dispatch_sync_owner,
+                                     }};
 
        /* Setup workloop to fake dispatch sync wake on a workloop */
        r = kevent_id(30, kev, 1, kev_err, 1, NULL,
-                       NULL, KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_ERROR_EVENTS);
+           NULL, KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_ERROR_EVENTS);
        T_QUIET; T_LOG("dispatch_sync_cancel returned\n");
-
 }
 
 static void *
@@ -591,8 +659,8 @@ thread_at_sixty(void *arg __unused)
        after_lock_time = mach_absolute_time();
 
        T_QUIET; T_LOG("The time for priority 60 thread to acquire lock was %llu \n",
-               (after_lock_time - before_lock_time));
-       exit(0);
+           (after_lock_time - before_lock_time));
+       T_END;
 }
 
 static void *
@@ -663,56 +731,54 @@ thread_at_default(void *arg __unused)
 static void *
 thread_at_maintenance(void *arg __unused)
 {
-       mach_port_t qos_send_port;
+       mach_port_t service_port;
+       mach_port_t conn_port;
        mach_port_t special_reply_port;
+       mach_port_options_t opts = {
+               .flags = MPO_INSERT_SEND_RIGHT,
+       };
 
        main_thread_port = mach_thread_self();
 
        set_thread_name(__FUNCTION__);
 
        kern_return_t kr = bootstrap_look_up(bootstrap_port,
-                       TURNSTILE_MULTIHOP_SERVICE_NAME, &qos_send_port);
+           TURNSTILE_MULTIHOP_SERVICE_NAME, &service_port);
        T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client bootstrap_look_up");
 
+       kr = mach_port_construct(mach_task_self(), &opts, 0ull, &conn_port);
+       T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct");
+
        special_reply_port = thread_get_special_reply_port();
        T_QUIET; T_ASSERT_TRUE(MACH_PORT_VALID(special_reply_port), "get_thread_special_reply_port");
 
        /* Become the dispatch sync owner, dispatch_sync_owner will be set in dispatch_sync_wait function */
 
-       /* Send an async message */
-       send(qos_send_port, MACH_PORT_NULL, MACH_PORT_NULL,
-                       (uint32_t)_pthread_qos_class_encode(QOS_CLASS_MAINTENANCE, 0, 0), 0);
-
        /* Send a sync message */
-       send(qos_send_port, special_reply_port, MACH_PORT_NULL,
-                       (uint32_t)_pthread_qos_class_encode(QOS_CLASS_MAINTENANCE, 0, 0), 0);
+       send(conn_port, special_reply_port, MACH_PORT_NULL,
+           (uint32_t)_pthread_qos_class_encode(QOS_CLASS_MAINTENANCE, 0, 0), 0);
+
+       /* Send an async checkin message */
+       send(service_port, MACH_PORT_NULL, conn_port,
+           (uint32_t)_pthread_qos_class_encode(QOS_CLASS_MAINTENANCE, 0, 0), 0);
 
        /* Create a new thread at QOS_CLASS_DEFAULT qos */
        thread_create_at_qos(QOS_CLASS_DEFAULT, thread_at_default);
 
        /* Block on Sync IPC */
-       receive(special_reply_port, qos_send_port);
+       receive(special_reply_port, service_port);
+
+       T_LOG("received reply");
 
        dispatch_sync_cancel(def_thread_port, QOS_CLASS_DEFAULT);
        return NULL;
 }
 
 T_HELPER_DECL(three_ulock_sync_ipc_hop,
-               "Create chain of 4 threads with 3 ulocks and 1 sync IPC at different qos")
+    "Create chain of 4 threads with 3 ulocks and 1 sync IPC at different qos")
 {
-       dt_stat_time_t roundtrip_stat = dt_stat_time_create("multihop_lock_acquire");
-
-       T_STAT_MEASURE_LOOP(roundtrip_stat) {
-               if (fork() == 0) {
-                       thread_create_at_qos(QOS_CLASS_MAINTENANCE, thread_at_maintenance);
-                       sigsuspend(0);
-                       exit(0);
-               }
-               wait(NULL);
-       }
-
-       dt_stat_finalize(roundtrip_stat);
-       T_END;
+       thread_create_at_qos(QOS_CLASS_MAINTENANCE, thread_at_maintenance);
+       sigsuspend(0);
 }
 
 static void
@@ -720,7 +786,7 @@ thread_create_at_qos(qos_class_t qos, void * (*function)(void *))
 {
        qos_class_t qos_thread;
        pthread_t thread;
-        pthread_attr_t attr;
+       pthread_attr_t attr;
        int ret;
 
        ret = setpriority(PRIO_DARWIN_ROLE, 0, PRIO_DARWIN_ROLE_UI_FOCAL);
@@ -728,9 +794,9 @@ thread_create_at_qos(qos_class_t qos, void * (*function)(void *))
                T_LOG("set priority failed\n");
        }
 
-        pthread_attr_init(&attr);
-        pthread_attr_set_qos_class_np(&attr, qos, 0);
-        pthread_create(&thread, &attr, function, NULL);
+       pthread_attr_init(&attr);
+       pthread_attr_set_qos_class_np(&attr, qos, 0);
+       pthread_create(&thread, &attr, function, NULL);
 
        T_LOG("pthread created\n");
        pthread_get_qos_class_np(thread, &qos_thread, NULL);
@@ -738,61 +804,34 @@ thread_create_at_qos(qos_class_t qos, void * (*function)(void *))
 
 #pragma mark Mach receive - kevent_qos
 
-static void
-expect_kevent_id_recv(mach_port_t port)
+T_HELPER_DECL(server_kevent_id,
+    "Reply with the QoS that a dispatch source event handler ran with")
 {
-       int r;
-
        T_QUIET; T_ASSERT_POSIX_ZERO(_pthread_workqueue_init_with_workloop(
-               worker_cb, event_cb,
-               (pthread_workqueue_function_workloop_t)workloop_cb_test_intransit, 0, 0), NULL);
-
-       struct kevent_qos_s kev[] = {{
-               .ident = port,
-               .filter = EVFILT_MACHPORT,
-               .flags = EV_ADD | EV_UDATA_SPECIFIC | EV_DISPATCH | EV_VANISHED,
-               .fflags = (MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_LARGE_IDENTITY |
-                               MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_CTX) |
-                               MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0) |
-                               MACH_RCV_VOUCHER),
-               .data = 1,
-               .qos = (int32_t)_pthread_qos_class_encode(QOS_CLASS_MAINTENANCE, 0, 0)
-       }};
-
-       struct kevent_qos_s kev_err[] = {{ 0 }};
+                   worker_cb, event_cb,
+                   (pthread_workqueue_function_workloop_t)workloop_cb_test_intransit, 0, 0), NULL);
 
-       /* Setup workloop for mach msg rcv */
-       r = kevent_id(25, kev, 1, kev_err, 1, NULL,
-                       NULL, KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_ERROR_EVENTS);
-
-       T_QUIET; T_ASSERT_POSIX_SUCCESS(r, "kevent_id");
-       T_QUIET; T_ASSERT_EQ(r, 0, "no errors returned from kevent_id");
-}
-
-T_HELPER_DECL(server_kevent_id,
-               "Reply with the QoS that a dispatch source event handler ran with")
-{
-       expect_kevent_id_recv(get_server_port());
+       register_port(LISTENER_WLID, get_server_port());
        sigsuspend(0);
        T_ASSERT_FAIL("should receive a message");
 }
 
 #define TEST_MULTIHOP(server_name, client_name, name) \
        T_DECL(server_kevent_id_##name, \
-                       "Event delivery using a kevent_id", \
-                       T_META_ASROOT(YES)) \
+                       "Event delivery using a kevent_id", \
+                       T_META_ASROOT(YES)) \
        { \
-               run_client_server(server_name, client_name); \
+               run_client_server(server_name, client_name); \
        }
 
 #define TEST_MULTIHOP_SPIN(server_name, client_name, name) \
        T_DECL(server_kevent_id_##name, \
-                       "Event delivery using a kevent_id", \
-                       T_META_ASROOT(YES), T_META_ENABLED(FALSE)) \
+                       "Event delivery using a kevent_id", \
+                       T_META_ASROOT(YES), T_META_ENABLED(FALSE)) \
        { \
-               spin_for_ever = true; \
-               run_client_server(server_name, client_name); \
-               spin_for_ever = false; \
+               spin_for_ever = true; \
+               run_client_server(server_name, client_name); \
+               spin_for_ever = false; \
        }
 
 /*