J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 2002 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 | /* |
| 27 | */ |
| 28 | |
| 29 | /* Maximum number of sockets per select() */ |
| 30 | /* This number should be equal to WindowsSelectorImpl.MAX_SELECTABLE_FDS */ |
| 31 | /* This definition MUST precede the inclusion of winsock2.h */ |
| 32 | |
| 33 | #define FD_SETSIZE 1024 |
| 34 | |
| 35 | #include <stdlib.h> |
| 36 | #include "jvm.h" |
| 37 | #include "jni.h" |
| 38 | #include "jni_util.h" |
| 39 | #include "sun_nio_ch_WindowsSelectorImpl.h" |
| 40 | #include "winsock2.h" |
| 41 | |
| 42 | |
| 43 | typedef struct { |
| 44 | jint fd; |
| 45 | jshort events; |
| 46 | } pollfd; |
| 47 | |
| 48 | static int POLLIN = 1; |
| 49 | static int POLLCONN = 2; |
| 50 | static int POLLOUT = 4; |
| 51 | |
| 52 | #define WAKEUP_SOCKET_BUF_SIZE 16 |
| 53 | |
| 54 | |
| 55 | JNIEXPORT jint JNICALL |
| 56 | Java_sun_nio_ch_WindowsSelectorImpl_00024SubSelector_poll0(JNIEnv *env, jobject this, |
| 57 | jlong pollAddress, jint numfds, |
| 58 | jintArray returnReadFds, jintArray returnWriteFds, |
| 59 | jintArray returnExceptFds, jlong timeout) |
| 60 | { |
| 61 | DWORD result = 0; |
| 62 | pollfd *fds = (pollfd *) pollAddress; |
| 63 | int i; |
| 64 | FD_SET readfds, writefds, exceptfds; |
| 65 | struct timeval timevalue, *tv; |
| 66 | static struct timeval zerotime = {0, 0}; |
| 67 | int read_count = 0, write_count = 0, except_count = 0; |
| 68 | |
| 69 | #ifdef _WIN64 |
| 70 | int resultbuf[FD_SETSIZE + 1]; |
| 71 | #endif |
| 72 | |
| 73 | if (timeout == 0) { |
| 74 | tv = &zerotime; |
| 75 | } else if (timeout < 0) { |
| 76 | tv = NULL; |
| 77 | } else { |
| 78 | tv = &timevalue; |
| 79 | tv->tv_sec = (long)(timeout / 1000); |
| 80 | tv->tv_usec = (long)((timeout % 1000) * 1000); |
| 81 | } |
| 82 | |
| 83 | /* Set FD_SET structures required for select */ |
| 84 | for (i = 0; i < numfds; i++) { |
| 85 | if (fds[i].events & POLLIN) { |
| 86 | readfds.fd_array[read_count] = fds[i].fd; |
| 87 | read_count++; |
| 88 | } |
| 89 | if (fds[i].events & (POLLOUT | POLLCONN)) { |
| 90 | writefds.fd_array[write_count] = fds[i].fd; |
| 91 | write_count++; |
| 92 | } |
| 93 | exceptfds.fd_array[except_count] = fds[i].fd; |
| 94 | except_count++; |
| 95 | } |
| 96 | |
| 97 | readfds.fd_count = read_count; |
| 98 | writefds.fd_count = write_count; |
| 99 | exceptfds.fd_count = except_count; |
| 100 | |
| 101 | /* Call select */ |
| 102 | if ((result = select(0 , &readfds, &writefds, &exceptfds, tv)) |
| 103 | == SOCKET_ERROR) { |
| 104 | /* Bad error - this should not happen frequently */ |
| 105 | /* Iterate over sockets and call select() on each separately */ |
| 106 | FD_SET errreadfds, errwritefds, errexceptfds; |
| 107 | readfds.fd_count = 0; |
| 108 | writefds.fd_count = 0; |
| 109 | exceptfds.fd_count = 0; |
| 110 | for (i = 0; i < numfds; i++) { |
| 111 | /* prepare select structures for the i-th socket */ |
| 112 | errreadfds.fd_count = 0; |
| 113 | errwritefds.fd_count = 0; |
| 114 | if (fds[i].events & POLLIN) { |
| 115 | errreadfds.fd_array[0] = fds[i].fd; |
| 116 | errreadfds.fd_count = 1; |
| 117 | } |
| 118 | if (fds[i].events & (POLLOUT | POLLCONN)) { |
| 119 | errwritefds.fd_array[0] = fds[i].fd; |
| 120 | errwritefds.fd_count = 1; |
| 121 | } |
| 122 | errexceptfds.fd_array[0] = fds[i].fd; |
| 123 | errexceptfds.fd_count = 1; |
| 124 | |
| 125 | /* call select on the i-th socket */ |
| 126 | if (select(0, &errreadfds, &errwritefds, &errexceptfds, &zerotime) |
| 127 | == SOCKET_ERROR) { |
| 128 | /* This socket causes an error. Add it to exceptfds set */ |
| 129 | exceptfds.fd_array[exceptfds.fd_count] = fds[i].fd; |
| 130 | exceptfds.fd_count++; |
| 131 | } else { |
| 132 | /* This socket does not cause an error. Process result */ |
| 133 | if (errreadfds.fd_count == 1) { |
| 134 | readfds.fd_array[readfds.fd_count] = fds[i].fd; |
| 135 | readfds.fd_count++; |
| 136 | } |
| 137 | if (errwritefds.fd_count == 1) { |
| 138 | writefds.fd_array[writefds.fd_count] = fds[i].fd; |
| 139 | writefds.fd_count++; |
| 140 | } |
| 141 | if (errexceptfds.fd_count == 1) { |
| 142 | exceptfds.fd_array[exceptfds.fd_count] = fds[i].fd; |
| 143 | exceptfds.fd_count++; |
| 144 | } |
| 145 | } |
| 146 | } |
| 147 | } |
| 148 | |
| 149 | /* Return selected sockets. */ |
| 150 | /* Each Java array consists of sockets count followed by sockets list */ |
| 151 | |
| 152 | #ifdef _WIN64 |
| 153 | resultbuf[0] = readfds.fd_count; |
| 154 | for (i = 0; i < (int)readfds.fd_count; i++) { |
| 155 | resultbuf[i + 1] = (int)readfds.fd_array[i]; |
| 156 | } |
| 157 | (*env)->SetIntArrayRegion(env, returnReadFds, 0, |
| 158 | readfds.fd_count + 1, resultbuf); |
| 159 | |
| 160 | resultbuf[0] = writefds.fd_count; |
| 161 | for (i = 0; i < (int)writefds.fd_count; i++) { |
| 162 | resultbuf[i + 1] = (int)writefds.fd_array[i]; |
| 163 | } |
| 164 | (*env)->SetIntArrayRegion(env, returnWriteFds, 0, |
| 165 | writefds.fd_count + 1, resultbuf); |
| 166 | |
| 167 | resultbuf[0] = exceptfds.fd_count; |
| 168 | for (i = 0; i < (int)exceptfds.fd_count; i++) { |
| 169 | resultbuf[i + 1] = (int)exceptfds.fd_array[i]; |
| 170 | } |
| 171 | (*env)->SetIntArrayRegion(env, returnExceptFds, 0, |
| 172 | exceptfds.fd_count + 1, resultbuf); |
| 173 | #else |
| 174 | (*env)->SetIntArrayRegion(env, returnReadFds, 0, |
| 175 | readfds.fd_count + 1, (jint *)&readfds); |
| 176 | |
| 177 | (*env)->SetIntArrayRegion(env, returnWriteFds, 0, |
| 178 | writefds.fd_count + 1, (jint *)&writefds); |
| 179 | (*env)->SetIntArrayRegion(env, returnExceptFds, 0, |
| 180 | exceptfds.fd_count + 1, (jint *)&exceptfds); |
| 181 | #endif |
| 182 | return 0; |
| 183 | } |
| 184 | |
| 185 | JNIEXPORT void JNICALL |
| 186 | Java_sun_nio_ch_WindowsSelectorImpl_setWakeupSocket0(JNIEnv *env, jclass this, |
| 187 | jint scoutFd) |
| 188 | { |
| 189 | /* Write one byte into the pipe */ |
| 190 | send(scoutFd, (char*)&POLLIN, 1, 0); |
| 191 | } |
| 192 | |
| 193 | JNIEXPORT void JNICALL |
| 194 | Java_sun_nio_ch_WindowsSelectorImpl_resetWakeupSocket0(JNIEnv *env, jclass this, |
| 195 | jint scinFd) |
| 196 | { |
| 197 | char bytes[WAKEUP_SOCKET_BUF_SIZE]; |
| 198 | long bytesToRead; |
| 199 | |
| 200 | /* Drain socket */ |
| 201 | /* Find out how many bytes available for read */ |
| 202 | ioctlsocket (scinFd, FIONREAD, &bytesToRead); |
| 203 | if (bytesToRead == 0) { |
| 204 | return; |
| 205 | } |
| 206 | /* Prepare corresponding buffer if needed, and then read */ |
| 207 | if (bytesToRead > WAKEUP_SOCKET_BUF_SIZE) { |
| 208 | char* buf = (char*)malloc(bytesToRead); |
| 209 | recv(scinFd, buf, bytesToRead, 0); |
| 210 | free(buf); |
| 211 | } else { |
| 212 | recv(scinFd, bytes, WAKEUP_SOCKET_BUF_SIZE, 0); |
| 213 | } |
| 214 | } |