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:
Josef Grieb 2020-08-20 10:15:16 +02:00
parent bf6a14effb
commit 1117c6fdb8
5 changed files with 253 additions and 11 deletions

View File

@ -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);
} }

View File

@ -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() {
}
}

View File

@ -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 { 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(); 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
} }

View File

@ -33,4 +33,8 @@ final class RingBuffer {
return this.ioUringCompletionQueue; return this.ioUringCompletionQueue;
} }
public void close() {
Native.ioUringExit(this);
}
} }

View File

@ -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();
}
}