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