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