1 #ifdef T_NAMESPACE 2 #undef T_NAMESPACE 3 #endif 4 #include <darwintest.h> 5 6 #include <dispatch/dispatch.h> 7 #include <fcntl.h> 8 #include <mach/mach.h> 9 #include <poll.h> 10 #include <stdint.h> 11 #include <unistd.h> 12 13 T_GLOBAL_META(T_META_NAMESPACE("xnu.poll"), 14 T_META_RUN_CONCURRENTLY(true)); 15 16 #define SLEEP_TIME_SECS 1 17 #define POLL_TIMEOUT_MS 1800 18 static_assert(POLL_TIMEOUT_MS > (SLEEP_TIME_SECS * 1000), 19 "poll timeout should be longer than sleep time"); 20 21 /* 22 * This matches the behavior of other UNIXes, but is under-specified in POSIX. 23 * 24 * See <rdar://problem/28372390>. 25 */ 26 T_DECL(sleep_with_no_fds, 27 "poll() called with no fds provided should act like sleep") 28 { 29 uint64_t begin_time, sleep_time, poll_time; 30 struct pollfd pfd = { .fd = 0, .events = 0, .revents = 0 }; 31 32 begin_time = mach_absolute_time(); 33 sleep(SLEEP_TIME_SECS); 34 sleep_time = mach_absolute_time() - begin_time; 35 T_LOG("sleep(%d) ~= %llu mach absolute time units", SLEEP_TIME_SECS, sleep_time); 36 37 begin_time = mach_absolute_time(); 38 T_ASSERT_POSIX_SUCCESS(poll(&pfd, 0, POLL_TIMEOUT_MS), 39 "poll() with 0 events and timeout %d ms", POLL_TIMEOUT_MS); 40 poll_time = mach_absolute_time() - begin_time; 41 42 T_EXPECT_GT(poll_time, sleep_time, 43 "poll(... %d) should wait longer than sleep(1)", POLL_TIMEOUT_MS); 44 } 45 46 #define LAUNCHD_PATH "/sbin/launchd" 47 #define PIPE_DIR_TIMEOUT_SECS 1 48 49 /* 50 * See <rdar://problem/28539155>. 51 */ 52 T_DECL(directories, 53 "poll() with directories should return an error") 54 { 55 int file, dir, pipes[2]; 56 struct pollfd pfd[] = { 57 { .events = POLLIN }, 58 { .events = POLLIN }, 59 { .events = POLLIN }, 60 }; 61 62 file = open(LAUNCHD_PATH, O_RDONLY | O_NONBLOCK); 63 T_QUIET; T_ASSERT_POSIX_SUCCESS(file, "open(%s)", LAUNCHD_PATH); 64 dir = open(".", O_RDONLY | O_NONBLOCK); 65 T_QUIET; T_ASSERT_POSIX_SUCCESS(dir, "open(\".\")"); 66 T_QUIET; T_ASSERT_POSIX_SUCCESS(pipe(pipes), NULL); 67 68 /* just directory */ 69 pfd[0].fd = dir; 70 T_EXPECT_POSIX_SUCCESS(poll(pfd, 1, -1), "poll() with a directory"); 71 T_QUIET; T_EXPECT_TRUE(pfd[0].revents & POLLNVAL, 72 "directory should be an invalid event"); 73 74 /* file and directory */ 75 pfd[0].fd = file; pfd[0].revents = 0; 76 pfd[1].fd = dir; pfd[1].revents = 0; 77 T_EXPECT_POSIX_SUCCESS(poll(pfd, 2, -1), 78 "poll() with a file and directory"); 79 T_QUIET; T_EXPECT_TRUE(pfd[0].revents & POLLIN, "file should be readable"); 80 T_QUIET; T_EXPECT_TRUE(pfd[1].revents & POLLNVAL, 81 "directory should be an invalid event"); 82 83 /* directory and file */ 84 pfd[0].fd = dir; pfd[0].revents = 0; 85 pfd[1].fd = file; pfd[1].revents = 0; 86 T_EXPECT_POSIX_SUCCESS(poll(pfd, 2, -1), 87 "poll() with a directory and a file"); 88 T_QUIET; T_EXPECT_TRUE(pfd[0].revents & POLLNVAL, 89 "directory should be an invalid event"); 90 T_QUIET; T_EXPECT_TRUE(pfd[1].revents & POLLIN, "file should be readable"); 91 92 /* file and pipe */ 93 pfd[0].fd = file; pfd[0].revents = 0; 94 pfd[1].fd = pipes[0]; pfd[0].revents = 0; 95 T_EXPECT_POSIX_SUCCESS(poll(pfd, 2, -1), 96 "poll() with a file and pipe"); 97 T_QUIET; T_EXPECT_TRUE(pfd[0].revents & POLLIN, "file should be readable"); 98 T_QUIET; T_EXPECT_FALSE(pfd[1].revents & POLLIN, 99 "pipe should not be readable"); 100 101 /* file, directory, and pipe */ 102 pfd[0].fd = file; pfd[0].revents = 0; 103 pfd[1].fd = dir; pfd[1].revents = 0; 104 pfd[2].fd = pipes[0]; pfd[2].revents = 0; 105 T_EXPECT_POSIX_SUCCESS(poll(pfd, 3, -1), 106 "poll() with a file, directory, and pipe"); 107 T_QUIET; T_EXPECT_TRUE(pfd[0].revents & POLLIN, "file should be readable"); 108 T_QUIET; T_EXPECT_TRUE(pfd[1].revents & POLLNVAL, 109 "directory should be an invalid event"); 110 T_QUIET; T_EXPECT_FALSE(pfd[2].revents & POLLIN, "pipe should not be readable"); 111 112 /* directory and pipe */ 113 __block bool timed_out = true; 114 pfd[0].fd = dir; pfd[0].revents = 0; 115 pfd[1].fd = pipes[0]; pfd[1].revents = 0; 116 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 117 PIPE_DIR_TIMEOUT_SECS * NSEC_PER_SEC), 118 dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{ 119 T_ASSERT_FALSE(timed_out, "poll timed out after %d seconds", 120 PIPE_DIR_TIMEOUT_SECS); 121 }); 122 123 T_EXPECT_POSIX_SUCCESS(poll(pfd, 3, -1), 124 "poll() with a directory and pipe"); 125 timed_out = false; 126 127 T_QUIET; T_EXPECT_TRUE(pfd[0].revents & POLLNVAL, 128 "directory should be an invalid event"); 129 T_QUIET; T_EXPECT_FALSE(pfd[1].revents & POLLIN, "pipe should not be readable"); 130 } 131