jdk/src/demo/solaris/jni/Poller/Poller.c
changeset 25859 3317bb8137f4
parent 23895 ede5bb2c36bf
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
       
     3  *
       
     4  * Redistribution and use in source and binary forms, with or without
       
     5  * modification, are permitted provided that the following conditions
       
     6  * are met:
       
     7  *
       
     8  *   - Redistributions of source code must retain the above copyright
       
     9  *     notice, this list of conditions and the following disclaimer.
       
    10  *
       
    11  *   - Redistributions in binary form must reproduce the above copyright
       
    12  *     notice, this list of conditions and the following disclaimer in the
       
    13  *     documentation and/or other materials provided with the distribution.
       
    14  *
       
    15  *   - Neither the name of Oracle nor the names of its
       
    16  *     contributors may be used to endorse or promote products derived
       
    17  *     from this software without specific prior written permission.
       
    18  *
       
    19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
       
    20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
       
    21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
       
    23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
       
    27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
       
    28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
       
    29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    30  */
       
    31 
       
    32 /*
       
    33  * This source code is provided to illustrate the usage of a given feature
       
    34  * or technique and has been deliberately simplified. Additional steps
       
    35  * required for a production-quality application, such as security checks,
       
    36  * input validation and proper error handling, might not be present in
       
    37  * this sample code.
       
    38  */
       
    39 
       
    40 
       
    41 /*
       
    42  **********************************************************************
       
    43  * Poller.c :
       
    44  * JNI code for use with Poller.java, principally to take advantage
       
    45  * of poll() or /dev/poll multiplexing.
       
    46  *
       
    47  * One will need Solaris 8 or Solaris 7 with adequate patches to take
       
    48  * advantage of the /dev/poll performance enhancements, though any
       
    49  * version of Solaris 7 will automatically use the kernel poll()
       
    50  * caching.  And poll() will function in 2.5.1 and 2.6 as well, but
       
    51  * will not perform well for large numbers of file descriptors.
       
    52  *
       
    53  * Several assumptions have been made to simplify this code :
       
    54  *  1> At most MAX_HANDLES (32) separate pollable entities are currently
       
    55  *     supported.
       
    56  *  2> Global synchronization from Java is assumed for all init, create
       
    57  *     and destroy routines.  Per Object (handle passed in) synchronization
       
    58  *     is required for all AddFd, RemoveFd, IsMember, and Wait routines.
       
    59  *  3> It is currently up to the user to handle waking up an
       
    60  *     existing nativeWait() call to do an addfd or removefd on
       
    61  *     that set...could implement that here with an extra pipe, or
       
    62  *     with a pair of loopback sockets in Poller.java or user code.
       
    63  *     In most cases interruption is not necessary for deletions,
       
    64  *     so long as deletions are queued up outside the Poller class
       
    65  *     and then executed the next time waitMultiple() returns.
       
    66  *  4> /dev/poll performance could be slightly improved by coalescing
       
    67  *     adds/removes so that a write() is only done before the ioctl
       
    68  *     (DP_POLL), but this complicates exception handling and sees
       
    69  *     only modest performance gains so wasn't done.
       
    70  *  5> /dev/poll does not report errors on attempts to remove non-
       
    71  *     extant fds, but a future bug fix to the /dev/poll device driver
       
    72  *     should solve this problem.
       
    73  *  6> Could add simpler code for pre-Solaris 7 releases which will
       
    74  *     perform slightly better on those OSs.  But again there
       
    75  *     are only modest gains to be had from these new code paths,
       
    76  *     so they've been omitted here.
       
    77  *
       
    78  * Compile "cc -G -o <dest_dir>/libpoller.so -I ${JAVA_HOME}/include " \
       
    79  * -I ${JAVA_HOME}/include/solaris Poller.c" and place the <dest_dir>
       
    80  * in your LD_LIBRARY_PATH
       
    81  *
       
    82  **********************************************************************
       
    83  */
       
    84 
       
    85 #include <stdio.h>
       
    86 #include <unistd.h>
       
    87 #include <errno.h>
       
    88 #include <poll.h>
       
    89 #include <malloc.h>
       
    90 #include <fcntl.h>
       
    91 
       
    92 
       
    93 /*
       
    94  * Remove "_NOT"s to turn on features
       
    95  * Append "_NOT" to turn off features.
       
    96  * Use of /dev/poll requires both the include file and kernel driver.
       
    97  */
       
    98 #define DEBUG_NOT
       
    99 #define DEVPOLL_NOT
       
   100 
       
   101 #ifdef DEVPOLL
       
   102 #include <sys/devpoll.h>
       
   103 #endif
       
   104 
       
   105 #include "Poller.h"
       
   106 
       
   107 #define MAX_HANDLES 32
       
   108 
       
   109 
       
   110 #ifdef DEBUG
       
   111 #define DBGMSG(x) printf x
       
   112 #define ASSERT(x) {if (!(x)) \
       
   113                    printf("assertion(%s) failed at line : %d\n",#x,__LINE__);}
       
   114 #define CHECK_HANDLE(x) check_handle(x)
       
   115 #else
       
   116 #define DBGMSG(x)
       
   117 #define ASSERT(x)
       
   118 #define CHECK_HANDLE(x)
       
   119 #endif
       
   120 
       
   121 /*
       
   122  * Globals ...protect all with a global synchronization object.
       
   123  */
       
   124 
       
   125 static int Current_handle = 0;
       
   126 static int Use_devpoll = 0;
       
   127 static int Max_index = 0;
       
   128 
       
   129 /*
       
   130  * Per Poller object data.
       
   131  * Must be synchronized on a per Poller object basis.
       
   132  */
       
   133 
       
   134 typedef struct ioevent {
       
   135   int inuse;
       
   136   int devpollfd;
       
   137   int last_index;
       
   138   int total_free;
       
   139   int left_events;
       
   140   int max_index;
       
   141   pollfd_t *pfd;
       
   142 } ioevent_t;
       
   143 
       
   144 static ioevent_t IOE_handles[MAX_HANDLES];
       
   145 
       
   146 /*
       
   147  * Exceptions to be thrown.
       
   148  * Note : assuming all illegal argument and NULL pointer checks
       
   149  *        have already been done by the Java calling methods.
       
   150  */
       
   151 static jint throwOutOfMemoryError(JNIEnv *env, const char * cause)
       
   152 {
       
   153   (*env)->ThrowNew(env, (*env)->FindClass(env,"java/lang/OutOfMemoryError"),
       
   154                    cause);
       
   155   return -1;
       
   156 }
       
   157 static jint throwInterruptedIOException(JNIEnv *env, const char * cause)
       
   158 {
       
   159   (*env)->ThrowNew(env,
       
   160                    (*env)->FindClass(env,"java/io/InterruptedIOException"),
       
   161                    cause);
       
   162   return -1;
       
   163 }
       
   164 static jint throwIllegalStateException(JNIEnv *env, const char * cause)
       
   165 {
       
   166   (*env)->ThrowNew(env,
       
   167                    (*env)->FindClass(env,"java/lang/IllegalStateException"),
       
   168                    cause);
       
   169   return -1;
       
   170 }
       
   171 
       
   172 #define MEMORY_EXCEPTION(str) throwOutOfMemoryError(env, "Poller:" str)
       
   173 #define STATE_EXCEPTION(str)  throwIllegalStateException(env, "Poller:" str)
       
   174 #define INTERRUPT_EXCEPTION(str) throwInterruptedIOException(env, \
       
   175                                                              "Poller:" str)
       
   176 jint addfd(JNIEnv *, ioevent_t *, jint, jshort);
       
   177 jint removefd(JNIEnv *, ioevent_t *, jint);
       
   178 
       
   179 /*
       
   180  * Class Poller
       
   181  * Method: nativeInit
       
   182  * Signature: ()I
       
   183  *
       
   184  * Only to be called once, right after this library is loaded,
       
   185  * so no need to deal with reentrancy here.
       
   186  * Could do as a pragma ini, but that isn't as portable.
       
   187  */
       
   188 JNIEXPORT jint JNICALL Java_Poller_nativeInit(JNIEnv *env, jclass cls)
       
   189 {
       
   190   int testdevpollfd;
       
   191   int i;
       
   192 
       
   193 #ifdef DEVPOLL
       
   194   /*
       
   195    * See if we can use this much faster method
       
   196    * Note : must have fix for BUGID # 4223353 or OS can crash!
       
   197    */
       
   198   testdevpollfd = open("/dev/poll",O_RDWR);
       
   199   if (testdevpollfd >= 0) {
       
   200     /*
       
   201      * If Solaris 7, we need a patch
       
   202      * Until we know what string to search for, we'll play it
       
   203      * safe and disable this for Solaris 7.
       
   204      */
       
   205 
       
   206     if (!strcmp(name.release,"5.7"))
       
   207       {
       
   208         Use_devpoll = 0;
       
   209       }
       
   210     else
       
   211       {
       
   212         Use_devpoll = 1;
       
   213       }
       
   214   }
       
   215 
       
   216   DBGMSG(("Use_devpoll=%d\n" ,Use_devpoll));
       
   217   close(testdevpollfd);
       
   218 #endif
       
   219 
       
   220   /*
       
   221    * For now, we optimize for Solaris 7 if /dev/poll isn't
       
   222    * available, as it is only a small % hit for Solaris < 7.
       
   223    * if ( (Use_devpoll == 0) && !strcmp(name.release,"5.6") )
       
   224    *      Use_sol7opt = 0;
       
   225    */
       
   226   Current_handle = 0;
       
   227   for (i = 0; i < MAX_HANDLES; i++) {
       
   228     IOE_handles[i].devpollfd = -1;
       
   229     IOE_handles[i].pfd = NULL;
       
   230   }
       
   231 
       
   232   /*
       
   233    * this tells me the max number of open filedescriptors
       
   234    */
       
   235   Max_index = sysconf(_SC_OPEN_MAX);
       
   236   if (Max_index < 0) {
       
   237     Max_index = 1024;
       
   238   }
       
   239 
       
   240   DBGMSG(("got sysconf(_SC_OPEN_MAX)=%d file desc\n",Max_index));
       
   241 
       
   242   return 0;
       
   243 }
       
   244 
       
   245 JNIEXPORT jint JNICALL Java_Poller_getNumCPUs(JNIEnv *env, jclass cls)
       
   246 {
       
   247   return sysconf(_SC_NPROCESSORS_ONLN);
       
   248 }
       
   249 
       
   250 /*
       
   251  * Class:     Poller
       
   252  * Method:    nativeCreatePoller
       
   253  * Signature: (I)I
       
   254  * Note : in the case where /dev/poll doesn't exist,
       
   255  *        using more than one poll array could hurt
       
   256  *        Solaris 7 performance due to kernel caching.
       
   257  */
       
   258 
       
   259 JNIEXPORT jint JNICALL Java_Poller_nativeCreatePoller
       
   260   (JNIEnv *env, jobject obj, jint maximum_fds)
       
   261 {
       
   262   int handle, retval, i;
       
   263   ioevent_t *ioeh;
       
   264 
       
   265   if (maximum_fds == -1) {
       
   266     maximum_fds = Max_index;
       
   267   }
       
   268   handle = Current_handle;
       
   269   if (Current_handle >= MAX_HANDLES) {
       
   270     for (i = 0; i < MAX_HANDLES; i++) {
       
   271       if (IOE_handles[i].inuse == 0) {
       
   272         handle = i;
       
   273         break;
       
   274       }
       
   275     }
       
   276     if (handle >= MAX_HANDLES) {
       
   277       return MEMORY_EXCEPTION("CreatePoller - MAX_HANDLES exceeded");
       
   278     }
       
   279   } else {
       
   280     Current_handle++;
       
   281   }
       
   282 
       
   283   ioeh = &IOE_handles[handle];
       
   284 
       
   285   ioeh->inuse      = 1;
       
   286 
       
   287   ioeh->last_index = 0;
       
   288   ioeh->total_free = 0;
       
   289   ioeh->left_events = 0;
       
   290   ioeh->max_index = maximum_fds;
       
   291 
       
   292   retval = handle;
       
   293   if (Use_devpoll) {
       
   294     ioeh->devpollfd = open("/dev/poll",O_RDWR);
       
   295     DBGMSG(("Opened /dev/poll, set devpollfd = %d\n",ioeh->devpollfd));
       
   296     if (ioeh->devpollfd < 0) {
       
   297       Current_handle--;
       
   298       return MEMORY_EXCEPTION("CreatePoller - can\'t open /dev/poll");
       
   299     }
       
   300   }
       
   301   ioeh->pfd = malloc(maximum_fds * sizeof(pollfd_t));
       
   302   if (ioeh->pfd == NULL) {
       
   303     Current_handle--;
       
   304     return MEMORY_EXCEPTION("CreatePoller - malloc failure");
       
   305   }
       
   306 
       
   307   return retval;
       
   308 }
       
   309 
       
   310 /*
       
   311  * Class:     Poller
       
   312  * Method:    nativeDestroyPoller
       
   313  * Signature: (I)V
       
   314  */
       
   315 JNIEXPORT void JNICALL Java_Poller_nativeDestroyPoller
       
   316   (JNIEnv *env, jobject obj, jint handle)
       
   317 {
       
   318 
       
   319   ioevent_t *ioeh;
       
   320 
       
   321   if (handle < 0 || handle >= MAX_HANDLES)
       
   322     {
       
   323       STATE_EXCEPTION("DestroyPoller - handle out of range");
       
   324       return;
       
   325     }
       
   326 
       
   327   ioeh = &IOE_handles[handle];
       
   328   ioeh->inuse = 0;
       
   329   if (Use_devpoll) {
       
   330     close(ioeh->devpollfd);
       
   331   }
       
   332   free(ioeh->pfd);
       
   333 }
       
   334 
       
   335 #ifdef DEBUG
       
   336 static void check_handle(ioevent_t *ioeh)
       
   337 {
       
   338   int i,used,unused;
       
   339 
       
   340   used=unused=0;
       
   341   for (i = 0; i < ioeh->last_index; i++)
       
   342     {
       
   343       if (ioeh->pfd[i].fd == -1)
       
   344         unused++;
       
   345       else
       
   346         used++;
       
   347     }
       
   348   if (unused != ioeh->total_free)
       
   349     printf("WARNING : found %d free, claimed %d.  Used : %d\n",
       
   350            unused, ioeh->total_free, used);
       
   351 }
       
   352 #endif
       
   353 
       
   354 /*
       
   355  * Class:     Poller
       
   356  * Method:    nativeAddFd
       
   357  * Signature: (IIS)I
       
   358  *
       
   359  * Currently doesn't check to make sure we aren't adding
       
   360  * an fd already added (no problem for /dev/poll...just
       
   361  * an array waster for poll()).
       
   362  */
       
   363 JNIEXPORT jint JNICALL Java_Poller_nativeAddFd
       
   364   (JNIEnv *env, jobject obj, jint handle, jint fd, jshort events)
       
   365 {
       
   366   int retval;
       
   367   ioevent_t *ioeh;
       
   368 
       
   369   if (handle < 0 || handle >= MAX_HANDLES)
       
   370     return STATE_EXCEPTION("AddFd - handle out of range");
       
   371 
       
   372   ioeh = &IOE_handles[handle];
       
   373 
       
   374   CHECK_HANDLE(ioeh);
       
   375 
       
   376   #ifdef DEVPOLL
       
   377   if (Use_devpoll)
       
   378     {
       
   379       int i;
       
   380       pollfd_t pollelt;
       
   381 
       
   382       /*
       
   383        * use /dev/poll
       
   384        */
       
   385       pollelt.fd = fd;
       
   386       pollelt.events = events;
       
   387       if ((i = write(ioeh->devpollfd, &pollelt, sizeof(pollfd_t))) !=
       
   388           sizeof(pollfd_t)) {
       
   389         DBGMSG(("write to devpollfd=%d showed %d bytes out of %d\n",
       
   390                 ioeh->devpollfd,i,sizeof(pollfd_t)));
       
   391         return STATE_EXCEPTION("AddFd - /dev/poll add failure");
       
   392       }
       
   393     else
       
   394       {
       
   395         retval = fd;
       
   396       }
       
   397     }
       
   398   else
       
   399   #endif
       
   400     { /* no /dev/poll available */
       
   401       retval = addfd(env, ioeh, fd, events);
       
   402     }
       
   403   return retval;
       
   404 }
       
   405 
       
   406 /*
       
   407  * Addfd to pollfd array...optimized for Solaris 7
       
   408  */
       
   409 jint addfd(JNIEnv *env, ioevent_t *ioeh, jint fd, jshort events)
       
   410 {
       
   411   int idx;
       
   412 
       
   413   if (ioeh->total_free)
       
   414     {
       
   415       /*
       
   416        * Traversing from end because that's where we pad.
       
   417        */
       
   418       ioeh->total_free--;
       
   419       for (idx = ioeh->last_index - 1; idx >= 0; idx--) {
       
   420         if (ioeh->pfd[idx].fd == -1)
       
   421           break;
       
   422       }
       
   423     }
       
   424   else if (ioeh->last_index >= ioeh->max_index)
       
   425     {
       
   426       return MEMORY_EXCEPTION("AddFd - too many fds");
       
   427     }
       
   428   else
       
   429     {
       
   430       int i;
       
   431       int new_total;
       
   432       /*
       
   433        * For Solaris 7, want to add some growth space
       
   434        * and fill extras with fd=-1.  This allows for
       
   435        * kernel poll() implementation to perform optimally.
       
   436        */
       
   437       new_total = ioeh->last_index;
       
   438       new_total += (new_total/10) + 1; /* bump size by 10% */
       
   439       if (new_total > ioeh->max_index)
       
   440         new_total = ioeh->max_index;
       
   441       for (i = ioeh->last_index; i <= new_total; i++)
       
   442         {
       
   443           ioeh->pfd[i].fd = -1;
       
   444         }
       
   445       idx = ioeh->last_index;
       
   446       ioeh->total_free = new_total - ioeh->last_index - 1;
       
   447       DBGMSG(("Just grew from %d to %d in size\n",
       
   448               ioeh->last_index, new_total));
       
   449       ioeh->last_index = new_total;
       
   450     }
       
   451   ASSERT((idx >= 0) && (idx <= ioeh->max_index));
       
   452   ASSERT(ioeh->pfd[idx].fd == -1);
       
   453   ioeh->pfd[idx].fd = fd;
       
   454   ioeh->pfd[idx].events = events;
       
   455   ioeh->pfd[idx].revents = 0;
       
   456 
       
   457   CHECK_HANDLE(ioeh);
       
   458 
       
   459   return fd;
       
   460 }
       
   461 
       
   462 /*
       
   463  * Class:     Poller
       
   464  * Method:    nativeRemoveFd
       
   465  * Signature: (II)I
       
   466  */
       
   467 JNIEXPORT jint JNICALL Java_Poller_nativeRemoveFd
       
   468   (JNIEnv *env, jobject obj, jint handle, jint fd)
       
   469 {
       
   470   ioevent_t *ioeh;
       
   471 
       
   472   if (handle < 0 || handle >= MAX_HANDLES)
       
   473     return STATE_EXCEPTION("RemoveFd - handle out of range");
       
   474 
       
   475   ioeh = &IOE_handles[handle];
       
   476 
       
   477   #ifdef DEVPOLL
       
   478   if (Use_devpoll)
       
   479     {
       
   480       /*
       
   481        * use /dev/poll - currently no need for locking here.
       
   482        */
       
   483       pollfd_t pollelt;
       
   484 
       
   485       pollelt.fd = fd;
       
   486       pollelt.events = POLLREMOVE;
       
   487       if (write(ioeh->devpollfd, &pollelt,
       
   488                 sizeof(pollfd_t) ) != sizeof(pollfd_t))
       
   489         {
       
   490           return STATE_EXCEPTION("RemoveFd - /dev/poll failure");
       
   491         }
       
   492     }
       
   493   else
       
   494   #endif DEVPOLL
       
   495     {
       
   496       return removefd(env, ioeh,fd);
       
   497     }
       
   498 }
       
   499 /*
       
   500  * remove from pollfd array...optimize for Solaris 7
       
   501  */
       
   502 jint removefd(JNIEnv *env, ioevent_t *ioeh, jint fd)
       
   503 {
       
   504   int i;
       
   505   int found = 0;
       
   506 
       
   507     { /* !Use_devpoll */
       
   508       for (i = 0; i < ioeh->last_index; i++)
       
   509         {
       
   510           if (ioeh->pfd[i].fd == fd)
       
   511             {
       
   512               ioeh->pfd[i].fd = -1;
       
   513               found = 1;
       
   514               break;
       
   515             }
       
   516         }
       
   517       if (!found)
       
   518         {
       
   519           return STATE_EXCEPTION("RemoveFd - no such fd");
       
   520         }
       
   521       ioeh->left_events = 0; /* Have to go back to the kernel */
       
   522       ioeh->total_free++;
       
   523       /*
       
   524        * Shrinking pool if > 33% empty. Just don't do this often!
       
   525        */
       
   526       if ( (ioeh->last_index > 100) &&
       
   527            (ioeh->total_free > (ioeh->last_index / 3)) )
       
   528         {
       
   529           int j;
       
   530           /*
       
   531            * we'll just bite the bullet here, since we're > 33% empty.
       
   532            * walk through and eliminate -1 fd values, shrink total
       
   533            * size to still have ~ 10 fd==-1 values at end.
       
   534            * Start at end (since we pad here) and, when we find fd != -1,
       
   535            * swap with an earlier fd == -1 until we have all -1 values
       
   536            * at the end.
       
   537            */
       
   538           CHECK_HANDLE(ioeh);
       
   539           for (i = ioeh->last_index - 1, j = 0; i > j; i--)
       
   540             {
       
   541               if (ioeh->pfd[i].fd != -1)
       
   542                 {
       
   543                   while ( (j < i) && (ioeh->pfd[j].fd != -1) )
       
   544                     j++;
       
   545                   DBGMSG( ("i=%d,j=%d,ioeh->pfd[j].fd=%d\n",
       
   546                            i, j, ioeh->pfd[j].fd) );
       
   547                   if (j < i)
       
   548                       {
       
   549                         ASSERT(ioeh->pfd[j].fd == -1);
       
   550                         ioeh->pfd[j].fd = ioeh->pfd[i].fd;
       
   551                         ioeh->pfd[j].events = ioeh->pfd[i].events;
       
   552                         ioeh->pfd[i].fd = -1;
       
   553                       }
       
   554                 }
       
   555             }
       
   556           DBGMSG(("Just shrunk from %d to %d in size\n",
       
   557                   ioeh->last_index, j+11));
       
   558           ioeh->last_index = j + 11; /* last_index always 1 greater */
       
   559           ioeh->total_free = 10;
       
   560           CHECK_HANDLE(ioeh);
       
   561         }
       
   562     } /* !Use_devpoll */
       
   563 
       
   564   return 1;
       
   565 }
       
   566 
       
   567 /*
       
   568  * Class:     Poller
       
   569  * Method:    nativeIsMember
       
   570  * Signature: (II)I
       
   571  */
       
   572 JNIEXPORT jint JNICALL Java_Poller_nativeIsMember
       
   573   (JNIEnv *env, jobject obj, jint handle, jint fd)
       
   574 {
       
   575   int found = 0;
       
   576   int i;
       
   577   ioevent_t *ioeh;
       
   578 
       
   579   if (handle < 0 || handle >= MAX_HANDLES)
       
   580     return STATE_EXCEPTION("IsMember - handle out of range");
       
   581 
       
   582   ioeh = &IOE_handles[handle];
       
   583 
       
   584   #ifdef DEVPOLL
       
   585   if (Use_devpoll)
       
   586     {
       
   587       pollfd_t pfd;
       
   588       /*
       
   589        * DEVPOLL ioctl DP_ISPOLLED call to determine if fd is polled.
       
   590        */
       
   591       pfd.fd = fd;
       
   592       pfd.events = 0;
       
   593       pfd.revents = 0;
       
   594       found = ioctl(ioeh->devpollfd, DP_ISPOLLED, &pfd);
       
   595       if (found == -1)
       
   596         {
       
   597           return STATE_EXCEPTION("IsMember - /dev/poll failure");
       
   598         }
       
   599     }
       
   600   else
       
   601   #endif
       
   602     {
       
   603       for (i = 0; i < ioeh->last_index; i++)
       
   604         {
       
   605           if (fd == ioeh->pfd[i].fd)
       
   606             {
       
   607               found = 1;
       
   608               break;
       
   609             }
       
   610         }
       
   611     }
       
   612 
       
   613   return found;
       
   614 }
       
   615 
       
   616 /*
       
   617  * Class:     Poller
       
   618  * Method:    nativeWait
       
   619  * Signature: (II[I[SJ)I
       
   620  */
       
   621 JNIEXPORT jint JNICALL Java_Poller_nativeWait
       
   622   (JNIEnv *env, jobject obj, jint handle, jint maxEvents,
       
   623    jintArray jfds, jshortArray jrevents, jlong timeout)
       
   624 {
       
   625   int useEvents, count, idx;
       
   626   short *reventp;
       
   627   jint  *fdp;
       
   628   int   retval;
       
   629   ioevent_t *ioeh;
       
   630   jboolean isCopy1,isCopy2;
       
   631 
       
   632   if (handle < 0 || handle >= MAX_HANDLES)
       
   633     return STATE_EXCEPTION("nativeWait - handle out of range");
       
   634 
       
   635   ioeh = &IOE_handles[handle];
       
   636 
       
   637   if (maxEvents == 0) /* just doing a kernel delay! */
       
   638     {
       
   639       useEvents = poll(NULL,0L,timeout);
       
   640       return 0;
       
   641     }
       
   642 
       
   643   #ifdef DEVPOLL
       
   644   if (Use_devpoll)
       
   645     {
       
   646       struct dvpoll dopoll;
       
   647       /*
       
   648        * DEVPOLL ioctl DP_POLL call, reading
       
   649        */
       
   650       dopoll.dp_timeout = timeout;
       
   651       dopoll.dp_nfds=maxEvents;
       
   652       dopoll.dp_fds=ioeh->pfd;
       
   653 
       
   654       useEvents = ioctl(ioeh->devpollfd, DP_POLL, &dopoll);
       
   655       while ((useEvents == -1) && (errno == EAGAIN))
       
   656             useEvents = ioctl(ioeh->devpollfd, DP_POLL, &dopoll);
       
   657 
       
   658       if (useEvents == -1)
       
   659         {
       
   660           if (errno == EINTR)
       
   661             return INTERRUPT_EXCEPTION("nativeWait - /dev/poll failure EINTR");
       
   662           else
       
   663             return STATE_EXCEPTION("nativeWait - /dev/poll failure");
       
   664         }
       
   665 
       
   666       reventp =(*env)->GetShortArrayElements(env,jrevents,&isCopy1);
       
   667       fdp =(*env)->GetIntArrayElements(env,jfds,&isCopy2);
       
   668       for (idx = 0,count = 0; idx < useEvents; idx++)
       
   669         {
       
   670           if (ioeh->pfd[idx].revents)
       
   671             {
       
   672               fdp[count] = ioeh->pfd[idx].fd;
       
   673               reventp[count] = ioeh->pfd[idx].revents;
       
   674               count++;
       
   675             }
       
   676         }
       
   677       if (count < useEvents)
       
   678         return STATE_EXCEPTION("Wait - Corrupted internals");
       
   679 
       
   680       if (isCopy1 == JNI_TRUE)
       
   681         (*env)->ReleaseShortArrayElements(env,jrevents,reventp,0);
       
   682       if (isCopy2 == JNI_TRUE)
       
   683         (*env)->ReleaseIntArrayElements(env,jfds,fdp,0);
       
   684     }
       
   685   else
       
   686   #endif
       
   687     { /* !Use_devpoll */
       
   688 
       
   689     /* no leftovers=>go to kernel */
       
   690       if (ioeh->left_events == 0)
       
   691         {
       
   692           useEvents = poll(ioeh->pfd,ioeh->last_index, timeout);
       
   693           while ((useEvents == -1) && (errno == EAGAIN))
       
   694             useEvents = poll(ioeh->pfd,ioeh->last_index, timeout);
       
   695           if (useEvents == -1)
       
   696             {
       
   697               if (errno == EINTR)
       
   698                 return INTERRUPT_EXCEPTION("Wait - poll() failure EINTR-" \
       
   699                                            "IO interrupted.");
       
   700               else if (errno == EINVAL)
       
   701                 return STATE_EXCEPTION("Wait - poll() failure EINVAL-" \
       
   702                                        "invalid args (is fdlim cur < max?)");
       
   703               else
       
   704                 return STATE_EXCEPTION("Wait - poll() failure");
       
   705             }
       
   706           ioeh->left_events = useEvents;
       
   707           DBGMSG(("waitnative : poll returns : %d\n",useEvents));
       
   708         }
       
   709       else
       
   710         {  /* left over from last call */
       
   711           useEvents = ioeh->left_events;
       
   712         }
       
   713 
       
   714       if (useEvents > maxEvents)
       
   715         {
       
   716           useEvents = maxEvents;
       
   717         }
       
   718 
       
   719       ioeh->left_events -= useEvents; /* left to process */
       
   720 
       
   721       DBGMSG(("waitnative : left %d, use %d, max %d\n",ioeh->left_events,
       
   722               useEvents,maxEvents));
       
   723 
       
   724       if (useEvents > 0)
       
   725         {
       
   726           reventp =(*env)->GetShortArrayElements(env,jrevents,&isCopy1);
       
   727           fdp =(*env)->GetIntArrayElements(env,jfds,&isCopy2);
       
   728           for (idx = 0,count = 0; (idx < ioeh->last_index) &&
       
   729                  (count < useEvents); idx++)
       
   730             {
       
   731               if (ioeh->pfd[idx].revents)
       
   732                 {
       
   733                   fdp[count] = ioeh->pfd[idx].fd;
       
   734                   reventp[count] = ioeh->pfd[idx].revents;
       
   735                   /* in case of leftover for next walk */
       
   736                   ioeh->pfd[idx].revents = 0;
       
   737                   count++;
       
   738                 }
       
   739             }
       
   740           if (count < useEvents)
       
   741             {
       
   742               ioeh->left_events = 0;
       
   743               return STATE_EXCEPTION("Wait - Corrupted internals");
       
   744             }
       
   745           if (isCopy1 == JNI_TRUE)
       
   746             (*env)->ReleaseShortArrayElements(env,jrevents,reventp,0);
       
   747           if (isCopy2 == JNI_TRUE)
       
   748             (*env)->ReleaseIntArrayElements(env,jfds,fdp,0);
       
   749         }
       
   750     } /* !Use_devpoll */
       
   751 
       
   752   return useEvents;
       
   753 }