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