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