io_uring availability check
Motivation: availability io_uring check for each test case Modification: added ioUringExit method to munmap the shared memory and close ring file descriptor which is required for the availability check Result: it's able to integrate testsuite tests
This commit is contained in:
parent
bf6a14effb
commit
1117c6fdb8
@ -64,6 +64,21 @@ static jclass ringBufferClass = NULL;
|
|||||||
static jclass ioUringCompletionQueueClass = NULL;
|
static jclass ioUringCompletionQueueClass = NULL;
|
||||||
static jclass ioUringSubmissionQueueClass = NULL;
|
static jclass ioUringSubmissionQueueClass = NULL;
|
||||||
|
|
||||||
|
static void netty_io_uring_native_JNI_OnUnLoad(JNIEnv* env) {
|
||||||
|
netty_unix_limits_JNI_OnUnLoad(env);
|
||||||
|
netty_unix_errors_JNI_OnUnLoad(env);
|
||||||
|
netty_unix_filedescriptor_JNI_OnUnLoad(env);
|
||||||
|
netty_unix_socket_JNI_OnUnLoad(env);
|
||||||
|
netty_unix_buffer_JNI_OnUnLoad(env);
|
||||||
|
|
||||||
|
ringBufferMethodId = NULL;
|
||||||
|
ioUringSubmissionQueueMethodId = NULL;
|
||||||
|
ioUringCommpletionQueueMethodId = NULL;
|
||||||
|
ringBufferClass = NULL;
|
||||||
|
ioUringCompletionQueueClass = NULL;
|
||||||
|
ioUringSubmissionQueueClass = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
void io_uring_unmap_rings(struct io_uring_sq *sq, struct io_uring_cq *cq) {
|
void io_uring_unmap_rings(struct io_uring_sq *sq, struct io_uring_cq *cq) {
|
||||||
munmap(sq->ring_ptr, sq->ring_sz);
|
munmap(sq->ring_ptr, sq->ring_sz);
|
||||||
if (cq->ring_ptr && cq->ring_ptr != sq->ring_ptr) {
|
if (cq->ring_ptr && cq->ring_ptr != sq->ring_ptr) {
|
||||||
@ -210,6 +225,43 @@ static void netty_epoll_native_eventFdWrite(JNIEnv* env, jclass clazz, jint fd,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void netty_io_uring_ring_buffer_exit(JNIEnv *env, jclass class, jobject ringBuffer) {
|
||||||
|
// Find the id of the Java method to be called
|
||||||
|
|
||||||
|
jmethodID submissionQueueMethodId = (*env)->GetMethodID(env, ringBufferClass, "getIoUringSubmissionQueue", "()Lio/netty/channel/uring/IOUringSubmissionQueue;");
|
||||||
|
jmethodID completionQueueMethodId = (*env)->GetMethodID(env, ringBufferClass, "getIoUringCompletionQueue", "()Lio/netty/channel/uring/IOUringCompletionQueue;");
|
||||||
|
|
||||||
|
jobject submissionQueue = (*env)->CallObjectMethod(env, ringBuffer, submissionQueueMethodId);
|
||||||
|
jobject completionQueue = (*env)->CallObjectMethod(env, ringBuffer, completionQueueMethodId);
|
||||||
|
|
||||||
|
jmethodID submissionQueueArrayAddressMethodId = (*env)->GetMethodID(env, ioUringSubmissionQueueClass, "getSubmissionQueueArrayAddress", "()J");
|
||||||
|
jmethodID submissionQueueKringEntriesAddressMethodId = (*env)->GetMethodID(env, ioUringSubmissionQueueClass, "getKRingEntriesAddress", "()J");
|
||||||
|
jmethodID submissionQueueRingFdMethodId = (*env)->GetMethodID(env, ioUringSubmissionQueueClass, "getRingFd", "()I");
|
||||||
|
jmethodID submissionQueueRingAddressMethodId = (*env)->GetMethodID(env, ioUringSubmissionQueueClass, "getRingAddress", "()J");
|
||||||
|
jmethodID submissionQueueRingSizeMethodId = (*env)->GetMethodID(env, ioUringSubmissionQueueClass, "getRingSize", "()I");
|
||||||
|
|
||||||
|
jmethodID completionQueueRingAddressMethodId = (*env)->GetMethodID(env, ioUringCompletionQueueClass, "getRingAddress", "()J");
|
||||||
|
jmethodID completionQueueRingSizeMethodId = (*env)->GetMethodID(env, ioUringCompletionQueueClass, "getRingSize", "()I");
|
||||||
|
|
||||||
|
jlong submissionQueueArrayAddress = (*env)->CallLongMethod(env, submissionQueue, submissionQueueArrayAddressMethodId);
|
||||||
|
jlong submissionQueueKringEntriesAddress = (*env)->CallLongMethod(env, submissionQueue, submissionQueueKringEntriesAddressMethodId);
|
||||||
|
jint submissionQueueRingFd = (*env)->CallIntMethod(env, submissionQueue, submissionQueueRingFdMethodId);
|
||||||
|
jlong submissionQueueRingAddress = (*env)->CallLongMethod(env, submissionQueue, submissionQueueRingAddressMethodId);
|
||||||
|
jint submissionQueueRingSize = (*env)->CallIntMethod(env, submissionQueue, submissionQueueRingSizeMethodId);
|
||||||
|
|
||||||
|
jlong completionQueueRingAddress = (*env)->CallLongMethod(env, completionQueue, completionQueueRingAddressMethodId);
|
||||||
|
jint completionQueueRingSize = (*env)->CallIntMethod(env, completionQueue, completionQueueRingSizeMethodId);
|
||||||
|
|
||||||
|
unsigned submissionQueueKringEntries = *((unsigned int *) submissionQueueKringEntriesAddress);
|
||||||
|
|
||||||
|
munmap((struct io_uring_sqe*) submissionQueueArrayAddress, submissionQueueKringEntries * sizeof(struct io_uring_sqe));
|
||||||
|
munmap((void*) submissionQueueRingAddress, submissionQueueRingSize);
|
||||||
|
if (((void *) completionQueueRingAddress) && ((void *) completionQueueRingAddress) != ((void *) submissionQueueRingAddress)) {
|
||||||
|
munmap((void *)completionQueueRingAddress, completionQueueRingSize);
|
||||||
|
}
|
||||||
|
close(submissionQueueRingFd);
|
||||||
|
}
|
||||||
|
|
||||||
static int nettyBlockingSocket(int domain, int type, int protocol) {
|
static int nettyBlockingSocket(int domain, int type, int protocol) {
|
||||||
return socket(domain, type, protocol);
|
return socket(domain, type, protocol);
|
||||||
}
|
}
|
||||||
@ -261,17 +313,14 @@ static jint netty_create_file(JNIEnv *env, jclass class) {
|
|||||||
return open("io-uring-test.txt", O_RDWR | O_TRUNC | O_CREAT, 0644);
|
return open("io-uring-test.txt", O_RDWR | O_TRUNC | O_CREAT, 0644);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void netty_io_uring_native_JNI_OnUnLoad(JNIEnv *env) {
|
|
||||||
// Todo OnUnLoad
|
|
||||||
}
|
|
||||||
|
|
||||||
// JNI Method Registration Table Begin
|
// JNI Method Registration Table Begin
|
||||||
static const JNINativeMethod method_table[] = {
|
static const JNINativeMethod method_table[] = {
|
||||||
{"ioUringSetup", "(I)Lio/netty/channel/uring/RingBuffer;", (void *) netty_io_uring_setup},
|
{"ioUringSetup", "(I)Lio/netty/channel/uring/RingBuffer;", (void *) netty_io_uring_setup},
|
||||||
|
{"ioUringExit", "(Lio/netty/channel/uring/RingBuffer;)V", (void *) netty_io_uring_ring_buffer_exit},
|
||||||
{"createFile", "()I", (void *) netty_create_file},
|
{"createFile", "()I", (void *) netty_create_file},
|
||||||
{"ioUringEnter", "(IIII)I", (void *)netty_io_uring_enter},
|
{"ioUringEnter", "(IIII)I", (void *)netty_io_uring_enter},
|
||||||
{"eventFd", "()I", (void *) netty_epoll_native_eventFd},
|
{"eventFd", "()I", (void *) netty_epoll_native_eventFd},
|
||||||
{ "eventFdWrite", "(IJ)V", (void *) netty_epoll_native_eventFdWrite },
|
{"eventFdWrite", "(IJ)V", (void *) netty_epoll_native_eventFdWrite },
|
||||||
{"ioUringRegisterEventFd", "(II)I", (void *) netty_io_uring_register_event_fd},
|
{"ioUringRegisterEventFd", "(II)I", (void *) netty_io_uring_register_event_fd},
|
||||||
{"ioUringUnregisterEventFd", "(I)I", (void *) netty_io_uring_unregister_event_fd}
|
{"ioUringUnregisterEventFd", "(I)I", (void *) netty_io_uring_unregister_event_fd}
|
||||||
};
|
};
|
||||||
@ -280,6 +329,12 @@ static const jint method_table_size =
|
|||||||
// JNI Method Registration Table End
|
// JNI Method Registration Table End
|
||||||
|
|
||||||
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||||
|
int ret = JNI_ERR;
|
||||||
|
int limitsOnLoadCalled = 0;
|
||||||
|
int errorsOnLoadCalled = 0;
|
||||||
|
int filedescriptorOnLoadCalled = 0;
|
||||||
|
int socketOnLoadCalled = 0;
|
||||||
|
int bufferOnLoadCalled = 0;
|
||||||
JNIEnv *env;
|
JNIEnv *env;
|
||||||
char *nettyClassName = NULL;
|
char *nettyClassName = NULL;
|
||||||
|
|
||||||
@ -316,22 +371,27 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||||||
if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
limitsOnLoadCalled = 1;
|
||||||
|
|
||||||
if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
errorsOnLoadCalled = 1;
|
||||||
|
|
||||||
if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
filedescriptorOnLoadCalled = 1;
|
||||||
|
|
||||||
if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
socketOnLoadCalled = 1;
|
||||||
|
|
||||||
if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
bufferOnLoadCalled = 1;
|
||||||
|
|
||||||
NETTY_PREPEND(packagePrefix, "io/netty/channel/uring/RingBuffer",
|
NETTY_PREPEND(packagePrefix, "io/netty/channel/uring/RingBuffer",
|
||||||
nettyClassName, done);
|
nettyClassName, done);
|
||||||
@ -354,9 +414,45 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
|||||||
NETTY_GET_METHOD(env, ioUringCompletionQueueClass,
|
NETTY_GET_METHOD(env, ioUringCompletionQueueClass,
|
||||||
ioUringCommpletionQueueMethodId, "<init>", "(JJJJJJIJI)V",
|
ioUringCommpletionQueueMethodId, "<init>", "(JJJJJJIJI)V",
|
||||||
done);
|
done);
|
||||||
|
ret = NETTY_JNI_VERSION;
|
||||||
done:
|
done:
|
||||||
//unload
|
//unload
|
||||||
|
free(nettyClassName);
|
||||||
|
|
||||||
return NETTY_JNI_VERSION;
|
if (ret == JNI_ERR) {
|
||||||
|
if (limitsOnLoadCalled == 1) {
|
||||||
|
netty_unix_limits_JNI_OnUnLoad(env);
|
||||||
|
}
|
||||||
|
if (errorsOnLoadCalled == 1) {
|
||||||
|
netty_unix_errors_JNI_OnUnLoad(env);
|
||||||
|
}
|
||||||
|
if (filedescriptorOnLoadCalled == 1) {
|
||||||
|
netty_unix_filedescriptor_JNI_OnUnLoad(env);
|
||||||
|
}
|
||||||
|
if (socketOnLoadCalled == 1) {
|
||||||
|
netty_unix_socket_JNI_OnUnLoad(env);
|
||||||
|
}
|
||||||
|
if (bufferOnLoadCalled == 1) {
|
||||||
|
netty_unix_buffer_JNI_OnUnLoad(env);
|
||||||
|
}
|
||||||
|
|
||||||
|
ringBufferMethodId = NULL;
|
||||||
|
ioUringSubmissionQueueMethodId = NULL;
|
||||||
|
ioUringCommpletionQueueMethodId = NULL;
|
||||||
|
ringBufferClass = NULL;
|
||||||
|
ioUringCompletionQueueClass = NULL;
|
||||||
|
ioUringSubmissionQueueClass = NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNI_OnUnload(JavaVM* vm, void* reserved) {
|
||||||
|
// Todo OnUnLoad
|
||||||
|
JNIEnv* env;
|
||||||
|
if ((*vm)->GetEnv(vm, (void**) &env, NETTY_JNI_VERSION) != JNI_OK) {
|
||||||
|
// Something is wrong but nothing we can do about this :(
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
netty_io_uring_native_JNI_OnUnLoad(env);
|
||||||
}
|
}
|
@ -0,0 +1,68 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.channel.uring;
|
||||||
|
|
||||||
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
|
|
||||||
|
final class IOUring {
|
||||||
|
|
||||||
|
private static final Throwable UNAVAILABILITY_CAUSE;
|
||||||
|
|
||||||
|
static {
|
||||||
|
Throwable cause = null;
|
||||||
|
|
||||||
|
if (SystemPropertyUtil.getBoolean("io.netty.transport.noNative", false)) {
|
||||||
|
cause = new UnsupportedOperationException(
|
||||||
|
"Native transport was explicit disabled with -Dio.netty.transport.noNative=true");
|
||||||
|
} else {
|
||||||
|
RingBuffer ringBuffer = null;
|
||||||
|
try {
|
||||||
|
ringBuffer = Native.createRingBuffer();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
cause = t;
|
||||||
|
} finally {
|
||||||
|
if (ringBuffer != null) {
|
||||||
|
try {
|
||||||
|
ringBuffer.close();
|
||||||
|
} catch (Exception ignore) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UNAVAILABILITY_CAUSE = cause;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isAvailable() {
|
||||||
|
return UNAVAILABILITY_CAUSE == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ensureAvailability() {
|
||||||
|
if (UNAVAILABILITY_CAUSE != null) {
|
||||||
|
throw (Error) new UnsatisfiedLinkError(
|
||||||
|
"failed to load the required native library").initCause(UNAVAILABILITY_CAUSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Throwable unavailabilityCause() {
|
||||||
|
return UNAVAILABILITY_CAUSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IOUring() {
|
||||||
|
}
|
||||||
|
}
|
@ -15,19 +15,52 @@
|
|||||||
*/
|
*/
|
||||||
package io.netty.channel.uring;
|
package io.netty.channel.uring;
|
||||||
|
|
||||||
|
import io.netty.channel.DefaultFileRegion;
|
||||||
import io.netty.channel.unix.FileDescriptor;
|
import io.netty.channel.unix.FileDescriptor;
|
||||||
|
import io.netty.channel.unix.PeerCredentials;
|
||||||
import io.netty.channel.unix.Socket;
|
import io.netty.channel.unix.Socket;
|
||||||
import io.netty.util.internal.NativeLibraryLoader;
|
import io.netty.util.internal.NativeLibraryLoader;
|
||||||
import io.netty.util.internal.PlatformDependent;
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
import io.netty.util.internal.ThrowableUtil;
|
import io.netty.util.internal.ThrowableUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.channels.Selector;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
final class Native {
|
import static io.netty.channel.unix.Socket.isIPv6Preferred;
|
||||||
|
|
||||||
|
|
||||||
|
final class Native {
|
||||||
private static final int DEFAULT_RING_SIZE = SystemPropertyUtil.getInt("io.netty.uring.ringSize", 32);
|
private static final int DEFAULT_RING_SIZE = SystemPropertyUtil.getInt("io.netty.uring.ringSize", 32);
|
||||||
static {
|
|
||||||
loadNativeLibrary();
|
static {
|
||||||
|
Selector selector = null;
|
||||||
|
try {
|
||||||
|
// We call Selector.open() as this will under the hood cause IOUtil to be loaded.
|
||||||
|
// This is a workaround for a possible classloader deadlock that could happen otherwise:
|
||||||
|
//
|
||||||
|
// See https://github.com/netty/netty/issues/10187
|
||||||
|
selector = Selector.open();
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
// Just ignore
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
// First, try calling a side-effect free JNI method to see if the library was already
|
||||||
|
// loaded by the application.
|
||||||
|
Native.createFile();
|
||||||
|
} catch (UnsatisfiedLinkError ignore) {
|
||||||
|
// The library was not previously loaded, load it now.
|
||||||
|
loadNativeLibrary();
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (selector != null) {
|
||||||
|
selector.close();
|
||||||
|
}
|
||||||
|
} catch (IOException ignore) {
|
||||||
|
// Just ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
Socket.initialize();
|
Socket.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,11 +88,17 @@ final class Native {
|
|||||||
return new FileDescriptor(eventFd());
|
return new FileDescriptor(eventFd());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static native void ioUringExit(RingBuffer ringBuffer);
|
||||||
|
|
||||||
private static native int eventFd();
|
private static native int eventFd();
|
||||||
|
|
||||||
// for testing(it is only temporary)
|
// for testing(it is only temporary)
|
||||||
public static native int createFile();
|
public static native int createFile();
|
||||||
|
|
||||||
|
public static Socket newSocketStream() {
|
||||||
|
return Socket.newSocketStream();
|
||||||
|
}
|
||||||
|
|
||||||
private Native() {
|
private Native() {
|
||||||
// utility
|
// utility
|
||||||
}
|
}
|
||||||
|
@ -33,4 +33,8 @@ final class RingBuffer {
|
|||||||
return this.ioUringCompletionQueue;
|
return this.ioUringCompletionQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
Native.ioUringExit(this);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,35 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2020 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.channel.uring;
|
||||||
|
|
||||||
|
import io.netty.channel.unix.Socket;
|
||||||
|
import io.netty.channel.unix.tests.SocketTest;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
|
public class IOUringSocketTest extends SocketTest<Socket> {
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void loadJNI() {
|
||||||
|
assumeTrue(IOUring.isAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Socket newSocket() {
|
||||||
|
return Socket.newSocketStream();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user