| /* |
| * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * - Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * - Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * - Neither the name of Oracle nor the names of its |
| * contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
| * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| /* |
| * This source code is provided to illustrate the usage of a given feature |
| * or technique and has been deliberately simplified. Additional steps |
| * required for a production-quality application, such as security checks, |
| * input validation and proper error handling, might not be present in |
| * this sample code. |
| */ |
| |
| |
| /* |
| ********************************************************************** |
| * Poller.c : |
| * JNI code for use with Poller.java, principally to take advantage |
| * of poll() or /dev/poll multiplexing. |
| * |
| * One will need Solaris 8 or Solaris 7 with adequate patches to take |
| * advantage of the /dev/poll performance enhancements, though any |
| * version of Solaris 7 will automatically use the kernel poll() |
| * caching. And poll() will function in 2.5.1 and 2.6 as well, but |
| * will not perform well for large numbers of file descriptors. |
| * |
| * Several assumptions have been made to simplify this code : |
| * 1> At most MAX_HANDLES (32) separate pollable entities are currently |
| * supported. |
| * 2> Global synchronization from Java is assumed for all init, create |
| * and destroy routines. Per Object (handle passed in) synchronization |
| * is required for all AddFd, RemoveFd, IsMember, and Wait routines. |
| * 3> It is currently up to the user to handle waking up an |
| * existing nativeWait() call to do an addfd or removefd on |
| * that set...could implement that here with an extra pipe, or |
| * with a pair of loopback sockets in Poller.java or user code. |
| * In most cases interruption is not necessary for deletions, |
| * so long as deletions are queued up outside the Poller class |
| * and then executed the next time waitMultiple() returns. |
| * 4> /dev/poll performance could be slightly improved by coalescing |
| * adds/removes so that a write() is only done before the ioctl |
| * (DP_POLL), but this complicates exception handling and sees |
| * only modest performance gains so wasn't done. |
| * 5> /dev/poll does not report errors on attempts to remove non- |
| * extant fds, but a future bug fix to the /dev/poll device driver |
| * should solve this problem. |
| * 6> Could add simpler code for pre-Solaris 7 releases which will |
| * perform slightly better on those OSs. But again there |
| * are only modest gains to be had from these new code paths, |
| * so they've been omitted here. |
| * |
| * Compile "cc -G -o <dest_dir>/libpoller.so -I ${JAVA_HOME}/include " \ |
| * -I ${JAVA_HOME}/include/solaris Poller.c" and place the <dest_dir> |
| * in your LD_LIBRARY_PATH |
| * |
| ********************************************************************** |
| */ |
| |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <poll.h> |
| #include <malloc.h> |
| #include <fcntl.h> |
| |
| |
| /* |
| * Remove "_NOT"s to turn on features |
| * Append "_NOT" to turn off features. |
| * Use of /dev/poll requires both the include file and kernel driver. |
| */ |
| #define DEBUG_NOT |
| #define DEVPOLL_NOT |
| |
| #ifdef DEVPOLL |
| #include <sys/devpoll.h> |
| #endif |
| |
| #include "Poller.h" |
| |
| #define MAX_HANDLES 32 |
| |
| |
| #ifdef DEBUG |
| #define DBGMSG(x) printf x |
| #define ASSERT(x) {if (!(x)) \ |
| printf("assertion(%s) failed at line : %d\n",#x,__LINE__);} |
| #define CHECK_HANDLE(x) check_handle(x) |
| #else |
| #define DBGMSG(x) |
| #define ASSERT(x) |
| #define CHECK_HANDLE(x) |
| #endif |
| |
| /* |
| * Globals ...protect all with a global synchronization object. |
| */ |
| |
| static int Current_handle = 0; |
| static int Use_devpoll = 0; |
| static int Max_index = 0; |
| |
| /* |
| * Per Poller object data. |
| * Must be synchronized on a per Poller object basis. |
| */ |
| |
| typedef struct ioevent { |
| int inuse; |
| int devpollfd; |
| int last_index; |
| int total_free; |
| int left_events; |
| int max_index; |
| pollfd_t *pfd; |
| } ioevent_t; |
| |
| static ioevent_t IOE_handles[MAX_HANDLES]; |
| |
| /* |
| * Exceptions to be thrown. |
| * Note : assuming all illegal argument and NULL pointer checks |
| * have already been done by the Java calling methods. |
| */ |
| static jint throwOutOfMemoryError(JNIEnv *env, const char * cause) |
| { |
| (*env)->ThrowNew(env, (*env)->FindClass(env,"java/lang/OutOfMemoryError"), |
| cause); |
| return -1; |
| } |
| static jint throwInterruptedIOException(JNIEnv *env, const char * cause) |
| { |
| (*env)->ThrowNew(env, |
| (*env)->FindClass(env,"java/io/InterruptedIOException"), |
| cause); |
| return -1; |
| } |
| static jint throwIllegalStateException(JNIEnv *env, const char * cause) |
| { |
| (*env)->ThrowNew(env, |
| (*env)->FindClass(env,"java/lang/IllegalStateException"), |
| cause); |
| return -1; |
| } |
| |
| #define MEMORY_EXCEPTION(str) throwOutOfMemoryError(env, "Poller:" str) |
| #define STATE_EXCEPTION(str) throwIllegalStateException(env, "Poller:" str) |
| #define INTERRUPT_EXCEPTION(str) throwInterruptedIOException(env, \ |
| "Poller:" str) |
| jint addfd(JNIEnv *, ioevent_t *, jint, jshort); |
| jint removefd(JNIEnv *, ioevent_t *, jint); |
| |
| /* |
| * Class Poller |
| * Method: nativeInit |
| * Signature: ()I |
| * |
| * Only to be called once, right after this library is loaded, |
| * so no need to deal with reentrancy here. |
| * Could do as a pragma ini, but that isn't as portable. |
| */ |
| JNIEXPORT jint JNICALL Java_Poller_nativeInit(JNIEnv *env, jclass cls) |
| { |
| int testdevpollfd; |
| int i; |
| |
| #ifdef DEVPOLL |
| /* |
| * See if we can use this much faster method |
| * Note : must have fix for BUGID # 4223353 or OS can crash! |
| */ |
| testdevpollfd = open("/dev/poll",O_RDWR); |
| if (testdevpollfd >= 0) { |
| /* |
| * If Solaris 7, we need a patch |
| * Until we know what string to search for, we'll play it |
| * safe and disable this for Solaris 7. |
| */ |
| |
| if (!strcmp(name.release,"5.7")) |
| { |
| Use_devpoll = 0; |
| } |
| else |
| { |
| Use_devpoll = 1; |
| } |
| } |
| |
| DBGMSG(("Use_devpoll=%d\n" ,Use_devpoll)); |
| close(testdevpollfd); |
| #endif |
| |
| /* |
| * For now, we optimize for Solaris 7 if /dev/poll isn't |
| * available, as it is only a small % hit for Solaris < 7. |
| * if ( (Use_devpoll == 0) && !strcmp(name.release,"5.6") ) |
| * Use_sol7opt = 0; |
| */ |
| Current_handle = 0; |
| for (i = 0; i < MAX_HANDLES; i++) { |
| IOE_handles[i].devpollfd = -1; |
| IOE_handles[i].pfd = NULL; |
| } |
| |
| /* |
| * this tells me the max number of open filedescriptors |
| */ |
| Max_index = sysconf(_SC_OPEN_MAX); |
| if (Max_index < 0) { |
| Max_index = 1024; |
| } |
| |
| DBGMSG(("got sysconf(_SC_OPEN_MAX)=%d file desc\n",Max_index)); |
| |
| return 0; |
| } |
| |
| JNIEXPORT jint JNICALL Java_Poller_getNumCPUs(JNIEnv *env, jclass cls) |
| { |
| return sysconf(_SC_NPROCESSORS_ONLN); |
| } |
| |
| /* |
| * Class: Poller |
| * Method: nativeCreatePoller |
| * Signature: (I)I |
| * Note : in the case where /dev/poll doesn't exist, |
| * using more than one poll array could hurt |
| * Solaris 7 performance due to kernel caching. |
| */ |
| |
| JNIEXPORT jint JNICALL Java_Poller_nativeCreatePoller |
| (JNIEnv *env, jobject obj, jint maximum_fds) |
| { |
| int handle, retval, i; |
| ioevent_t *ioeh; |
| |
| if (maximum_fds == -1) { |
| maximum_fds = Max_index; |
| } |
| handle = Current_handle; |
| if (Current_handle >= MAX_HANDLES) { |
| for (i = 0; i < MAX_HANDLES; i++) { |
| if (IOE_handles[i].inuse == 0) { |
| handle = i; |
| break; |
| } |
| } |
| if (handle >= MAX_HANDLES) { |
| return MEMORY_EXCEPTION("CreatePoller - MAX_HANDLES exceeded"); |
| } |
| } else { |
| Current_handle++; |
| } |
| |
| ioeh = &IOE_handles[handle]; |
| |
| ioeh->inuse = 1; |
| |
| ioeh->last_index = 0; |
| ioeh->total_free = 0; |
| ioeh->left_events = 0; |
| ioeh->max_index = maximum_fds; |
| |
| retval = handle; |
| if (Use_devpoll) { |
| ioeh->devpollfd = open("/dev/poll",O_RDWR); |
| DBGMSG(("Opened /dev/poll, set devpollfd = %d\n",ioeh->devpollfd)); |
| if (ioeh->devpollfd < 0) { |
| Current_handle--; |
| return MEMORY_EXCEPTION("CreatePoller - can\'t open /dev/poll"); |
| } |
| } |
| ioeh->pfd = malloc(maximum_fds * sizeof(pollfd_t)); |
| if (ioeh->pfd == NULL) { |
| Current_handle--; |
| return MEMORY_EXCEPTION("CreatePoller - malloc failure"); |
| } |
| |
| return retval; |
| } |
| |
| /* |
| * Class: Poller |
| * Method: nativeDestroyPoller |
| * Signature: (I)V |
| */ |
| JNIEXPORT void JNICALL Java_Poller_nativeDestroyPoller |
| (JNIEnv *env, jobject obj, jint handle) |
| { |
| |
| ioevent_t *ioeh; |
| |
| if (handle < 0 || handle >= MAX_HANDLES) |
| { |
| STATE_EXCEPTION("DestroyPoller - handle out of range"); |
| return; |
| } |
| |
| ioeh = &IOE_handles[handle]; |
| ioeh->inuse = 0; |
| if (Use_devpoll) { |
| close(ioeh->devpollfd); |
| } |
| free(ioeh->pfd); |
| } |
| |
| #ifdef DEBUG |
| static void check_handle(ioevent_t *ioeh) |
| { |
| int i,used,unused; |
| |
| used=unused=0; |
| for (i = 0; i < ioeh->last_index; i++) |
| { |
| if (ioeh->pfd[i].fd == -1) |
| unused++; |
| else |
| used++; |
| } |
| if (unused != ioeh->total_free) |
| printf("WARNING : found %d free, claimed %d. Used : %d\n", |
| unused, ioeh->total_free, used); |
| } |
| #endif |
| |
| /* |
| * Class: Poller |
| * Method: nativeAddFd |
| * Signature: (IIS)I |
| * |
| * Currently doesn't check to make sure we aren't adding |
| * an fd already added (no problem for /dev/poll...just |
| * an array waster for poll()). |
| */ |
| JNIEXPORT jint JNICALL Java_Poller_nativeAddFd |
| (JNIEnv *env, jobject obj, jint handle, jint fd, jshort events) |
| { |
| int retval; |
| ioevent_t *ioeh; |
| |
| if (handle < 0 || handle >= MAX_HANDLES) |
| return STATE_EXCEPTION("AddFd - handle out of range"); |
| |
| ioeh = &IOE_handles[handle]; |
| |
| CHECK_HANDLE(ioeh); |
| |
| #ifdef DEVPOLL |
| if (Use_devpoll) |
| { |
| int i; |
| pollfd_t pollelt; |
| |
| /* |
| * use /dev/poll |
| */ |
| pollelt.fd = fd; |
| pollelt.events = events; |
| if ((i = write(ioeh->devpollfd, &pollelt, sizeof(pollfd_t))) != |
| sizeof(pollfd_t)) { |
| DBGMSG(("write to devpollfd=%d showed %d bytes out of %d\n", |
| ioeh->devpollfd,i,sizeof(pollfd_t))); |
| return STATE_EXCEPTION("AddFd - /dev/poll add failure"); |
| } |
| else |
| { |
| retval = fd; |
| } |
| } |
| else |
| #endif |
| { /* no /dev/poll available */ |
| retval = addfd(env, ioeh, fd, events); |
| } |
| return retval; |
| } |
| |
| /* |
| * Addfd to pollfd array...optimized for Solaris 7 |
| */ |
| jint addfd(JNIEnv *env, ioevent_t *ioeh, jint fd, jshort events) |
| { |
| int idx; |
| |
| if (ioeh->total_free) |
| { |
| /* |
| * Traversing from end because that's where we pad. |
| */ |
| ioeh->total_free--; |
| for (idx = ioeh->last_index - 1; idx >= 0; idx--) { |
| if (ioeh->pfd[idx].fd == -1) |
| break; |
| } |
| } |
| else if (ioeh->last_index >= ioeh->max_index) |
| { |
| return MEMORY_EXCEPTION("AddFd - too many fds"); |
| } |
| else |
| { |
| int i; |
| int new_total; |
| /* |
| * For Solaris 7, want to add some growth space |
| * and fill extras with fd=-1. This allows for |
| * kernel poll() implementation to perform optimally. |
| */ |
| new_total = ioeh->last_index; |
| new_total += (new_total/10) + 1; /* bump size by 10% */ |
| if (new_total > ioeh->max_index) |
| new_total = ioeh->max_index; |
| for (i = ioeh->last_index; i <= new_total; i++) |
| { |
| ioeh->pfd[i].fd = -1; |
| } |
| idx = ioeh->last_index; |
| ioeh->total_free = new_total - ioeh->last_index - 1; |
| DBGMSG(("Just grew from %d to %d in size\n", |
| ioeh->last_index, new_total)); |
| ioeh->last_index = new_total; |
| } |
| ASSERT((idx >= 0) && (idx <= ioeh->max_index)); |
| ASSERT(ioeh->pfd[idx].fd == -1); |
| ioeh->pfd[idx].fd = fd; |
| ioeh->pfd[idx].events = events; |
| ioeh->pfd[idx].revents = 0; |
| |
| CHECK_HANDLE(ioeh); |
| |
| return fd; |
| } |
| |
| /* |
| * Class: Poller |
| * Method: nativeRemoveFd |
| * Signature: (II)I |
| */ |
| JNIEXPORT jint JNICALL Java_Poller_nativeRemoveFd |
| (JNIEnv *env, jobject obj, jint handle, jint fd) |
| { |
| ioevent_t *ioeh; |
| |
| if (handle < 0 || handle >= MAX_HANDLES) |
| return STATE_EXCEPTION("RemoveFd - handle out of range"); |
| |
| ioeh = &IOE_handles[handle]; |
| |
| #ifdef DEVPOLL |
| if (Use_devpoll) |
| { |
| /* |
| * use /dev/poll - currently no need for locking here. |
| */ |
| pollfd_t pollelt; |
| |
| pollelt.fd = fd; |
| pollelt.events = POLLREMOVE; |
| if (write(ioeh->devpollfd, &pollelt, |
| sizeof(pollfd_t) ) != sizeof(pollfd_t)) |
| { |
| return STATE_EXCEPTION("RemoveFd - /dev/poll failure"); |
| } |
| } |
| else |
| #endif DEVPOLL |
| { |
| return removefd(env, ioeh,fd); |
| } |
| } |
| /* |
| * remove from pollfd array...optimize for Solaris 7 |
| */ |
| jint removefd(JNIEnv *env, ioevent_t *ioeh, jint fd) |
| { |
| int i; |
| int found = 0; |
| |
| { /* !Use_devpoll */ |
| for (i = 0; i < ioeh->last_index; i++) |
| { |
| if (ioeh->pfd[i].fd == fd) |
| { |
| ioeh->pfd[i].fd = -1; |
| found = 1; |
| break; |
| } |
| } |
| if (!found) |
| { |
| return STATE_EXCEPTION("RemoveFd - no such fd"); |
| } |
| ioeh->left_events = 0; /* Have to go back to the kernel */ |
| ioeh->total_free++; |
| /* |
| * Shrinking pool if > 33% empty. Just don't do this often! |
| */ |
| if ( (ioeh->last_index > 100) && |
| (ioeh->total_free > (ioeh->last_index / 3)) ) |
| { |
| int j; |
| /* |
| * we'll just bite the bullet here, since we're > 33% empty. |
| * walk through and eliminate -1 fd values, shrink total |
| * size to still have ~ 10 fd==-1 values at end. |
| * Start at end (since we pad here) and, when we find fd != -1, |
| * swap with an earlier fd == -1 until we have all -1 values |
| * at the end. |
| */ |
| CHECK_HANDLE(ioeh); |
| for (i = ioeh->last_index - 1, j = 0; i > j; i--) |
| { |
| if (ioeh->pfd[i].fd != -1) |
| { |
| while ( (j < i) && (ioeh->pfd[j].fd != -1) ) |
| j++; |
| DBGMSG( ("i=%d,j=%d,ioeh->pfd[j].fd=%d\n", |
| i, j, ioeh->pfd[j].fd) ); |
| if (j < i) |
| { |
| ASSERT(ioeh->pfd[j].fd == -1); |
| ioeh->pfd[j].fd = ioeh->pfd[i].fd; |
| ioeh->pfd[j].events = ioeh->pfd[i].events; |
| ioeh->pfd[i].fd = -1; |
| } |
| } |
| } |
| DBGMSG(("Just shrunk from %d to %d in size\n", |
| ioeh->last_index, j+11)); |
| ioeh->last_index = j + 11; /* last_index always 1 greater */ |
| ioeh->total_free = 10; |
| CHECK_HANDLE(ioeh); |
| } |
| } /* !Use_devpoll */ |
| |
| return 1; |
| } |
| |
| /* |
| * Class: Poller |
| * Method: nativeIsMember |
| * Signature: (II)I |
| */ |
| JNIEXPORT jint JNICALL Java_Poller_nativeIsMember |
| (JNIEnv *env, jobject obj, jint handle, jint fd) |
| { |
| int found = 0; |
| int i; |
| ioevent_t *ioeh; |
| |
| if (handle < 0 || handle >= MAX_HANDLES) |
| return STATE_EXCEPTION("IsMember - handle out of range"); |
| |
| ioeh = &IOE_handles[handle]; |
| |
| #ifdef DEVPOLL |
| if (Use_devpoll) |
| { |
| pollfd_t pfd; |
| /* |
| * DEVPOLL ioctl DP_ISPOLLED call to determine if fd is polled. |
| */ |
| pfd.fd = fd; |
| pfd.events = 0; |
| pfd.revents = 0; |
| found = ioctl(ioeh->devpollfd, DP_ISPOLLED, &pfd); |
| if (found == -1) |
| { |
| return STATE_EXCEPTION("IsMember - /dev/poll failure"); |
| } |
| } |
| else |
| #endif |
| { |
| for (i = 0; i < ioeh->last_index; i++) |
| { |
| if (fd == ioeh->pfd[i].fd) |
| { |
| found = 1; |
| break; |
| } |
| } |
| } |
| |
| return found; |
| } |
| |
| /* |
| * Class: Poller |
| * Method: nativeWait |
| * Signature: (II[I[SJ)I |
| */ |
| JNIEXPORT jint JNICALL Java_Poller_nativeWait |
| (JNIEnv *env, jobject obj, jint handle, jint maxEvents, |
| jintArray jfds, jshortArray jrevents, jlong timeout) |
| { |
| int useEvents, count, idx; |
| short *reventp; |
| jint *fdp; |
| int retval; |
| ioevent_t *ioeh; |
| jboolean isCopy1,isCopy2; |
| |
| if (handle < 0 || handle >= MAX_HANDLES) |
| return STATE_EXCEPTION("nativeWait - handle out of range"); |
| |
| ioeh = &IOE_handles[handle]; |
| |
| if (maxEvents == 0) /* just doing a kernel delay! */ |
| { |
| useEvents = poll(NULL,0L,timeout); |
| return 0; |
| } |
| |
| #ifdef DEVPOLL |
| if (Use_devpoll) |
| { |
| struct dvpoll dopoll; |
| /* |
| * DEVPOLL ioctl DP_POLL call, reading |
| */ |
| dopoll.dp_timeout = timeout; |
| dopoll.dp_nfds=maxEvents; |
| dopoll.dp_fds=ioeh->pfd; |
| |
| useEvents = ioctl(ioeh->devpollfd, DP_POLL, &dopoll); |
| while ((useEvents == -1) && (errno == EAGAIN)) |
| useEvents = ioctl(ioeh->devpollfd, DP_POLL, &dopoll); |
| |
| if (useEvents == -1) |
| { |
| if (errno == EINTR) |
| return INTERRUPT_EXCEPTION("nativeWait - /dev/poll failure EINTR"); |
| else |
| return STATE_EXCEPTION("nativeWait - /dev/poll failure"); |
| } |
| |
| reventp =(*env)->GetShortArrayElements(env,jrevents,&isCopy1); |
| fdp =(*env)->GetIntArrayElements(env,jfds,&isCopy2); |
| for (idx = 0,count = 0; idx < useEvents; idx++) |
| { |
| if (ioeh->pfd[idx].revents) |
| { |
| fdp[count] = ioeh->pfd[idx].fd; |
| reventp[count] = ioeh->pfd[idx].revents; |
| count++; |
| } |
| } |
| if (count < useEvents) |
| return STATE_EXCEPTION("Wait - Corrupted internals"); |
| |
| if (isCopy1 == JNI_TRUE) |
| (*env)->ReleaseShortArrayElements(env,jrevents,reventp,0); |
| if (isCopy2 == JNI_TRUE) |
| (*env)->ReleaseIntArrayElements(env,jfds,fdp,0); |
| } |
| else |
| #endif |
| { /* !Use_devpoll */ |
| |
| /* no leftovers=>go to kernel */ |
| if (ioeh->left_events == 0) |
| { |
| useEvents = poll(ioeh->pfd,ioeh->last_index, timeout); |
| while ((useEvents == -1) && (errno == EAGAIN)) |
| useEvents = poll(ioeh->pfd,ioeh->last_index, timeout); |
| if (useEvents == -1) |
| { |
| if (errno == EINTR) |
| return INTERRUPT_EXCEPTION("Wait - poll() failure EINTR-" \ |
| "IO interrupted."); |
| else if (errno == EINVAL) |
| return STATE_EXCEPTION("Wait - poll() failure EINVAL-" \ |
| "invalid args (is fdlim cur < max?)"); |
| else |
| return STATE_EXCEPTION("Wait - poll() failure"); |
| } |
| ioeh->left_events = useEvents; |
| DBGMSG(("waitnative : poll returns : %d\n",useEvents)); |
| } |
| else |
| { /* left over from last call */ |
| useEvents = ioeh->left_events; |
| } |
| |
| if (useEvents > maxEvents) |
| { |
| useEvents = maxEvents; |
| } |
| |
| ioeh->left_events -= useEvents; /* left to process */ |
| |
| DBGMSG(("waitnative : left %d, use %d, max %d\n",ioeh->left_events, |
| useEvents,maxEvents)); |
| |
| if (useEvents > 0) |
| { |
| reventp =(*env)->GetShortArrayElements(env,jrevents,&isCopy1); |
| fdp =(*env)->GetIntArrayElements(env,jfds,&isCopy2); |
| for (idx = 0,count = 0; (idx < ioeh->last_index) && |
| (count < useEvents); idx++) |
| { |
| if (ioeh->pfd[idx].revents) |
| { |
| fdp[count] = ioeh->pfd[idx].fd; |
| reventp[count] = ioeh->pfd[idx].revents; |
| /* in case of leftover for next walk */ |
| ioeh->pfd[idx].revents = 0; |
| count++; |
| } |
| } |
| if (count < useEvents) |
| { |
| ioeh->left_events = 0; |
| return STATE_EXCEPTION("Wait - Corrupted internals"); |
| } |
| if (isCopy1 == JNI_TRUE) |
| (*env)->ReleaseShortArrayElements(env,jrevents,reventp,0); |
| if (isCopy2 == JNI_TRUE) |
| (*env)->ReleaseIntArrayElements(env,jfds,fdp,0); |
| } |
| } /* !Use_devpoll */ |
| |
| return useEvents; |
| } |