xref: /xnu-10002.61.3/tests/workq/workq_83476290.c (revision 0f4c859e951fba394238ab619495c4e1d54d0f34)
1 #include <mach/port.h>
2 #include <mach/mach.h>
3 #include <sys/event.h>
4 #include <dispatch/dispatch.h>
5 #include <pthread/workqueue_private.h>
6 #include <darwintest.h>
7 
8 T_GLOBAL_META(
9 	T_META_NAMESPACE("xnu.workq"),
10 	T_META_RADAR_COMPONENT_NAME("xnu"),
11 	T_META_RADAR_COMPONENT_VERSION("workq"),
12 	T_META_RUN_CONCURRENTLY(true));
13 
14 T_DECL(thread_request_83476290,
15     "test that mach_msg_trap causes a thread request")
16 {
17 	mach_port_t mp, rp;
18 	kern_return_t kr;
19 	dispatch_source_t ds;
20 	dispatch_queue_t dq;
21 	int kq;
22 
23 	mach_port_options_t opts = {
24 		.flags = MPO_INSERT_SEND_RIGHT,
25 	};
26 
27 	kr = mach_port_construct(mach_task_self(), &opts, 0, &mp);
28 	T_ASSERT_MACH_SUCCESS(kr, "create receive right %x", mp);
29 
30 	kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &rp);
31 	T_ASSERT_MACH_SUCCESS(kr, "create reply port right %x", rp);
32 
33 	dq = dispatch_queue_create_with_target("tr.q", DISPATCH_QUEUE_SERIAL, NULL);
34 	ds = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, dq);
35 	dispatch_source_set_event_handler(ds, ^{
36 		T_PASS("received the event");
37 		T_END;
38 	});
39 	dispatch_activate(ds);
40 
41 	T_LOG("wait 1ms for the existing dispatch thread to park again");
42 	usleep(1000);
43 
44 	kq = kqueue();
45 	T_ASSERT_POSIX_SUCCESS(kq, "kqueue()");
46 
47 	/*
48 	 * Now use the threads that were on the pool to make sure the process
49 	 * is starved
50 	 */
51 	dispatch_async(dispatch_get_global_queue(0, 0), ^{
52 		usleep(1000);
53 		struct kevent_qos_s ke = {
54 		        .ident  = 1,
55 		        .filter = EVFILT_USER,
56 		        .fflags = NOTE_TRIGGER,
57 		};
58 		int rc = kevent_qos(kq, &ke, 1, NULL, 0, NULL, NULL, 0);
59 		T_ASSERT_POSIX_SUCCESS(rc, "NOTE_TRIGGER");
60 		pause();
61 	});
62 
63 	struct kevent_qos_s ke = {
64 		.ident  = 1,
65 		.filter = EVFILT_USER,
66 		.flags  = EV_ADD | EV_CLEAR,
67 	};
68 
69 	T_LOG("block in kevent, call mach_msg with 5s timeout");
70 	(void)kevent_qos(kq, &ke, 1, &ke, 1, NULL, NULL, 0);
71 
72 	mach_msg_header_t hdr = {
73 		.msgh_remote_port = mp,
74 		.msgh_local_port  = rp,
75 		.msgh_bits        = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND,
76 	    MACH_MSG_TYPE_MAKE_SEND_ONCE, 0, 0),
77 		.msgh_id          = 1,
78 		.msgh_size        = sizeof(hdr),
79 	};
80 
81 	kr = mach_msg(&hdr, MACH_SEND_MSG | MACH_RCV_MSG | MACH_RCV_TIMEOUT,
82 	    sizeof(hdr), sizeof(hdr), rp, 5000, 0);
83 	T_FAIL("mach_msg returned: %#x", kr);
84 }
85