1*d583b39bSJohn Wren Kennedy /*
2*d583b39bSJohn Wren Kennedy  * This file and its contents are supplied under the terms of the
3*d583b39bSJohn Wren Kennedy  * Common Development and Distribution License ("CDDL"), version 1.0.
4*d583b39bSJohn Wren Kennedy  * You may only use this file in accordance with the terms of version
5*d583b39bSJohn Wren Kennedy  * 1.0 of the CDDL.
6*d583b39bSJohn Wren Kennedy  *
7*d583b39bSJohn Wren Kennedy  * A full copy of the text of the CDDL should have accompanied this
8*d583b39bSJohn Wren Kennedy  * source.  A copy of the CDDL is also available via the Internet at
9*d583b39bSJohn Wren Kennedy  * http://www.illumos.org/license/CDDL.
10*d583b39bSJohn Wren Kennedy  */
11*d583b39bSJohn Wren Kennedy 
12*d583b39bSJohn Wren Kennedy /*
13*d583b39bSJohn Wren Kennedy  * Copyright (c) 2012 by Delphix. All rights reserved.
14*d583b39bSJohn Wren Kennedy  */
15*d583b39bSJohn Wren Kennedy 
16*d583b39bSJohn Wren Kennedy #include <stdlib.h>
17*d583b39bSJohn Wren Kennedy #include <stdio.h>
18*d583b39bSJohn Wren Kennedy #include <stdarg.h>
19*d583b39bSJohn Wren Kennedy #include <string.h>
20*d583b39bSJohn Wren Kennedy #include <fcntl.h>
21*d583b39bSJohn Wren Kennedy #include <pthread.h>
22*d583b39bSJohn Wren Kennedy #include <assert.h>
23*d583b39bSJohn Wren Kennedy #include <errno.h>
24*d583b39bSJohn Wren Kennedy #include <ctype.h>
25*d583b39bSJohn Wren Kennedy #include <unistd.h>
26*d583b39bSJohn Wren Kennedy #include <poll.h>
27*d583b39bSJohn Wren Kennedy #include <sys/types.h>
28*d583b39bSJohn Wren Kennedy #include <sys/wait.h>
29*d583b39bSJohn Wren Kennedy #include <sys/stat.h>
30*d583b39bSJohn Wren Kennedy #include <sys/socket.h>
31*d583b39bSJohn Wren Kennedy #include <sys/devpoll.h>
32*d583b39bSJohn Wren Kennedy 
33*d583b39bSJohn Wren Kennedy /*
34*d583b39bSJohn Wren Kennedy  * poll_test.c --
35*d583b39bSJohn Wren Kennedy  *
36*d583b39bSJohn Wren Kennedy  *      This file implements some simple tests to verify the behavior of the
37*d583b39bSJohn Wren Kennedy  *      poll system call and the DP_POLL ioctl on /dev/poll.
38*d583b39bSJohn Wren Kennedy  *
39*d583b39bSJohn Wren Kennedy  * Background:
40*d583b39bSJohn Wren Kennedy  *
41*d583b39bSJohn Wren Kennedy  *      Several customers recently ran into an issue where threads in grizzly
42*d583b39bSJohn Wren Kennedy  *      (java http server implementation) would randomly wake up from a java
43*d583b39bSJohn Wren Kennedy  *      call to select against a java.nio.channels.Selector with no events ready
44*d583b39bSJohn Wren Kennedy  *      but well before the specified timeout expired. The
45*d583b39bSJohn Wren Kennedy  *      java.nio.channels.Selector select logic is implemented via /dev/poll.
46*d583b39bSJohn Wren Kennedy  *      The selector opens /dev/poll, writes the file descriptors it wants to
47*d583b39bSJohn Wren Kennedy  *      select on to the file descritpor, and then issues a DP_POLL ioctl to
48*d583b39bSJohn Wren Kennedy  *      wait for events to be ready.
49*d583b39bSJohn Wren Kennedy  *
50*d583b39bSJohn Wren Kennedy  *      The DP_POLL ioctl arguments include a relative timeout in milliseconds,
51*d583b39bSJohn Wren Kennedy  *      according to man poll.7d the ioctl should block until events are ready,
52*d583b39bSJohn Wren Kennedy  *      the timeout expires, or a signal was received. In this case we noticed
53*d583b39bSJohn Wren Kennedy  *      that DP_POLL was returning before the timeout expired despite no events
54*d583b39bSJohn Wren Kennedy  *      being ready and no signal being delivered.
55*d583b39bSJohn Wren Kennedy  *
56*d583b39bSJohn Wren Kennedy  *      Using dtrace we discovered that DP_POLL was returning in cases where the
57*d583b39bSJohn Wren Kennedy  *      system time was changed and the thread calling DP_POLL was woken up as
58*d583b39bSJohn Wren Kennedy  *      a result of the process forking. The DP_POLL logic was in a loop
59*d583b39bSJohn Wren Kennedy  *      checking if events were ready and then calling cv_waituntil_sig to
60*d583b39bSJohn Wren Kennedy  *      block. cv_waituntil_sig will return -1 if the system time has changed,
61*d583b39bSJohn Wren Kennedy  *      causing the DP_POLL to complete prematurely.
62*d583b39bSJohn Wren Kennedy  *
63*d583b39bSJohn Wren Kennedy  *      Looking at the code it turns out the same problem exists in
64*d583b39bSJohn Wren Kennedy  *      the implementation for poll.2 as well.
65*d583b39bSJohn Wren Kennedy  *
66*d583b39bSJohn Wren Kennedy  * Fix:
67*d583b39bSJohn Wren Kennedy  *
68*d583b39bSJohn Wren Kennedy  *      The fix changes dpioctl and poll_common to use cv_relwaituntil_sig
69*d583b39bSJohn Wren Kennedy  *      rather then cv_waituntil_sig. cv_reltimedwait_sig expects a
70*d583b39bSJohn Wren Kennedy  *      relative timeout rather then an absolute timeout, so we avoid the
71*d583b39bSJohn Wren Kennedy  *      problem.
72*d583b39bSJohn Wren Kennedy  *
73*d583b39bSJohn Wren Kennedy  * Test:
74*d583b39bSJohn Wren Kennedy  *
75*d583b39bSJohn Wren Kennedy  *      The test verifies that changing the date does not wake up threads
76*d583b39bSJohn Wren Kennedy  *      blocked processing a poll request or a DP_POLL ioctl. The test spawns
77*d583b39bSJohn Wren Kennedy  *      one thread that changes the date and forks (to force the threads to
78*d583b39bSJohn Wren Kennedy  *      wakeup from cv_reltimedwait_sig) every two seconds. The test spawns
79*d583b39bSJohn Wren Kennedy  *      a second thread that issues poll / DP_POLL on an fd set that will
80*d583b39bSJohn Wren Kennedy  *      never have events ready and verifies that it does not return until
81*d583b39bSJohn Wren Kennedy  *      the specified timeout expires.
82*d583b39bSJohn Wren Kennedy  */
83*d583b39bSJohn Wren Kennedy 
84*d583b39bSJohn Wren Kennedy /*
85*d583b39bSJohn Wren Kennedy  * The maximum amount of skew in seconds allowed between the
86*d583b39bSJohn Wren Kennedy  * expected an actual time that a test takes.
87*d583b39bSJohn Wren Kennedy  */
88*d583b39bSJohn Wren Kennedy #define	TIME_DRIFT	1
89*d583b39bSJohn Wren Kennedy 
90*d583b39bSJohn Wren Kennedy static pthread_mutex_t	exitLock = PTHREAD_MUTEX_INITIALIZER;
91*d583b39bSJohn Wren Kennedy static pthread_cond_t	exitCond = PTHREAD_COND_INITIALIZER;
92*d583b39bSJohn Wren Kennedy static int		terminated = 0;
93*d583b39bSJohn Wren Kennedy 
94*d583b39bSJohn Wren Kennedy /*
95*d583b39bSJohn Wren Kennedy  * Set via -d to enable debug logging
96*d583b39bSJohn Wren Kennedy  */
97*d583b39bSJohn Wren Kennedy static int debug = 0;
98*d583b39bSJohn Wren Kennedy 
99*d583b39bSJohn Wren Kennedy static void
debug_log(const char * format,...)100*d583b39bSJohn Wren Kennedy debug_log(const char *format, ...)
101*d583b39bSJohn Wren Kennedy {
102*d583b39bSJohn Wren Kennedy 	va_list	args;
103*d583b39bSJohn Wren Kennedy 
104*d583b39bSJohn Wren Kennedy 	if (!debug) {
105*d583b39bSJohn Wren Kennedy 		return;
106*d583b39bSJohn Wren Kennedy 	}
107*d583b39bSJohn Wren Kennedy 
108*d583b39bSJohn Wren Kennedy 	(void) printf("DEBUG: ");
109*d583b39bSJohn Wren Kennedy 
110*d583b39bSJohn Wren Kennedy 	va_start(args, format);
111*d583b39bSJohn Wren Kennedy 	(void) vprintf(format, args);
112*d583b39bSJohn Wren Kennedy 	va_end(args);
113*d583b39bSJohn Wren Kennedy }
114*d583b39bSJohn Wren Kennedy 
115*d583b39bSJohn Wren Kennedy static void
test_start(const char * testName,const char * format,...)116*d583b39bSJohn Wren Kennedy test_start(const char *testName, const char *format, ...)
117*d583b39bSJohn Wren Kennedy {
118*d583b39bSJohn Wren Kennedy 	va_list	args;
119*d583b39bSJohn Wren Kennedy 
120*d583b39bSJohn Wren Kennedy 	(void) printf("TEST STARTING %s: ", testName);
121*d583b39bSJohn Wren Kennedy 
122*d583b39bSJohn Wren Kennedy 	va_start(args, format);
123*d583b39bSJohn Wren Kennedy 	(void) vprintf(format, args);
124*d583b39bSJohn Wren Kennedy 	va_end(args);
125*d583b39bSJohn Wren Kennedy 	(void) fflush(stdout);
126*d583b39bSJohn Wren Kennedy }
127*d583b39bSJohn Wren Kennedy 
128*d583b39bSJohn Wren Kennedy static void
test_failed(const char * testName,const char * format,...)129*d583b39bSJohn Wren Kennedy test_failed(const char *testName, const char *format, ...)
130*d583b39bSJohn Wren Kennedy {
131*d583b39bSJohn Wren Kennedy 	va_list	args;
132*d583b39bSJohn Wren Kennedy 
133*d583b39bSJohn Wren Kennedy 	(void) printf("TEST FAILED %s: ", testName);
134*d583b39bSJohn Wren Kennedy 
135*d583b39bSJohn Wren Kennedy 	va_start(args, format);
136*d583b39bSJohn Wren Kennedy 	(void) vprintf(format, args);
137*d583b39bSJohn Wren Kennedy 	va_end(args);
138*d583b39bSJohn Wren Kennedy 
139*d583b39bSJohn Wren Kennedy 	(void) exit(-1);
140*d583b39bSJohn Wren Kennedy }
141*d583b39bSJohn Wren Kennedy 
142*d583b39bSJohn Wren Kennedy static void
test_passed(const char * testName)143*d583b39bSJohn Wren Kennedy test_passed(const char *testName)
144*d583b39bSJohn Wren Kennedy {
145*d583b39bSJohn Wren Kennedy 	(void) printf("TEST PASS: %s\n", testName);
146*d583b39bSJohn Wren Kennedy 	(void) fflush(stdout);
147*d583b39bSJohn Wren Kennedy }
148*d583b39bSJohn Wren Kennedy 
149*d583b39bSJohn Wren Kennedy static int
check_time(time_t elapsed,time_t expected)150*d583b39bSJohn Wren Kennedy check_time(time_t elapsed, time_t expected)
151*d583b39bSJohn Wren Kennedy {
152*d583b39bSJohn Wren Kennedy 	time_t	diff = expected - elapsed;
153*d583b39bSJohn Wren Kennedy 
154*d583b39bSJohn Wren Kennedy 	/*
155*d583b39bSJohn Wren Kennedy 	 * We may take slightly more or less time then expected,
156*d583b39bSJohn Wren Kennedy 	 * we allow for a small fudge factor if things completed
157*d583b39bSJohn Wren Kennedy 	 * before we expect them to.
158*d583b39bSJohn Wren Kennedy 	 */
159*d583b39bSJohn Wren Kennedy 	return (elapsed >= expected || diff <= TIME_DRIFT);
160*d583b39bSJohn Wren Kennedy }
161*d583b39bSJohn Wren Kennedy 
162*d583b39bSJohn Wren Kennedy static int
poll_wrapper(pollfd_t * fds,nfds_t nfds,int timeout,time_t * elapsed)163*d583b39bSJohn Wren Kennedy poll_wrapper(pollfd_t *fds, nfds_t nfds, int timeout, time_t *elapsed)
164*d583b39bSJohn Wren Kennedy {
165*d583b39bSJohn Wren Kennedy 	int		ret;
166*d583b39bSJohn Wren Kennedy 	time_t		start = time(NULL);
167*d583b39bSJohn Wren Kennedy 
168*d583b39bSJohn Wren Kennedy 	debug_log("POLL start: (0x%p, %d, %d)\n", fds, nfds, timeout);
169*d583b39bSJohn Wren Kennedy 
170*d583b39bSJohn Wren Kennedy 	ret = poll(fds, nfds, timeout);
171*d583b39bSJohn Wren Kennedy 
172*d583b39bSJohn Wren Kennedy 	*elapsed = time(NULL) - start;
173*d583b39bSJohn Wren Kennedy 
174*d583b39bSJohn Wren Kennedy 	debug_log("POLL end: (0x%p, %d, %d) returns %d (elapse=%d)\n",
175*d583b39bSJohn Wren Kennedy 	    fds, nfds, timeout, ret, (*elapsed));
176*d583b39bSJohn Wren Kennedy 
177*d583b39bSJohn Wren Kennedy 	return (ret);
178*d583b39bSJohn Wren Kennedy }
179*d583b39bSJohn Wren Kennedy 
180*d583b39bSJohn Wren Kennedy static int
dppoll(int pollfd,pollfd_t * fds,nfds_t nfds,int timeout,time_t * elapsed)181*d583b39bSJohn Wren Kennedy dppoll(int pollfd, pollfd_t *fds, nfds_t nfds, int timeout, time_t *elapsed)
182*d583b39bSJohn Wren Kennedy {
183*d583b39bSJohn Wren Kennedy 	struct dvpoll	arg;
184*d583b39bSJohn Wren Kennedy 	int		ret;
185*d583b39bSJohn Wren Kennedy 	time_t		start = time(NULL);
186*d583b39bSJohn Wren Kennedy 
187*d583b39bSJohn Wren Kennedy 	arg.dp_fds = fds;
188*d583b39bSJohn Wren Kennedy 	arg.dp_nfds = nfds;
189*d583b39bSJohn Wren Kennedy 	arg.dp_timeout = timeout;
190*d583b39bSJohn Wren Kennedy 
191*d583b39bSJohn Wren Kennedy 	debug_log("DP_POLL start: (0x%p, %d, %d)\n", fds, nfds, timeout);
192*d583b39bSJohn Wren Kennedy 
193*d583b39bSJohn Wren Kennedy 	ret = ioctl(pollfd, DP_POLL, &arg);
194*d583b39bSJohn Wren Kennedy 
195*d583b39bSJohn Wren Kennedy 	*elapsed = time(NULL) - start;
196*d583b39bSJohn Wren Kennedy 
197*d583b39bSJohn Wren Kennedy 	debug_log("DP_POLL end: (0x%p, %d, %d) returns %d (elapse=%d)\n",
198*d583b39bSJohn Wren Kennedy 	    fds, arg.dp_nfds, arg.dp_timeout, ret, (*elapsed));
199*d583b39bSJohn Wren Kennedy 
200*d583b39bSJohn Wren Kennedy 	return (ret);
201*d583b39bSJohn Wren Kennedy }
202*d583b39bSJohn Wren Kennedy 
203*d583b39bSJohn Wren Kennedy static void
clear_fd(const char * testName,int pollfd,int testfd)204*d583b39bSJohn Wren Kennedy clear_fd(const char *testName, int pollfd, int testfd)
205*d583b39bSJohn Wren Kennedy {
206*d583b39bSJohn Wren Kennedy 	int		ret;
207*d583b39bSJohn Wren Kennedy 	pollfd_t	fd;
208*d583b39bSJohn Wren Kennedy 
209*d583b39bSJohn Wren Kennedy 	fd.fd = testfd;
210*d583b39bSJohn Wren Kennedy 	fd.events = POLLREMOVE;
211*d583b39bSJohn Wren Kennedy 	fd.revents = 0;
212*d583b39bSJohn Wren Kennedy 
213*d583b39bSJohn Wren Kennedy 	ret = write(pollfd, &fd, sizeof (pollfd_t));
214*d583b39bSJohn Wren Kennedy 
215*d583b39bSJohn Wren Kennedy 	if (ret != sizeof (pollfd_t)) {
216*d583b39bSJohn Wren Kennedy 		if (ret < 0) {
217*d583b39bSJohn Wren Kennedy 			test_failed(testName, "Failed to clear fd %d: %s",
218*d583b39bSJohn Wren Kennedy 			    testfd, strerror(ret));
219*d583b39bSJohn Wren Kennedy 		}
220*d583b39bSJohn Wren Kennedy 
221*d583b39bSJohn Wren Kennedy 
222*d583b39bSJohn Wren Kennedy 		test_failed(testName, "Failed to clear fd %d: %d", testfd, ret);
223*d583b39bSJohn Wren Kennedy 	}
224*d583b39bSJohn Wren Kennedy }
225*d583b39bSJohn Wren Kennedy 
226*d583b39bSJohn Wren Kennedy /*
227*d583b39bSJohn Wren Kennedy  * TEST: poll with no FDs set, verify we wait the appropriate amount of time.
228*d583b39bSJohn Wren Kennedy  */
229*d583b39bSJohn Wren Kennedy static void
poll_no_fd_test(void)230*d583b39bSJohn Wren Kennedy poll_no_fd_test(void)
231*d583b39bSJohn Wren Kennedy {
232*d583b39bSJohn Wren Kennedy 	const char	*testName = __func__;
233*d583b39bSJohn Wren Kennedy 	time_t		elapsed;
234*d583b39bSJohn Wren Kennedy 	int		timeout = 10;
235*d583b39bSJohn Wren Kennedy 	int		ret;
236*d583b39bSJohn Wren Kennedy 
237*d583b39bSJohn Wren Kennedy 	test_start(testName, "poll for %d sec with no fds\n", timeout);
238*d583b39bSJohn Wren Kennedy 
239*d583b39bSJohn Wren Kennedy 	ret = poll_wrapper(NULL, 0, timeout * 1000, &elapsed);
240*d583b39bSJohn Wren Kennedy 
241*d583b39bSJohn Wren Kennedy 	if (ret != 0) {
242*d583b39bSJohn Wren Kennedy 		test_failed(testName, "POLL returns %d (expected 0)\n", ret);
243*d583b39bSJohn Wren Kennedy 	}
244*d583b39bSJohn Wren Kennedy 
245*d583b39bSJohn Wren Kennedy 	if (!check_time(elapsed, timeout)) {
246*d583b39bSJohn Wren Kennedy 		test_failed(testName, "took %d (expected %d)\n",
247*d583b39bSJohn Wren Kennedy 		    elapsed, timeout);
248*d583b39bSJohn Wren Kennedy 	}
249*d583b39bSJohn Wren Kennedy 
250*d583b39bSJohn Wren Kennedy 	test_passed(testName);
251*d583b39bSJohn Wren Kennedy }
252*d583b39bSJohn Wren Kennedy 
253*d583b39bSJohn Wren Kennedy /*
254*d583b39bSJohn Wren Kennedy  * TEST: POLL with a valid FD set, verify that we wait the appropriate amount
255*d583b39bSJohn Wren Kennedy  * of time.
256*d583b39bSJohn Wren Kennedy  */
257*d583b39bSJohn Wren Kennedy static void
poll_with_fds_test(int testfd)258*d583b39bSJohn Wren Kennedy poll_with_fds_test(int testfd)
259*d583b39bSJohn Wren Kennedy {
260*d583b39bSJohn Wren Kennedy 	const char	*testName = __func__;
261*d583b39bSJohn Wren Kennedy 	time_t		elapsed;
262*d583b39bSJohn Wren Kennedy 	int		timeout = 10;
263*d583b39bSJohn Wren Kennedy 	int		ret;
264*d583b39bSJohn Wren Kennedy 	pollfd_t	fd;
265*d583b39bSJohn Wren Kennedy 
266*d583b39bSJohn Wren Kennedy 	fd.fd = testfd;
267*d583b39bSJohn Wren Kennedy 	fd.events = 0;
268*d583b39bSJohn Wren Kennedy 	fd.revents = 0;
269*d583b39bSJohn Wren Kennedy 
270*d583b39bSJohn Wren Kennedy 	test_start(testName, "poll for %d sec with fds\n", timeout);
271*d583b39bSJohn Wren Kennedy 
272*d583b39bSJohn Wren Kennedy 	ret = poll_wrapper(&fd, 1, timeout * 1000, &elapsed);
273*d583b39bSJohn Wren Kennedy 
274*d583b39bSJohn Wren Kennedy 	if (ret != 0) {
275*d583b39bSJohn Wren Kennedy 		test_failed(testName, "POLL returns %d (expected 0)\n", ret);
276*d583b39bSJohn Wren Kennedy 	}
277*d583b39bSJohn Wren Kennedy 
278*d583b39bSJohn Wren Kennedy 	if (!check_time(elapsed, timeout)) {
279*d583b39bSJohn Wren Kennedy 		test_failed(testName, "took %d (expected %d)\n",
280*d583b39bSJohn Wren Kennedy 		    elapsed, timeout);
281*d583b39bSJohn Wren Kennedy 	}
282*d583b39bSJohn Wren Kennedy 
283*d583b39bSJohn Wren Kennedy 	test_passed(testName);
284*d583b39bSJohn Wren Kennedy }
285*d583b39bSJohn Wren Kennedy 
286*d583b39bSJohn Wren Kennedy /*
287*d583b39bSJohn Wren Kennedy  * TEST: DP_POLL with no FDs set, verify we wait the appropriate
288*d583b39bSJohn Wren Kennedy  * amount of time.
289*d583b39bSJohn Wren Kennedy  */
290*d583b39bSJohn Wren Kennedy static void
dev_poll_no_fd_test(int pollfd)291*d583b39bSJohn Wren Kennedy dev_poll_no_fd_test(int pollfd)
292*d583b39bSJohn Wren Kennedy {
293*d583b39bSJohn Wren Kennedy 	const char	*testName = __func__;
294*d583b39bSJohn Wren Kennedy 	time_t		elapsed;
295*d583b39bSJohn Wren Kennedy 	int		timeout = 10;
296*d583b39bSJohn Wren Kennedy 	int		ret;
297*d583b39bSJohn Wren Kennedy 
298*d583b39bSJohn Wren Kennedy 	test_start(testName, "poll for %d sec with no fds\n", timeout);
299*d583b39bSJohn Wren Kennedy 
300*d583b39bSJohn Wren Kennedy 	ret = dppoll(pollfd, NULL, 0, timeout * 1000, &elapsed);
301*d583b39bSJohn Wren Kennedy 
302*d583b39bSJohn Wren Kennedy 	if (ret != 0) {
303*d583b39bSJohn Wren Kennedy 		test_failed(testName, "DP_POLL returns %d (expected 0)\n", ret);
304*d583b39bSJohn Wren Kennedy 	}
305*d583b39bSJohn Wren Kennedy 
306*d583b39bSJohn Wren Kennedy 	if (!check_time(elapsed, timeout)) {
307*d583b39bSJohn Wren Kennedy 		test_failed(testName, "took %d (expected %d)\n",
308*d583b39bSJohn Wren Kennedy 		    elapsed, timeout);
309*d583b39bSJohn Wren Kennedy 	}
310*d583b39bSJohn Wren Kennedy 
311*d583b39bSJohn Wren Kennedy 	test_passed(testName);
312*d583b39bSJohn Wren Kennedy }
313*d583b39bSJohn Wren Kennedy 
314*d583b39bSJohn Wren Kennedy /*
315*d583b39bSJohn Wren Kennedy  * TEST: DP_POLL with a valid FD set, verify that we wait
316*d583b39bSJohn Wren Kennedy  * the appropriate amount of time.
317*d583b39bSJohn Wren Kennedy  */
318*d583b39bSJohn Wren Kennedy static void
dev_poll_with_fds_test(int pollfd,int testfd)319*d583b39bSJohn Wren Kennedy dev_poll_with_fds_test(int pollfd, int testfd)
320*d583b39bSJohn Wren Kennedy {
321*d583b39bSJohn Wren Kennedy 	const char	*testName = __func__;
322*d583b39bSJohn Wren Kennedy 	time_t		elapsed;
323*d583b39bSJohn Wren Kennedy 	int		timeout = 10;
324*d583b39bSJohn Wren Kennedy 	int		ret;
325*d583b39bSJohn Wren Kennedy 	pollfd_t	fds[5];
326*d583b39bSJohn Wren Kennedy 
327*d583b39bSJohn Wren Kennedy 	test_start(testName, "poll for %d sec with fds\n", timeout);
328*d583b39bSJohn Wren Kennedy 
329*d583b39bSJohn Wren Kennedy 	/*
330*d583b39bSJohn Wren Kennedy 	 * Clear the FD in case it's already in the cached set
331*d583b39bSJohn Wren Kennedy 	 */
332*d583b39bSJohn Wren Kennedy 	clear_fd(testName, pollfd, testfd);
333*d583b39bSJohn Wren Kennedy 
334*d583b39bSJohn Wren Kennedy 	/*
335*d583b39bSJohn Wren Kennedy 	 * Add the FD with POLLIN
336*d583b39bSJohn Wren Kennedy 	 */
337*d583b39bSJohn Wren Kennedy 	fds[0].fd = testfd;
338*d583b39bSJohn Wren Kennedy 	fds[0].events = POLLIN;
339*d583b39bSJohn Wren Kennedy 	fds[0].revents = 0;
340*d583b39bSJohn Wren Kennedy 
341*d583b39bSJohn Wren Kennedy 	ret = write(pollfd, fds, sizeof (pollfd_t));
342*d583b39bSJohn Wren Kennedy 
343*d583b39bSJohn Wren Kennedy 	if (ret != sizeof (pollfd_t)) {
344*d583b39bSJohn Wren Kennedy 		if (ret < 0) {
345*d583b39bSJohn Wren Kennedy 			test_failed(testName, "Failed to set fds: %s",
346*d583b39bSJohn Wren Kennedy 			    strerror(ret));
347*d583b39bSJohn Wren Kennedy 		}
348*d583b39bSJohn Wren Kennedy 
349*d583b39bSJohn Wren Kennedy 		test_failed(testName, "Failed to set fds: %d", ret);
350*d583b39bSJohn Wren Kennedy 	}
351*d583b39bSJohn Wren Kennedy 
352*d583b39bSJohn Wren Kennedy 	ret = dppoll(pollfd, fds, 5, timeout * 1000, &elapsed);
353*d583b39bSJohn Wren Kennedy 
354*d583b39bSJohn Wren Kennedy 	if (ret != 0) {
355*d583b39bSJohn Wren Kennedy 		test_failed(testName, "DP_POLL returns %d (expected 0)\n", ret);
356*d583b39bSJohn Wren Kennedy 	}
357*d583b39bSJohn Wren Kennedy 
358*d583b39bSJohn Wren Kennedy 	if (!check_time(elapsed, timeout)) {
359*d583b39bSJohn Wren Kennedy 		test_failed(testName, "took %d (expected %d)\n",
360*d583b39bSJohn Wren Kennedy 		    elapsed, timeout);
361*d583b39bSJohn Wren Kennedy 	}
362*d583b39bSJohn Wren Kennedy 
363*d583b39bSJohn Wren Kennedy 	clear_fd(testName, pollfd, testfd);
364*d583b39bSJohn Wren Kennedy 
365*d583b39bSJohn Wren Kennedy 	test_passed(testName);
366*d583b39bSJohn Wren Kennedy }
367*d583b39bSJohn Wren Kennedy 
368*d583b39bSJohn Wren Kennedy /* ARGSUSED */
369*d583b39bSJohn Wren Kennedy static void *
poll_thread(void * data)370*d583b39bSJohn Wren Kennedy poll_thread(void *data)
371*d583b39bSJohn Wren Kennedy {
372*d583b39bSJohn Wren Kennedy 	int	pollfd;
373*d583b39bSJohn Wren Kennedy 	int	testfd;
374*d583b39bSJohn Wren Kennedy 
375*d583b39bSJohn Wren Kennedy 	pollfd = open("/dev/poll", O_RDWR);
376*d583b39bSJohn Wren Kennedy 
377*d583b39bSJohn Wren Kennedy 	if (pollfd <  0) {
378*d583b39bSJohn Wren Kennedy 		perror("Failed to open /dev/poll: ");
379*d583b39bSJohn Wren Kennedy 		exit(-1);
380*d583b39bSJohn Wren Kennedy 	}
381*d583b39bSJohn Wren Kennedy 
382*d583b39bSJohn Wren Kennedy 	/*
383*d583b39bSJohn Wren Kennedy 	 * Create a dummy FD that will never have POLLIN set
384*d583b39bSJohn Wren Kennedy 	 */
385*d583b39bSJohn Wren Kennedy 	testfd = socket(PF_INET, SOCK_STREAM, 0);
386*d583b39bSJohn Wren Kennedy 
387*d583b39bSJohn Wren Kennedy 	poll_no_fd_test();
388*d583b39bSJohn Wren Kennedy 	poll_with_fds_test(testfd);
389*d583b39bSJohn Wren Kennedy 
390*d583b39bSJohn Wren Kennedy 	dev_poll_no_fd_test(pollfd);
391*d583b39bSJohn Wren Kennedy 	dev_poll_with_fds_test(pollfd, testfd);
392*d583b39bSJohn Wren Kennedy 
393*d583b39bSJohn Wren Kennedy 	(void) close(testfd);
394*d583b39bSJohn Wren Kennedy 	(void) close(pollfd);
395*d583b39bSJohn Wren Kennedy 
396*d583b39bSJohn Wren Kennedy 	pthread_exit(0);
397*d583b39bSJohn Wren Kennedy 	return (NULL);
398*d583b39bSJohn Wren Kennedy }
399*d583b39bSJohn Wren Kennedy 
400*d583b39bSJohn Wren Kennedy /*
401*d583b39bSJohn Wren Kennedy  * This function causes any threads blocked in cv_timedwait_sig_hires
402*d583b39bSJohn Wren Kennedy  * to wakeup, which allows us to test how dpioctl handles spurious
403*d583b39bSJohn Wren Kennedy  * wakeups.
404*d583b39bSJohn Wren Kennedy  */
405*d583b39bSJohn Wren Kennedy static void
trigger_wakeup(void)406*d583b39bSJohn Wren Kennedy trigger_wakeup(void)
407*d583b39bSJohn Wren Kennedy {
408*d583b39bSJohn Wren Kennedy 	pid_t   child;
409*d583b39bSJohn Wren Kennedy 
410*d583b39bSJohn Wren Kennedy 	/*
411*d583b39bSJohn Wren Kennedy 	 * Forking will force all of the threads to be woken up so
412*d583b39bSJohn Wren Kennedy 	 * they can be moved to a well known state.
413*d583b39bSJohn Wren Kennedy 	 */
414*d583b39bSJohn Wren Kennedy 	child = vfork();
415*d583b39bSJohn Wren Kennedy 
416*d583b39bSJohn Wren Kennedy 	if (child == -1) {
417*d583b39bSJohn Wren Kennedy 		perror("Fork failed: ");
418*d583b39bSJohn Wren Kennedy 		exit(-1);
419*d583b39bSJohn Wren Kennedy 	} else if (child == 0) {
420*d583b39bSJohn Wren Kennedy 		_exit(0);
421*d583b39bSJohn Wren Kennedy 	} else {
422*d583b39bSJohn Wren Kennedy 		pid_t   result = -1;
423*d583b39bSJohn Wren Kennedy 		int	status;
424*d583b39bSJohn Wren Kennedy 
425*d583b39bSJohn Wren Kennedy 		do {
426*d583b39bSJohn Wren Kennedy 			result = waitpid(child, &status, 0);
427*d583b39bSJohn Wren Kennedy 
428*d583b39bSJohn Wren Kennedy 			if (result == -1 && errno != EINTR) {
429*d583b39bSJohn Wren Kennedy 				(void) printf("Waitpid for %ld failed: %s\n",
430*d583b39bSJohn Wren Kennedy 				    child, strerror(errno));
431*d583b39bSJohn Wren Kennedy 				exit(-1);
432*d583b39bSJohn Wren Kennedy 			}
433*d583b39bSJohn Wren Kennedy 		} while (result != child);
434*d583b39bSJohn Wren Kennedy 
435*d583b39bSJohn Wren Kennedy 		if (status != 0) {
436*d583b39bSJohn Wren Kennedy 			(void) printf("Child pid %ld failed: %d\n",
437*d583b39bSJohn Wren Kennedy 			    child, status);
438*d583b39bSJohn Wren Kennedy 			exit(-1);
439*d583b39bSJohn Wren Kennedy 		}
440*d583b39bSJohn Wren Kennedy 	}
441*d583b39bSJohn Wren Kennedy }
442*d583b39bSJohn Wren Kennedy 
443*d583b39bSJohn Wren Kennedy /*
444*d583b39bSJohn Wren Kennedy  * This function changes the system time, which has the side
445*d583b39bSJohn Wren Kennedy  * effect of updating timechanged in the kernel.
446*d583b39bSJohn Wren Kennedy  */
447*d583b39bSJohn Wren Kennedy static void
change_date(void)448*d583b39bSJohn Wren Kennedy change_date(void)
449*d583b39bSJohn Wren Kennedy {
450*d583b39bSJohn Wren Kennedy 	int	ret;
451*d583b39bSJohn Wren Kennedy 	struct timeval  tp;
452*d583b39bSJohn Wren Kennedy 
453*d583b39bSJohn Wren Kennedy 	ret = gettimeofday(&tp, NULL);
454*d583b39bSJohn Wren Kennedy 	assert(ret == 0);
455*d583b39bSJohn Wren Kennedy 
456*d583b39bSJohn Wren Kennedy 	tp.tv_usec++;
457*d583b39bSJohn Wren Kennedy 	ret = settimeofday(&tp, NULL);
458*d583b39bSJohn Wren Kennedy 	assert(ret == 0);
459*d583b39bSJohn Wren Kennedy }
460*d583b39bSJohn Wren Kennedy 
461*d583b39bSJohn Wren Kennedy /*
462*d583b39bSJohn Wren Kennedy  * The helper thread runs in a loop changing the time and
463*d583b39bSJohn Wren Kennedy  * forcing wakeups every 2 seconds.
464*d583b39bSJohn Wren Kennedy  */
465*d583b39bSJohn Wren Kennedy /* ARGSUSED */
466*d583b39bSJohn Wren Kennedy static void *
helper_thread(void * data)467*d583b39bSJohn Wren Kennedy helper_thread(void *data)
468*d583b39bSJohn Wren Kennedy {
469*d583b39bSJohn Wren Kennedy 	int	exit;
470*d583b39bSJohn Wren Kennedy 	struct	timespec ts = {2, 0};
471*d583b39bSJohn Wren Kennedy 
472*d583b39bSJohn Wren Kennedy 	debug_log("Helper thread started ...\n");
473*d583b39bSJohn Wren Kennedy 
474*d583b39bSJohn Wren Kennedy 	/* CONSTCOND */
475*d583b39bSJohn Wren Kennedy 	while (1) {
476*d583b39bSJohn Wren Kennedy 		(void) pthread_mutex_lock(&exitLock);
477*d583b39bSJohn Wren Kennedy 		(void) pthread_cond_reltimedwait_np(&exitCond, &exitLock, &ts);
478*d583b39bSJohn Wren Kennedy 		exit = terminated;
479*d583b39bSJohn Wren Kennedy 		(void) pthread_mutex_unlock(&exitLock);
480*d583b39bSJohn Wren Kennedy 
481*d583b39bSJohn Wren Kennedy 		if (exit) {
482*d583b39bSJohn Wren Kennedy 			break;
483*d583b39bSJohn Wren Kennedy 		}
484*d583b39bSJohn Wren Kennedy 
485*d583b39bSJohn Wren Kennedy 		change_date();
486*d583b39bSJohn Wren Kennedy 		trigger_wakeup();
487*d583b39bSJohn Wren Kennedy 		debug_log("Time changed and force wakeup issued\n");
488*d583b39bSJohn Wren Kennedy 	}
489*d583b39bSJohn Wren Kennedy 
490*d583b39bSJohn Wren Kennedy 	debug_log("Helper thread exiting ...\n");
491*d583b39bSJohn Wren Kennedy 
492*d583b39bSJohn Wren Kennedy 	pthread_exit(0);
493*d583b39bSJohn Wren Kennedy 	return (NULL);
494*d583b39bSJohn Wren Kennedy }
495*d583b39bSJohn Wren Kennedy 
496*d583b39bSJohn Wren Kennedy static void
stop_threads(void)497*d583b39bSJohn Wren Kennedy stop_threads(void)
498*d583b39bSJohn Wren Kennedy {
499*d583b39bSJohn Wren Kennedy 	(void) pthread_mutex_lock(&exitLock);
500*d583b39bSJohn Wren Kennedy 	terminated = 1;
501*d583b39bSJohn Wren Kennedy 	(void) pthread_cond_broadcast(&exitCond);
502*d583b39bSJohn Wren Kennedy 	(void) pthread_mutex_unlock(&exitLock);
503*d583b39bSJohn Wren Kennedy }
504*d583b39bSJohn Wren Kennedy 
505*d583b39bSJohn Wren Kennedy static void
run_tests(void)506*d583b39bSJohn Wren Kennedy run_tests(void)
507*d583b39bSJohn Wren Kennedy {
508*d583b39bSJohn Wren Kennedy 	pthread_t	pollThread;
509*d583b39bSJohn Wren Kennedy 	pthread_t	helperThread;
510*d583b39bSJohn Wren Kennedy 	int		ret;
511*d583b39bSJohn Wren Kennedy 
512*d583b39bSJohn Wren Kennedy 	ret = pthread_create(&helperThread, NULL, helper_thread, NULL);
513*d583b39bSJohn Wren Kennedy 
514*d583b39bSJohn Wren Kennedy 	if (ret != 0) {
515*d583b39bSJohn Wren Kennedy 		(void) printf("Failed to create date thread: %s",
516*d583b39bSJohn Wren Kennedy 		    strerror(ret));
517*d583b39bSJohn Wren Kennedy 		exit(-1);
518*d583b39bSJohn Wren Kennedy 	}
519*d583b39bSJohn Wren Kennedy 
520*d583b39bSJohn Wren Kennedy 	ret = pthread_create(&pollThread, NULL, poll_thread, NULL);
521*d583b39bSJohn Wren Kennedy 
522*d583b39bSJohn Wren Kennedy 	if (ret != 0) {
523*d583b39bSJohn Wren Kennedy 		(void) printf("Failed to create poll thread: %s",
524*d583b39bSJohn Wren Kennedy 		    strerror(ret));
525*d583b39bSJohn Wren Kennedy 		exit(-1);
526*d583b39bSJohn Wren Kennedy 	}
527*d583b39bSJohn Wren Kennedy 
528*d583b39bSJohn Wren Kennedy 	(void) pthread_join(pollThread, NULL);
529*d583b39bSJohn Wren Kennedy 	stop_threads();
530*d583b39bSJohn Wren Kennedy 	(void) pthread_join(helperThread, NULL);
531*d583b39bSJohn Wren Kennedy }
532*d583b39bSJohn Wren Kennedy 
533*d583b39bSJohn Wren Kennedy int
main(int argc,char * const argv[])534*d583b39bSJohn Wren Kennedy main(int argc, char * const argv[])
535*d583b39bSJohn Wren Kennedy {
536*d583b39bSJohn Wren Kennedy 	int	c;
537*d583b39bSJohn Wren Kennedy 
538*d583b39bSJohn Wren Kennedy 	while ((c = getopt(argc, argv, "d")) != -1) {
539*d583b39bSJohn Wren Kennedy 		switch (c) {
540*d583b39bSJohn Wren Kennedy 		case 'd':
541*d583b39bSJohn Wren Kennedy 			debug = 1;
542*d583b39bSJohn Wren Kennedy 			break;
543*d583b39bSJohn Wren Kennedy 		default:
544*d583b39bSJohn Wren Kennedy 			break;
545*d583b39bSJohn Wren Kennedy 		}
546*d583b39bSJohn Wren Kennedy 	}
547*d583b39bSJohn Wren Kennedy 
548*d583b39bSJohn Wren Kennedy 	/*
549*d583b39bSJohn Wren Kennedy 	 * We need to be root to change the system time
550*d583b39bSJohn Wren Kennedy 	 */
551*d583b39bSJohn Wren Kennedy 	if (getuid() != 0 && geteuid() != 0) {
552*d583b39bSJohn Wren Kennedy 		(void) printf("%s must be run as root\n", argv[0]);
553*d583b39bSJohn Wren Kennedy 		exit(-1);
554*d583b39bSJohn Wren Kennedy 	}
555*d583b39bSJohn Wren Kennedy 
556*d583b39bSJohn Wren Kennedy 	run_tests();
557*d583b39bSJohn Wren Kennedy 
558*d583b39bSJohn Wren Kennedy 	exit(0);
559*d583b39bSJohn Wren Kennedy }
560