blob: 4927d68c2ecb1df79a1d7c49ca810e90c07f28d6 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
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
43typedef struct {
44 jint fd;
45 jshort events;
46} pollfd;
47
48static int POLLIN = 1;
49static int POLLCONN = 2;
50static int POLLOUT = 4;
51
52#define WAKEUP_SOCKET_BUF_SIZE 16
53
54
55JNIEXPORT jint JNICALL
56Java_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
185JNIEXPORT void JNICALL
186Java_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
193JNIEXPORT void JNICALL
194Java_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}