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 }