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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 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 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 * 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 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 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 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