src/windows/native/sun/nio/ch/WindowsSelectorImpl.c
author asaha
Thu Mar 24 10:43:47 2011 -0700 (2 years ago)
changeset 506 bfc1a4516e20
parent 354ffa98eed5766
permissions -rw-r--r--
6213702: (so) non-blocking sockets with TCP urgent disabled get still selected for read ops (win)
Reviewed-by: alanb
        1 /*
        2  * Copyright (c) 2002, 2011, Oracle and/or its affiliates. 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.  Oracle designates this
        8  * particular file as subject to the "Classpath" exception as provided
        9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       22  * or visit www.oracle.com if you need additional information or have any
       23  * questions.
       24  */
       25 
       26 
       27 
       28 /* Maximum number of sockets per select() */
       29 /* This number should be equal to WindowsSelectorImpl.MAX_SELECTABLE_FDS */
       30 /* This definition MUST precede the inclusion of winsock2.h */
       31 
       32 #define FD_SETSIZE 1024
       33 
       34 #include <stdlib.h>
       35 #include "jvm.h"
       36 #include "jni.h"
       37 #include "jni_util.h"
       38 #include "sun_nio_ch_WindowsSelectorImpl.h"
       39 #include "winsock2.h"
       40 
       41 
       42 typedef struct {
       43     jint fd;
       44     jshort events;
       45 } pollfd;
       46 
       47 static int POLLIN   = 1;
       48 static int POLLCONN = 2;
       49 static int POLLOUT  = 4;
       50 
       51 #define WAKEUP_SOCKET_BUF_SIZE 16
       52 
       53 
       54 JNIEXPORT jint JNICALL
       55 Java_sun_nio_ch_WindowsSelectorImpl_00024SubSelector_poll0(JNIEnv *env, jobject this,
       56                                    jlong pollAddress, jint numfds,
       57                                    jintArray returnReadFds, jintArray returnWriteFds,
       58                                    jintArray returnExceptFds, jlong timeout)
       59 {
       60     DWORD result = 0;
       61     pollfd *fds = (pollfd *) pollAddress;
       62     int i;
       63     FD_SET readfds, writefds, exceptfds;
       64     struct timeval timevalue, *tv;
       65     static struct timeval zerotime = {0, 0};
       66     int read_count = 0, write_count = 0, except_count = 0;
       67 
       68 #ifdef _WIN64
       69     int resultbuf[FD_SETSIZE + 1];
       70 #endif
       71 
       72     if (timeout == 0) {
       73         tv = &zerotime;
       74     } else if (timeout < 0) {
       75         tv = NULL;
       76     } else {
       77         tv = &timevalue;
       78         tv->tv_sec =  (long)(timeout / 1000);
       79         tv->tv_usec = (long)((timeout % 1000) * 1000);
       80     }
       81 
       82     /* Set FD_SET structures required for select */
       83     for (i = 0; i < numfds; i++) {
       84         if (fds[i].events & POLLIN) {
       85            readfds.fd_array[read_count] = fds[i].fd;
       86            read_count++;
       87         }
       88         if (fds[i].events & (POLLOUT | POLLCONN)) {
       89            writefds.fd_array[write_count] = fds[i].fd;
       90            write_count++;
       91         }
       92         exceptfds.fd_array[except_count] = fds[i].fd;
       93         except_count++;
       94     }
       95 
       96     readfds.fd_count = read_count;
       97     writefds.fd_count = write_count;
       98     exceptfds.fd_count = except_count;
       99 
      100     /* Call select */
      101     if ((result = select(0 , &readfds, &writefds, &exceptfds, tv))
      102                                                              == SOCKET_ERROR) {
      103         /* Bad error - this should not happen frequently */
      104         /* Iterate over sockets and call select() on each separately */
      105         FD_SET errreadfds, errwritefds, errexceptfds;
      106         readfds.fd_count = 0;
      107         writefds.fd_count = 0;
      108         exceptfds.fd_count = 0;
      109         for (i = 0; i < numfds; i++) {
      110             /* prepare select structures for the i-th socket */
      111             errreadfds.fd_count = 0;
      112             errwritefds.fd_count = 0;
      113             if (fds[i].events & POLLIN) {
      114                errreadfds.fd_array[0] = fds[i].fd;
      115                errreadfds.fd_count = 1;
      116             }
      117             if (fds[i].events & (POLLOUT | POLLCONN)) {
      118                 errwritefds.fd_array[0] = fds[i].fd;
      119                 errwritefds.fd_count = 1;
      120             }
      121             errexceptfds.fd_array[0] = fds[i].fd;
      122             errexceptfds.fd_count = 1;
      123 
      124             /* call select on the i-th socket */
      125             if (select(0, &errreadfds, &errwritefds, &errexceptfds, &zerotime)
      126                                                              == SOCKET_ERROR) {
      127                 /* This socket causes an error. Add it to exceptfds set */
      128                 exceptfds.fd_array[exceptfds.fd_count] = fds[i].fd;
      129                 exceptfds.fd_count++;
      130             } else {
      131                 /* This socket does not cause an error. Process result */
      132                 if (errreadfds.fd_count == 1) {
      133                     readfds.fd_array[readfds.fd_count] = fds[i].fd;
      134                     readfds.fd_count++;
      135                 }
      136                 if (errwritefds.fd_count == 1) {
      137                     writefds.fd_array[writefds.fd_count] = fds[i].fd;
      138                     writefds.fd_count++;
      139                 }
      140                 if (errexceptfds.fd_count == 1) {
      141                     exceptfds.fd_array[exceptfds.fd_count] = fds[i].fd;
      142                     exceptfds.fd_count++;
      143                 }
      144             }
      145         }
      146     }
      147 
      148     /* Return selected sockets. */
      149     /* Each Java array consists of sockets count followed by sockets list */
      150 
      151 #ifdef _WIN64
      152     resultbuf[0] = readfds.fd_count;
      153     for (i = 0; i < (int)readfds.fd_count; i++) {
      154         resultbuf[i + 1] = (int)readfds.fd_array[i];
      155     }
      156     (*env)->SetIntArrayRegion(env, returnReadFds, 0,
      157                               readfds.fd_count + 1, resultbuf);
      158 
      159     resultbuf[0] = writefds.fd_count;
      160     for (i = 0; i < (int)writefds.fd_count; i++) {
      161         resultbuf[i + 1] = (int)writefds.fd_array[i];
      162     }
      163     (*env)->SetIntArrayRegion(env, returnWriteFds, 0,
      164                               writefds.fd_count + 1, resultbuf);
      165 
      166     resultbuf[0] = exceptfds.fd_count;
      167     for (i = 0; i < (int)exceptfds.fd_count; i++) {
      168         resultbuf[i + 1] = (int)exceptfds.fd_array[i];
      169     }
      170     (*env)->SetIntArrayRegion(env, returnExceptFds, 0,
      171                               exceptfds.fd_count + 1, resultbuf);
      172 #else
      173     (*env)->SetIntArrayRegion(env, returnReadFds, 0,
      174                               readfds.fd_count + 1, (jint *)&readfds);
      175 
      176     (*env)->SetIntArrayRegion(env, returnWriteFds, 0,
      177                               writefds.fd_count + 1, (jint *)&writefds);
      178     (*env)->SetIntArrayRegion(env, returnExceptFds, 0,
      179                               exceptfds.fd_count + 1, (jint *)&exceptfds);
      180 #endif
      181     return 0;
      182 }
      183 
      184 JNIEXPORT void JNICALL
      185 Java_sun_nio_ch_WindowsSelectorImpl_setWakeupSocket0(JNIEnv *env, jclass this,
      186                                                 jint scoutFd)
      187 {
      188     /* Write one byte into the pipe */
      189     send(scoutFd, (char*)&POLLIN, 1, 0);
      190 }
      191 
      192 JNIEXPORT void JNICALL
      193 Java_sun_nio_ch_WindowsSelectorImpl_resetWakeupSocket0(JNIEnv *env, jclass this,
      194                                                 jint scinFd)
      195 {
      196     char bytes[WAKEUP_SOCKET_BUF_SIZE];
      197     long bytesToRead;
      198 
      199     /* Drain socket */
      200     /* Find out how many bytes available for read */
      201     ioctlsocket (scinFd, FIONREAD, &bytesToRead);
      202     if (bytesToRead == 0) {
      203         return;
      204     }
      205     /* Prepare corresponding buffer if needed, and then read */
      206     if (bytesToRead > WAKEUP_SOCKET_BUF_SIZE) {
      207         char* buf = (char*)malloc(bytesToRead);
      208         recv(scinFd, buf, bytesToRead, 0);
      209         free(buf);
      210     } else {
      211         recv(scinFd, bytes, WAKEUP_SOCKET_BUF_SIZE, 0);
      212     }
      213 }
      214 
      215 JNIEXPORT jboolean JNICALL
      216 Java_sun_nio_ch_WindowsSelectorImpl_discardUrgentData(JNIEnv* env, jobject this,
      217                                                       jint s)
      218 {
      219     char data[8];
      220     jboolean discarded = JNI_FALSE;
      221     int n;
      222     do {
      223         n = recv(s, data, sizeof(data), MSG_OOB);
      224         if (n > 0) {
      225             discarded = JNI_TRUE;
      226         }
      227     } while (n > 0);
      228     return discarded;
      229 }
      230