annotate src/solaris/native/sun/nio/ch/DevPollArrayWrapper.c @ 11693:00936f2a3f2f

8153192: (se) Selector.select(long) uses wrong timeout after EINTR (lnx) Summary: Pass what remains of the initial timeout to epoll_wait(2) (Linux) and ioctl(7d) (Solaris) instead of the original un-decremented timeout value. Reviewed-by: alanb, rriggs
author bpb
date Wed, 04 May 2016 08:04:22 -0700
parents cea72c2bf071
children
rev   line source
duke@0 1 /*
bpb@11693 2 * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
duke@0 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@0 4 *
duke@0 5 * This code is free software; you can redistribute it and/or modify it
duke@0 6 * under the terms of the GNU General Public License version 2 only, as
ohair@2362 7 * published by the Free Software Foundation. Oracle designates this
duke@0 8 * particular file as subject to the "Classpath" exception as provided
ohair@2362 9 * by Oracle in the LICENSE file that accompanied this code.
duke@0 10 *
duke@0 11 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@0 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@0 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@0 14 * version 2 for more details (a copy is included in the LICENSE file that
duke@0 15 * accompanied this code).
duke@0 16 *
duke@0 17 * You should have received a copy of the GNU General Public License version
duke@0 18 * 2 along with this work; if not, write to the Free Software Foundation,
duke@0 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@0 20 *
ohair@2362 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@2362 22 * or visit www.oracle.com if you need additional information or have any
ohair@2362 23 * questions.
duke@0 24 */
duke@0 25
duke@0 26 #include "jni.h"
duke@0 27 #include "jni_util.h"
duke@0 28 #include "jvm.h"
duke@0 29 #include "jlong.h"
duke@0 30 #include "sun_nio_ch_DevPollArrayWrapper.h"
duke@0 31 #include <sys/poll.h>
duke@0 32 #include <unistd.h>
duke@0 33 #include <sys/time.h>
duke@0 34
duke@0 35 #ifdef __cplusplus
duke@0 36 extern "C" {
duke@0 37 #endif
duke@0 38
duke@0 39 typedef uint32_t caddr32_t;
duke@0 40
duke@0 41 /* /dev/poll ioctl */
duke@0 42 #define DPIOC (0xD0 << 8)
duke@0 43 #define DP_POLL (DPIOC | 1) /* poll on fds in cached in /dev/poll */
duke@0 44 #define DP_ISPOLLED (DPIOC | 2) /* is this fd cached in /dev/poll */
duke@0 45 #define DEVPOLLSIZE 1000 /* /dev/poll table size increment */
duke@0 46 #define POLLREMOVE 0x0800 /* Removes fd from monitored set */
duke@0 47
duke@0 48 /*
duke@0 49 * /dev/poll DP_POLL ioctl format
duke@0 50 */
duke@0 51 typedef struct dvpoll {
duke@0 52 pollfd_t *dp_fds; /* pollfd array */
duke@0 53 nfds_t dp_nfds; /* num of pollfd's in dp_fds[] */
duke@0 54 int dp_timeout; /* time out in millisec */
duke@0 55 } dvpoll_t;
duke@0 56
duke@0 57 typedef struct dvpoll32 {
duke@0 58 caddr32_t dp_fds; /* pollfd array */
duke@0 59 uint32_t dp_nfds; /* num of pollfd's in dp_fds[] */
duke@0 60 int32_t dp_timeout; /* time out in millisec */
duke@0 61 } dvpoll32_t;
duke@0 62
duke@0 63 #ifdef __cplusplus
duke@0 64 }
duke@0 65 #endif
duke@0 66
duke@0 67 #define RESTARTABLE(_cmd, _result) do { \
duke@0 68 do { \
duke@0 69 _result = _cmd; \
duke@0 70 } while((_result == -1) && (errno == EINTR)); \
duke@0 71 } while(0)
duke@0 72
duke@0 73 static int
duke@0 74 idevpoll(jint wfd, int dpctl, struct dvpoll a)
duke@0 75 {
duke@0 76 jlong start, now;
duke@0 77 int remaining = a.dp_timeout;
duke@0 78 struct timeval t;
duke@0 79 int diff;
duke@0 80
duke@0 81 gettimeofday(&t, NULL);
duke@0 82 start = t.tv_sec * 1000 + t.tv_usec / 1000;
duke@0 83
duke@0 84 for (;;) {
duke@0 85 /* poll(7d) ioctl does not return remaining count */
duke@0 86 int res = ioctl(wfd, dpctl, &a);
duke@0 87 if (res < 0 && errno == EINTR) {
duke@0 88 if (remaining >= 0) {
duke@0 89 gettimeofday(&t, NULL);
duke@0 90 now = t.tv_sec * 1000 + t.tv_usec / 1000;
duke@0 91 diff = now - start;
duke@0 92 remaining -= diff;
duke@0 93 if (diff < 0 || remaining <= 0) {
duke@0 94 return 0;
duke@0 95 }
duke@0 96 start = now;
bpb@11693 97 a.dp_timeout = remaining;
duke@0 98 }
duke@0 99 } else {
duke@0 100 return res;
duke@0 101 }
duke@0 102 }
duke@0 103 }
duke@0 104
duke@0 105 JNIEXPORT jint JNICALL
duke@0 106 Java_sun_nio_ch_DevPollArrayWrapper_init(JNIEnv *env, jobject this)
duke@0 107 {
duke@0 108 int wfd = open("/dev/poll", O_RDWR);
duke@0 109 if (wfd < 0) {
duke@0 110 JNU_ThrowIOExceptionWithLastError(env, "Error opening driver");
duke@0 111 return -1;
duke@0 112 }
duke@0 113 return wfd;
duke@0 114 }
duke@0 115
duke@0 116 JNIEXPORT void JNICALL
duke@0 117 Java_sun_nio_ch_DevPollArrayWrapper_register(JNIEnv *env, jobject this,
duke@0 118 jint wfd, jint fd, jint mask)
duke@0 119 {
alanb@5459 120 struct pollfd a[1];
alanb@5459 121 int n;
duke@0 122
duke@0 123 a[0].fd = fd;
alanb@5459 124 a[0].events = mask;
duke@0 125 a[0].revents = 0;
duke@0 126
alanb@5459 127 n = write(wfd, &a[0], sizeof(a));
alanb@5459 128 if (n != sizeof(a)) {
alanb@5459 129 if (n < 0) {
duke@0 130 JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds");
alanb@5459 131 } else {
alanb@5459 132 JNU_ThrowIOException(env, "Unexpected number of bytes written");
duke@0 133 }
duke@0 134 }
duke@0 135 }
duke@0 136
duke@0 137 JNIEXPORT void JNICALL
duke@0 138 Java_sun_nio_ch_DevPollArrayWrapper_registerMultiple(JNIEnv *env, jobject this,
duke@0 139 jint wfd, jlong address,
duke@0 140 jint len)
duke@0 141 {
duke@0 142 unsigned char *pollBytes = (unsigned char *)jlong_to_ptr(address);
duke@0 143 unsigned char *pollEnd = pollBytes + sizeof(struct pollfd) * len;
duke@0 144 while (pollBytes < pollEnd) {
duke@0 145 int bytesWritten = write(wfd, pollBytes, (int)(pollEnd - pollBytes));
duke@0 146 if (bytesWritten < 0) {
duke@0 147 JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds");
duke@0 148 return;
duke@0 149 }
duke@0 150 pollBytes += bytesWritten;
duke@0 151 }
duke@0 152 }
duke@0 153
duke@0 154 JNIEXPORT jint JNICALL
duke@0 155 Java_sun_nio_ch_DevPollArrayWrapper_poll0(JNIEnv *env, jobject this,
duke@0 156 jlong address, jint numfds,
duke@0 157 jlong timeout, jint wfd)
duke@0 158 {
duke@0 159 struct dvpoll a;
duke@0 160 void *pfd = (void *) jlong_to_ptr(address);
duke@0 161 int result = 0;
duke@0 162
duke@0 163 a.dp_fds = pfd;
duke@0 164 a.dp_nfds = numfds;
duke@0 165 a.dp_timeout = (int)timeout;
duke@0 166
duke@0 167 if (timeout <= 0) { /* Indefinite or no wait */
duke@0 168 RESTARTABLE (ioctl(wfd, DP_POLL, &a), result);
duke@0 169 } else { /* Bounded wait; bounded restarts */
duke@0 170 result = idevpoll(wfd, DP_POLL, a);
duke@0 171 }
duke@0 172
duke@0 173 if (result < 0) {
duke@0 174 JNU_ThrowIOExceptionWithLastError(env, "Error reading driver");
duke@0 175 return -1;
duke@0 176 }
duke@0 177 return result;
duke@0 178 }
duke@0 179
duke@0 180 JNIEXPORT void JNICALL
duke@0 181 Java_sun_nio_ch_DevPollArrayWrapper_interrupt(JNIEnv *env, jclass this, jint fd)
duke@0 182 {
duke@0 183 int fakebuf[1];
duke@0 184 fakebuf[0] = 1;
duke@0 185 if (write(fd, fakebuf, 1) < 0) {
duke@0 186 JNU_ThrowIOExceptionWithLastError(env,
duke@0 187 "Write to interrupt fd failed");
duke@0 188 }
duke@0 189 }