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 "java_lang_Integer.h" 32 #include <sys/poll.h> 33 #include <sys/resource.h> 34 #include <unistd.h> 35 #include <sys/time.h> 36 37 #ifdef __cplusplus 38 extern "C" { 39 #endif 40 41 typedef uint32_t caddr32_t; 42 43 /* /dev/poll ioctl */ 44 #define DPIOC (0xD0 << 8) 45 #define DP_POLL (DPIOC | 1) /* poll on fds in cached in /dev/poll */ 46 #define DP_ISPOLLED (DPIOC | 2) /* is this fd cached in /dev/poll */ 47 #define DEVPOLLSIZE 1000 /* /dev/poll table size increment */ 48 #define POLLREMOVE 0x0800 /* Removes fd from monitored set */ 49 50 /* 51 * /dev/poll DP_POLL ioctl format 52 */ 53 typedef struct dvpoll { 54 pollfd_t *dp_fds; /* pollfd array */ 55 nfds_t dp_nfds; /* num of pollfd's in dp_fds[] */ 56 int dp_timeout; /* time out in millisec */ 57 } dvpoll_t; 58 59 typedef struct dvpoll32 { 60 caddr32_t dp_fds; /* pollfd array */ 61 uint32_t dp_nfds; /* num of pollfd's in dp_fds[] */ 62 int32_t dp_timeout; /* time out in millisec */ 63 } dvpoll32_t; 64 65 #ifdef __cplusplus 66 } 67 #endif 68 69 #define RESTARTABLE(_cmd, _result) do { \ 70 do { \ 71 _result = _cmd; \ 72 } while((_result == -1) && (errno == EINTR)); \ 73 } while(0) 74 75 static int 76 idevpoll(jint wfd, int dpctl, struct dvpoll a) 77 { 78 jlong start, now; 79 int remaining = a.dp_timeout; 80 struct timeval t; 81 int diff; 82 83 gettimeofday(&t, NULL); 84 start = t.tv_sec * 1000 + t.tv_usec / 1000; 85 86 for (;;) { 87 /* poll(7d) ioctl does not return remaining count */ 88 int res = ioctl(wfd, dpctl, &a); 89 if (res < 0 && errno == EINTR) { 90 if (remaining >= 0) { 91 gettimeofday(&t, NULL); 92 now = t.tv_sec * 1000 + t.tv_usec / 1000; 93 diff = now - start; 94 remaining -= diff; 95 if (diff < 0 || remaining <= 0) { 96 return 0; 97 } 98 start = now; 99 } 100 } else { 101 return res; 102 } 103 } 104 } 105 106 JNIEXPORT jint JNICALL 107 Java_sun_nio_ch_DevPollArrayWrapper_init(JNIEnv *env, jobject this) 108 { 109 int wfd = open("/dev/poll", O_RDWR); 110 if (wfd < 0) { 111 JNU_ThrowIOExceptionWithLastError(env, "Error opening driver"); 112 return -1; 113 } 114 return wfd; 115 } 116 117 JNIEXPORT void JNICALL 118 Java_sun_nio_ch_DevPollArrayWrapper_register(JNIEnv *env, jobject this, 119 jint wfd, jint fd, jint mask) 120 { 121 struct pollfd a[2]; 122 unsigned char *pollBytes = (unsigned char *)&a[0]; 123 unsigned char *pollEnd = pollBytes + sizeof(struct pollfd) * 2; 124 125 /* We clear it first, otherwise any entries between poll invocations 126 get OR'd together */ 127 a[0].fd = fd; 128 a[0].events = POLLREMOVE; 129 a[0].revents = 0; 130 131 a[1].fd = fd; 132 a[1].events = mask; 133 a[1].revents = 0; 134 135 while (pollBytes < pollEnd) { 136 int bytesWritten = write(wfd, pollBytes, (int)(pollEnd - pollBytes)); 137 if (bytesWritten < 0) { 138 JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds"); 139 return; 140 } 141 pollBytes += bytesWritten; 142 } 143 } 144 145 JNIEXPORT void JNICALL 146 Java_sun_nio_ch_DevPollArrayWrapper_registerMultiple(JNIEnv *env, jobject this, 147 jint wfd, jlong address, 148 jint len) 149 { 150 unsigned char *pollBytes = (unsigned char *)jlong_to_ptr(address); 151 unsigned char *pollEnd = pollBytes + sizeof(struct pollfd) * len; 152 while (pollBytes < pollEnd) { 153 int bytesWritten = write(wfd, pollBytes, (int)(pollEnd - pollBytes)); 154 if (bytesWritten < 0) { 155 JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds"); 156 return; 157 } 158 pollBytes += bytesWritten; 159 } 160 } 161 162 JNIEXPORT jint JNICALL 163 Java_sun_nio_ch_DevPollArrayWrapper_poll0(JNIEnv *env, jobject this, 164 jlong address, jint numfds, 165 jlong timeout, jint wfd) 166 { 167 struct dvpoll a; 168 void *pfd = (void *) jlong_to_ptr(address); 169 int result = 0; 170 171 a.dp_fds = pfd; 172 a.dp_nfds = numfds; 173 a.dp_timeout = (int)timeout; 174 175 if (timeout <= 0) { /* Indefinite or no wait */ 176 RESTARTABLE (ioctl(wfd, DP_POLL, &a), result); 177 } else { /* Bounded wait; bounded restarts */ 178 result = idevpoll(wfd, DP_POLL, a); 179 } 180 181 if (result < 0) { 182 JNU_ThrowIOExceptionWithLastError(env, "Error reading driver"); 183 return -1; 184 } 185 return result; 186 } 187 188 JNIEXPORT jint JNICALL 189 Java_sun_nio_ch_DevPollArrayWrapper_fdLimit(JNIEnv *env, jclass this) 190 { 191 struct rlimit rlp; 192 if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) { 193 JNU_ThrowIOExceptionWithLastError(env, 194 "getrlimit failed"); 195 } 196 if (rlp.rlim_max < 0 || rlp.rlim_max > java_lang_Integer_MAX_VALUE) { 197 return java_lang_Integer_MAX_VALUE; 198 } else { 199 return (jint)rlp.rlim_max; 200 } 201 } 202 203 JNIEXPORT void JNICALL 204 Java_sun_nio_ch_DevPollArrayWrapper_interrupt(JNIEnv *env, jclass this, jint fd) 205 { 206 int fakebuf[1]; 207 fakebuf[0] = 1; 208 if (write(fd, fakebuf, 1) < 0) { 209 JNU_ThrowIOExceptionWithLastError(env, 210 "Write to interrupt fd failed"); 211 } 212 }