1/* 2 * Copyright (c) 2011, 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/* 27 * KQueueArrayWrapper.c 28 * Implementation of Selector using FreeBSD / Mac OS X kqueues 29 * Derived from Sun's DevPollArrayWrapper 30 */ 31 32 33#include "jni.h" 34#include "jni_util.h" 35#include "jvm.h" 36#include "jlong.h" 37 38#include <sys/types.h> 39#include <sys/event.h> 40#include <sys/time.h> 41 42JNIEXPORT void JNICALL 43Java_sun_nio_ch_KQueueArrayWrapper_initStructSizes(JNIEnv *env, jclass clazz) 44{ 45#define CHECK_EXCEPTION() { \ 46 if ((*env)->ExceptionCheck(env)) { \ 47 goto exceptionOccurred; \ 48 } \ 49} 50 51#define CHECK_ERROR_AND_EXCEPTION(_field) { \ 52 if (_field == NULL) { \ 53 goto badField; \ 54 } \ 55 CHECK_EXCEPTION(); \ 56} 57 58 59 jfieldID field; 60 61 field = (*env)->GetStaticFieldID(env, clazz, "EVFILT_READ", "S"); 62 CHECK_ERROR_AND_EXCEPTION(field); 63 (*env)->SetStaticShortField(env, clazz, field, EVFILT_READ); 64 CHECK_EXCEPTION(); 65 66 field = (*env)->GetStaticFieldID(env, clazz, "EVFILT_WRITE", "S"); 67 CHECK_ERROR_AND_EXCEPTION(field); 68 (*env)->SetStaticShortField(env, clazz, field, EVFILT_WRITE); 69 CHECK_EXCEPTION(); 70 71 field = (*env)->GetStaticFieldID(env, clazz, "SIZEOF_KEVENT", "S"); 72 CHECK_ERROR_AND_EXCEPTION(field); 73 (*env)->SetStaticShortField(env, clazz, field, (short) sizeof(struct kevent)); 74 CHECK_EXCEPTION(); 75 76 field = (*env)->GetStaticFieldID(env, clazz, "FD_OFFSET", "S"); 77 CHECK_ERROR_AND_EXCEPTION(field); 78 (*env)->SetStaticShortField(env, clazz, field, (short) offsetof(struct kevent, ident)); 79 CHECK_EXCEPTION(); 80 81 field = (*env)->GetStaticFieldID(env, clazz, "FILTER_OFFSET", "S"); 82 CHECK_ERROR_AND_EXCEPTION(field); 83 (*env)->SetStaticShortField(env, clazz, field, (short) offsetof(struct kevent, filter)); 84 CHECK_EXCEPTION(); 85 return; 86 87badField: 88 return; 89 90exceptionOccurred: 91 return; 92 93#undef CHECK_EXCEPTION 94#undef CHECK_ERROR_AND_EXCEPTION 95} 96 97JNIEXPORT jint JNICALL 98Java_sun_nio_ch_KQueueArrayWrapper_init(JNIEnv *env, jobject this) 99{ 100 int kq = kqueue(); 101 if (kq < 0) { 102 JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: kqueue() failed"); 103 } 104 return kq; 105} 106 107 108JNIEXPORT void JNICALL 109Java_sun_nio_ch_KQueueArrayWrapper_register0(JNIEnv *env, jobject this, 110 jint kq, jint fd, jint r, jint w) 111{ 112 struct kevent changes[2]; 113 struct kevent errors[2]; 114 struct timespec dontBlock = {0, 0}; 115 116 // if (r) then { register for read } else { unregister for read } 117 // if (w) then { register for write } else { unregister for write } 118 // Ignore errors - they're probably complaints about deleting non- 119 // added filters - but provide an error array anyway because 120 // kqueue behaves erratically if some of its registrations fail. 121 EV_SET(&changes[0], fd, EVFILT_READ, r ? EV_ADD : EV_DELETE, 0, 0, 0); 122 EV_SET(&changes[1], fd, EVFILT_WRITE, w ? EV_ADD : EV_DELETE, 0, 0, 0); 123 kevent(kq, changes, 2, errors, 2, &dontBlock); 124} 125 126JNIEXPORT jint JNICALL 127Java_sun_nio_ch_KQueueArrayWrapper_kevent0(JNIEnv *env, jobject this, jint kq, 128 jlong kevAddr, jint kevCount, 129 jlong timeout) 130{ 131 struct kevent *kevs = (struct kevent *)jlong_to_ptr(kevAddr); 132 struct timespec ts; 133 struct timespec *tsp; 134 int result; 135 136 // Java timeout is in milliseconds. Convert to struct timespec. 137 // Java timeout == -1 : wait forever : timespec timeout of NULL 138 // Java timeout == 0 : return immediately : timespec timeout of zero 139 if (timeout >= 0) { 140 // For some indeterminate reason kevent(2) has been found to fail with 141 // an EINVAL error for timeout values greater than or equal to 142 // 100000001000L. To avoid this problem, clamp the timeout arbitrarily 143 // to the maximum value of a 32-bit signed integer which is 144 // approximately 25 days in milliseconds. 145 const jlong timeoutMax = 0x7fffffff; // java.lang.Integer.MAX_VALUE 146 if (timeout > timeoutMax) { 147 timeout = timeoutMax; 148 } 149 ts.tv_sec = timeout / 1000; 150 ts.tv_nsec = (timeout % 1000) * 1000000; //nanosec = 1 million millisec 151 tsp = &ts; 152 } else { 153 tsp = NULL; 154 } 155 156 result = kevent(kq, NULL, 0, kevs, kevCount, tsp); 157 158 if (result < 0) { 159 if (errno == EINTR) { 160 // ignore EINTR, pretend nothing was selected 161 result = 0; 162 } else { 163 JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: kqueue failed"); 164 } 165 } 166 167 return result; 168} 169 170 171JNIEXPORT void JNICALL 172Java_sun_nio_ch_KQueueArrayWrapper_interrupt(JNIEnv *env, jclass cls, jint fd) 173{ 174 char c = 1; 175 if (1 != write(fd, &c, 1)) { 176 JNU_ThrowIOExceptionWithLastError(env, "KQueueArrayWrapper: interrupt failed"); 177 } 178} 179 180