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