1*a325d9c4SApple OSS Distributions #include <unistd.h>
2*a325d9c4SApple OSS Distributions #include <pthread.h>
3*a325d9c4SApple OSS Distributions #include <errno.h>
4*a325d9c4SApple OSS Distributions
5*a325d9c4SApple OSS Distributions #include <sys/event.h>
6*a325d9c4SApple OSS Distributions #include <mach/mach.h>
7*a325d9c4SApple OSS Distributions #include <mach/mach_port.h>
8*a325d9c4SApple OSS Distributions
9*a325d9c4SApple OSS Distributions #include <Block.h>
10*a325d9c4SApple OSS Distributions #include <darwintest.h>
11*a325d9c4SApple OSS Distributions
12*a325d9c4SApple OSS Distributions T_GLOBAL_META(
13*a325d9c4SApple OSS Distributions T_META_NAMESPACE("xnu.kevent"),
14*a325d9c4SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
15*a325d9c4SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("kevent"),
16*a325d9c4SApple OSS Distributions T_META_RUN_CONCURRENTLY(true)
17*a325d9c4SApple OSS Distributions );
18*a325d9c4SApple OSS Distributions
19*a325d9c4SApple OSS Distributions static void
send(mach_port_t send_port)20*a325d9c4SApple OSS Distributions send(mach_port_t send_port)
21*a325d9c4SApple OSS Distributions {
22*a325d9c4SApple OSS Distributions kern_return_t kr = 0;
23*a325d9c4SApple OSS Distributions mach_msg_base_t msg = {
24*a325d9c4SApple OSS Distributions .header = {
25*a325d9c4SApple OSS Distributions .msgh_remote_port = send_port,
26*a325d9c4SApple OSS Distributions .msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND,
27*a325d9c4SApple OSS Distributions 0, MACH_MSG_TYPE_MOVE_SEND, 0),
28*a325d9c4SApple OSS Distributions .msgh_id = 0x100,
29*a325d9c4SApple OSS Distributions .msgh_size = sizeof(msg),
30*a325d9c4SApple OSS Distributions },
31*a325d9c4SApple OSS Distributions };
32*a325d9c4SApple OSS Distributions
33*a325d9c4SApple OSS Distributions kr = mach_msg(&msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT,
34*a325d9c4SApple OSS Distributions msg.header.msgh_size, 0, MACH_PORT_NULL, 10000, 0);
35*a325d9c4SApple OSS Distributions
36*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client mach_msg");
37*a325d9c4SApple OSS Distributions }
38*a325d9c4SApple OSS Distributions
39*a325d9c4SApple OSS Distributions static kern_return_t
receive(mach_port_t rcv_port)40*a325d9c4SApple OSS Distributions receive(mach_port_t rcv_port)
41*a325d9c4SApple OSS Distributions {
42*a325d9c4SApple OSS Distributions mach_msg_base_t msg = {
43*a325d9c4SApple OSS Distributions .header = {
44*a325d9c4SApple OSS Distributions .msgh_remote_port = MACH_PORT_NULL,
45*a325d9c4SApple OSS Distributions .msgh_local_port = rcv_port,
46*a325d9c4SApple OSS Distributions .msgh_size = sizeof(msg),
47*a325d9c4SApple OSS Distributions },
48*a325d9c4SApple OSS Distributions };
49*a325d9c4SApple OSS Distributions
50*a325d9c4SApple OSS Distributions return mach_msg(&msg.header, MACH_RCV_MSG | MACH_RCV_TIMEOUT,
51*a325d9c4SApple OSS Distributions 0, msg.header.msgh_size, rcv_port, 5000, 0);
52*a325d9c4SApple OSS Distributions }
53*a325d9c4SApple OSS Distributions
54*a325d9c4SApple OSS Distributions static void
fill_kevent(struct kevent * ke,uint16_t action,mach_port_t mp)55*a325d9c4SApple OSS Distributions fill_kevent(struct kevent *ke, uint16_t action, mach_port_t mp)
56*a325d9c4SApple OSS Distributions {
57*a325d9c4SApple OSS Distributions *ke = (struct kevent){
58*a325d9c4SApple OSS Distributions .filter = EVFILT_MACHPORT,
59*a325d9c4SApple OSS Distributions .flags = action,
60*a325d9c4SApple OSS Distributions .ident = mp,
61*a325d9c4SApple OSS Distributions };
62*a325d9c4SApple OSS Distributions }
63*a325d9c4SApple OSS Distributions
64*a325d9c4SApple OSS Distributions #define TS(s) (struct timespec){ .tv_sec = s }
65*a325d9c4SApple OSS Distributions
66*a325d9c4SApple OSS Distributions static void *
pthread_async_do(void * arg)67*a325d9c4SApple OSS Distributions pthread_async_do(void *arg)
68*a325d9c4SApple OSS Distributions {
69*a325d9c4SApple OSS Distributions void (^block)(void) = arg;
70*a325d9c4SApple OSS Distributions block();
71*a325d9c4SApple OSS Distributions Block_release(block);
72*a325d9c4SApple OSS Distributions pthread_detach(pthread_self());
73*a325d9c4SApple OSS Distributions return NULL;
74*a325d9c4SApple OSS Distributions }
75*a325d9c4SApple OSS Distributions
76*a325d9c4SApple OSS Distributions static void
77*a325d9c4SApple OSS Distributions pthread_async(void (^block)(void))
78*a325d9c4SApple OSS Distributions {
79*a325d9c4SApple OSS Distributions pthread_t th;
80*a325d9c4SApple OSS Distributions int rc;
81*a325d9c4SApple OSS Distributions
82*a325d9c4SApple OSS Distributions rc = pthread_create(&th, NULL, pthread_async_do, Block_copy(block));
83*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, "pthread_create");
84*a325d9c4SApple OSS Distributions }
85*a325d9c4SApple OSS Distributions
86*a325d9c4SApple OSS Distributions T_DECL(kqueue_machport, "basic EVFILT_MACHPORT tests")
87*a325d9c4SApple OSS Distributions {
88*a325d9c4SApple OSS Distributions mach_port_options_t opts = {
89*a325d9c4SApple OSS Distributions .flags = MPO_INSERT_SEND_RIGHT,
90*a325d9c4SApple OSS Distributions };
91*a325d9c4SApple OSS Distributions mach_port_t mp, pset;
92*a325d9c4SApple OSS Distributions kern_return_t kr;
93*a325d9c4SApple OSS Distributions struct kevent ke[2];
94*a325d9c4SApple OSS Distributions int kq, rc;
95*a325d9c4SApple OSS Distributions
96*a325d9c4SApple OSS Distributions kr = mach_port_construct(mach_task_self(), &opts, 0, &mp);
97*a325d9c4SApple OSS Distributions T_EXPECT_MACH_SUCCESS(kr, "mach_port_construct()");
98*a325d9c4SApple OSS Distributions
99*a325d9c4SApple OSS Distributions kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &pset);
100*a325d9c4SApple OSS Distributions T_EXPECT_MACH_SUCCESS(kr, "mach_port_allocate(PSET)");
101*a325d9c4SApple OSS Distributions
102*a325d9c4SApple OSS Distributions kr = mach_port_move_member(mach_task_self(), mp, pset);
103*a325d9c4SApple OSS Distributions T_EXPECT_MACH_SUCCESS(kr, "mach_port_move_member(PORT, PSET)");
104*a325d9c4SApple OSS Distributions
105*a325d9c4SApple OSS Distributions kq = kqueue();
106*a325d9c4SApple OSS Distributions T_EXPECT_POSIX_SUCCESS(kq, "kqueue()");
107*a325d9c4SApple OSS Distributions
108*a325d9c4SApple OSS Distributions /*
109*a325d9c4SApple OSS Distributions * Fired when attached
110*a325d9c4SApple OSS Distributions */
111*a325d9c4SApple OSS Distributions send(mp);
112*a325d9c4SApple OSS Distributions
113*a325d9c4SApple OSS Distributions fill_kevent(&ke[0], EV_ADD, mp);
114*a325d9c4SApple OSS Distributions fill_kevent(&ke[1], EV_ADD, pset);
115*a325d9c4SApple OSS Distributions rc = kevent(kq, ke, 2, NULL, 0, &TS(5));
116*a325d9c4SApple OSS Distributions T_EXPECT_POSIX_SUCCESS(rc, "kevent(registration)");
117*a325d9c4SApple OSS Distributions
118*a325d9c4SApple OSS Distributions rc = kevent(kq, NULL, 0, ke, 2, &TS(5));
119*a325d9c4SApple OSS Distributions T_EXPECT_EQ(rc, 2, "kevent(fired at attach time)");
120*a325d9c4SApple OSS Distributions
121*a325d9c4SApple OSS Distributions receive(mp);
122*a325d9c4SApple OSS Distributions rc = kevent(kq, NULL, 0, ke, 2, &TS(1));
123*a325d9c4SApple OSS Distributions T_EXPECT_EQ(rc, 0, "no event");
124*a325d9c4SApple OSS Distributions
125*a325d9c4SApple OSS Distributions /*
126*a325d9c4SApple OSS Distributions * Fired after being attached, before wait
127*a325d9c4SApple OSS Distributions */
128*a325d9c4SApple OSS Distributions send(mp);
129*a325d9c4SApple OSS Distributions rc = kevent(kq, NULL, 0, ke, 2, &TS(5));
130*a325d9c4SApple OSS Distributions T_EXPECT_EQ(rc, 2, "kevent(fired after attach time, before wait)");
131*a325d9c4SApple OSS Distributions
132*a325d9c4SApple OSS Distributions receive(mp);
133*a325d9c4SApple OSS Distributions rc = kevent(kq, NULL, 0, ke, 2, &TS(1));
134*a325d9c4SApple OSS Distributions T_EXPECT_EQ(rc, 0, "no event");
135*a325d9c4SApple OSS Distributions
136*a325d9c4SApple OSS Distributions /*
137*a325d9c4SApple OSS Distributions * Fired after being attached, after wait
138*a325d9c4SApple OSS Distributions */
139*a325d9c4SApple OSS Distributions pthread_async(^{
140*a325d9c4SApple OSS Distributions sleep(1);
141*a325d9c4SApple OSS Distributions send(mp);
142*a325d9c4SApple OSS Distributions });
143*a325d9c4SApple OSS Distributions rc = kevent(kq, NULL, 0, ke, 2, &TS(5));
144*a325d9c4SApple OSS Distributions T_EXPECT_EQ(rc, 2, "kevent(fired after attach time, after wait)");
145*a325d9c4SApple OSS Distributions
146*a325d9c4SApple OSS Distributions receive(mp);
147*a325d9c4SApple OSS Distributions rc = kevent(kq, NULL, 0, ke, 2, &TS(1));
148*a325d9c4SApple OSS Distributions T_EXPECT_EQ(rc, 0, "no event");
149*a325d9c4SApple OSS Distributions
150*a325d9c4SApple OSS Distributions /* Make sure destroying ports wakes you up */
151*a325d9c4SApple OSS Distributions pthread_async(^{
152*a325d9c4SApple OSS Distributions sleep(1);
153*a325d9c4SApple OSS Distributions T_EXPECT_MACH_SUCCESS(mach_port_destruct(mach_task_self(), mp, -1, 0),
154*a325d9c4SApple OSS Distributions "mach_port_destruct");
155*a325d9c4SApple OSS Distributions });
156*a325d9c4SApple OSS Distributions rc = kevent(kq, NULL, 0, ke, 2, &TS(5));
157*a325d9c4SApple OSS Distributions T_EXPECT_EQ(rc, 1, "kevent(port-destroyed)");
158*a325d9c4SApple OSS Distributions T_EXPECT_EQ(ke[0].ident, (uintptr_t)mp, "event was for the port");
159*a325d9c4SApple OSS Distributions
160*a325d9c4SApple OSS Distributions pthread_async(^{
161*a325d9c4SApple OSS Distributions sleep(1);
162*a325d9c4SApple OSS Distributions T_EXPECT_MACH_SUCCESS(mach_port_mod_refs(mach_task_self(), pset,
163*a325d9c4SApple OSS Distributions MACH_PORT_RIGHT_PORT_SET, -1), "destroy pset");
164*a325d9c4SApple OSS Distributions });
165*a325d9c4SApple OSS Distributions rc = kevent(kq, NULL, 0, ke, 2, &TS(5));
166*a325d9c4SApple OSS Distributions T_EXPECT_EQ(rc, 1, "kevent(port-destroyed)");
167*a325d9c4SApple OSS Distributions T_EXPECT_EQ(ke[0].ident, (uintptr_t)pset, "event was for the pset");
168*a325d9c4SApple OSS Distributions }
169