xref: /xnu-8792.41.9/tests/poll.c (revision 5c2921b07a2480ab43ec66f5b9e41cb872bc554f)
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