xref: /xnu-11215.1.10/tests/kqueue_nesting.c (revision 8d741a5de7ff4191bf97d57b9f54c2f6d4a15585)
1*8d741a5dSApple OSS Distributions #include <unistd.h>
2*8d741a5dSApple OSS Distributions #include <pthread.h>
3*8d741a5dSApple OSS Distributions #include <errno.h>
4*8d741a5dSApple OSS Distributions 
5*8d741a5dSApple OSS Distributions #include <sys/event.h>
6*8d741a5dSApple OSS Distributions #include <mach/mach.h>
7*8d741a5dSApple OSS Distributions #include <mach/mach_port.h>
8*8d741a5dSApple OSS Distributions 
9*8d741a5dSApple OSS Distributions #include <Block.h>
10*8d741a5dSApple OSS Distributions #include <darwintest.h>
11*8d741a5dSApple OSS Distributions 
12*8d741a5dSApple OSS Distributions T_DECL(kqueue_nesting_level, "rdar://100277117 (Reduce kqueue nesting level so that we don't overflow kernel stack)")
13*8d741a5dSApple OSS Distributions {
14*8d741a5dSApple OSS Distributions 	// Create a port and register a knote for it on a kqueue
15*8d741a5dSApple OSS Distributions 	mach_port_t port = MACH_PORT_NULL;
16*8d741a5dSApple OSS Distributions 	kern_return_t kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
17*8d741a5dSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "allocating a port with a receive right");
18*8d741a5dSApple OSS Distributions 
19*8d741a5dSApple OSS Distributions 	int port_kq = kqueue();
20*8d741a5dSApple OSS Distributions 	struct kevent_qos_s event = {
21*8d741a5dSApple OSS Distributions 		.ident = port,
22*8d741a5dSApple OSS Distributions 		.filter = EVFILT_MACHPORT,
23*8d741a5dSApple OSS Distributions 		.flags = EV_ADD | EV_ENABLE,
24*8d741a5dSApple OSS Distributions 		.qos = 0x00,
25*8d741a5dSApple OSS Distributions 		.udata = 0x66666666,
26*8d741a5dSApple OSS Distributions 		.fflags = MACH_RCV_MSG,
27*8d741a5dSApple OSS Distributions 		.xflags = 0,
28*8d741a5dSApple OSS Distributions 		.data = 0,
29*8d741a5dSApple OSS Distributions 		.ext = {},
30*8d741a5dSApple OSS Distributions 	};
31*8d741a5dSApple OSS Distributions 	int nevents = kevent_qos(port_kq, &event, 1, NULL, 0, NULL, NULL, 0);
32*8d741a5dSApple OSS Distributions 	T_EXPECT_EQ(nevents, 0, NULL);
33*8d741a5dSApple OSS Distributions 
34*8d741a5dSApple OSS Distributions 	// Register the other kqueues
35*8d741a5dSApple OSS Distributions 	int child_kq = port_kq;
36*8d741a5dSApple OSS Distributions 
37*8d741a5dSApple OSS Distributions 	for (size_t i = 0; i < 1000; i++) {
38*8d741a5dSApple OSS Distributions 		int kq = kqueue();
39*8d741a5dSApple OSS Distributions 		struct kevent_qos_s kq_read_event = {
40*8d741a5dSApple OSS Distributions 			.ident = child_kq,
41*8d741a5dSApple OSS Distributions 			.filter = EVFILT_READ,
42*8d741a5dSApple OSS Distributions 			.flags = EV_ADD | EV_ENABLE,
43*8d741a5dSApple OSS Distributions 			.qos = 0x00,
44*8d741a5dSApple OSS Distributions 			.udata = 0x66666666,
45*8d741a5dSApple OSS Distributions 			.fflags = 0x00,
46*8d741a5dSApple OSS Distributions 			.xflags = 0x00,
47*8d741a5dSApple OSS Distributions 			.data = 0,
48*8d741a5dSApple OSS Distributions 			.ext = {},
49*8d741a5dSApple OSS Distributions 		};
50*8d741a5dSApple OSS Distributions 
51*8d741a5dSApple OSS Distributions 		nevents = kevent_qos(kq, &kq_read_event, 1, NULL, 0, NULL, NULL, 0);
52*8d741a5dSApple OSS Distributions 		// This kevent may sometimes fail after we exceed the limit enforced by the
53*8d741a5dSApple OSS Distributions 		// kernel in which case, we'd just have created kqueues but not set up any
54*8d741a5dSApple OSS Distributions 		// knotes on them.
55*8d741a5dSApple OSS Distributions 		//
56*8d741a5dSApple OSS Distributions 		// On old-OSes prior to rdar://100277117, this would always succeed and then
57*8d741a5dSApple OSS Distributions 		// we'd panic when we send a message
58*8d741a5dSApple OSS Distributions 		child_kq = kq;
59*8d741a5dSApple OSS Distributions 	}
60*8d741a5dSApple OSS Distributions 
61*8d741a5dSApple OSS Distributions 	// Send a message to the port and activate the first kqueue
62*8d741a5dSApple OSS Distributions 	struct {
63*8d741a5dSApple OSS Distributions 		mach_msg_header_t header;
64*8d741a5dSApple OSS Distributions 		uint64_t data;
65*8d741a5dSApple OSS Distributions 	} message = {
66*8d741a5dSApple OSS Distributions 		.header = {
67*8d741a5dSApple OSS Distributions 			.msgh_remote_port = port,
68*8d741a5dSApple OSS Distributions 			.msgh_local_port = MACH_PORT_NULL,
69*8d741a5dSApple OSS Distributions 			.msgh_voucher_port = MACH_PORT_NULL,
70*8d741a5dSApple OSS Distributions 			.msgh_size = sizeof(message),
71*8d741a5dSApple OSS Distributions 			.msgh_id = 0x88888888,
72*8d741a5dSApple OSS Distributions 			.msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MAKE_SEND_ONCE, 0, 0, 0),
73*8d741a5dSApple OSS Distributions 		},
74*8d741a5dSApple OSS Distributions 		.data = 0x8888888888888,
75*8d741a5dSApple OSS Distributions 	};
76*8d741a5dSApple OSS Distributions 
77*8d741a5dSApple OSS Distributions 	kr = mach_msg(&message.header, MACH_SEND_MSG, sizeof(message), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
78*8d741a5dSApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "mach_msg(SEND)");
79*8d741a5dSApple OSS Distributions }
80