home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / JBuilder8.iso / Solaris / resource / jre / demo / jni / Poller / Poller.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-09-06  |  17.7 KB  |  722 lines

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