1/* 2 * Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26#include "jni.h" 27#include "jni_util.h" 28#include "jvm.h" 29#include "jlong.h" 30 31#include "sun_nio_ch_EPollArrayWrapper.h" 32 33#include <unistd.h> 34#include <sys/time.h> 35#include <sys/epoll.h> 36 37#define RESTARTABLE(_cmd, _result) do { \ 38 do { \ 39 _result = _cmd; \ 40 } while((_result == -1) && (errno == EINTR)); \ 41} while(0) 42 43 44static int 45iepoll(int epfd, struct epoll_event *events, int numfds, jlong timeout) 46{ 47 jlong start, now; 48 int remaining = timeout; 49 struct timeval t; 50 int diff; 51 52 gettimeofday(&t, NULL); 53 start = t.tv_sec * 1000 + t.tv_usec / 1000; 54 55 for (;;) { 56 int res = epoll_wait(epfd, events, numfds, remaining); 57 if (res < 0 && errno == EINTR) { 58 if (remaining >= 0) { 59 gettimeofday(&t, NULL); 60 now = t.tv_sec * 1000 + t.tv_usec / 1000; 61 diff = now - start; 62 remaining -= diff; 63 if (diff < 0 || remaining <= 0) { 64 return 0; 65 } 66 start = now; 67 } 68 } else { 69 return res; 70 } 71 } 72} 73 74JNIEXPORT void JNICALL 75Java_sun_nio_ch_EPollArrayWrapper_init(JNIEnv *env, jclass this) 76{ 77} 78 79JNIEXPORT jint JNICALL 80Java_sun_nio_ch_EPollArrayWrapper_epollCreate(JNIEnv *env, jobject this) 81{ 82 /* 83 * epoll_create expects a size as a hint to the kernel about how to 84 * dimension internal structures. We can't predict the size in advance. 85 */ 86 int epfd = epoll_create(256); 87 if (epfd < 0) { 88 JNU_ThrowIOExceptionWithLastError(env, "epoll_create failed"); 89 } 90 return epfd; 91} 92 93JNIEXPORT jint JNICALL 94Java_sun_nio_ch_EPollArrayWrapper_sizeofEPollEvent(JNIEnv* env, jclass this) 95{ 96 return sizeof(struct epoll_event); 97} 98 99JNIEXPORT jint JNICALL 100Java_sun_nio_ch_EPollArrayWrapper_offsetofData(JNIEnv* env, jclass this) 101{ 102 return offsetof(struct epoll_event, data); 103} 104 105JNIEXPORT void JNICALL 106Java_sun_nio_ch_EPollArrayWrapper_epollCtl(JNIEnv *env, jobject this, jint epfd, 107 jint opcode, jint fd, jint events) 108{ 109 struct epoll_event event; 110 int res; 111 112 event.events = events; 113 event.data.fd = fd; 114 115 RESTARTABLE(epoll_ctl(epfd, (int)opcode, (int)fd, &event), res); 116 117 /* 118 * A channel may be registered with several Selectors. When each Selector 119 * is polled a EPOLL_CTL_DEL op will be inserted into its pending update 120 * list to remove the file descriptor from epoll. The "last" Selector will 121 * close the file descriptor which automatically unregisters it from each 122 * epoll descriptor. To avoid costly synchronization between Selectors we 123 * allow pending updates to be processed, ignoring errors. The errors are 124 * harmless as the last update for the file descriptor is guaranteed to 125 * be EPOLL_CTL_DEL. 126 */ 127 if (res < 0 && errno != EBADF && errno != ENOENT && errno != EPERM) { 128 JNU_ThrowIOExceptionWithLastError(env, "epoll_ctl failed"); 129 } 130} 131 132JNIEXPORT jint JNICALL 133Java_sun_nio_ch_EPollArrayWrapper_epollWait(JNIEnv *env, jobject this, 134 jlong address, jint numfds, 135 jlong timeout, jint epfd) 136{ 137 struct epoll_event *events = jlong_to_ptr(address); 138 int res; 139 140 if (timeout <= 0) { /* Indefinite or no wait */ 141 RESTARTABLE(epoll_wait(epfd, events, numfds, timeout), res); 142 } else { /* Bounded wait; bounded restarts */ 143 res = iepoll(epfd, events, numfds, timeout); 144 } 145 146 if (res < 0) { 147 JNU_ThrowIOExceptionWithLastError(env, "epoll_wait failed"); 148 } 149 return res; 150} 151 152JNIEXPORT void JNICALL 153Java_sun_nio_ch_EPollArrayWrapper_interrupt(JNIEnv *env, jobject this, jint fd) 154{ 155 int fakebuf[1]; 156 fakebuf[0] = 1; 157 if (write(fd, fakebuf, 1) < 0) { 158 JNU_ThrowIOExceptionWithLastError(env,"write to interrupt fd failed"); 159 } 160} 161