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 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) {
|
||||
munmap(sq->ring_ptr, sq->ring_sz);
|
||||
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) {
|
||||
return socket(domain, type, protocol);
|
||||
}
|
||||
@ -261,13 +313,10 @@ static jint netty_create_file(JNIEnv *env, jclass class) {
|
||||
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
|
||||
static const JNINativeMethod method_table[] = {
|
||||
{"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},
|
||||
{"ioUringEnter", "(IIII)I", (void *)netty_io_uring_enter},
|
||||
{"eventFd", "()I", (void *) netty_epoll_native_eventFd},
|
||||
@ -280,6 +329,12 @@ static const jint method_table_size =
|
||||
// JNI Method Registration Table End
|
||||
|
||||
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;
|
||||
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) {
|
||||
goto done;
|
||||
}
|
||||
limitsOnLoadCalled = 1;
|
||||
|
||||
if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
||||
goto done;
|
||||
}
|
||||
errorsOnLoadCalled = 1;
|
||||
|
||||
if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
||||
goto done;
|
||||
}
|
||||
filedescriptorOnLoadCalled = 1;
|
||||
|
||||
if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
||||
goto done;
|
||||
}
|
||||
socketOnLoadCalled = 1;
|
||||
|
||||
if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
|
||||
goto done;
|
||||
}
|
||||
bufferOnLoadCalled = 1;
|
||||
|
||||
NETTY_PREPEND(packagePrefix, "io/netty/channel/uring/RingBuffer",
|
||||
nettyClassName, done);
|
||||
@ -354,9 +414,45 @@ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
NETTY_GET_METHOD(env, ioUringCompletionQueueClass,
|
||||
ioUringCommpletionQueueMethodId, "<init>", "(JJJJJJIJI)V",
|
||||
done);
|
||||
|
||||
ret = NETTY_JNI_VERSION;
|
||||
done:
|
||||
//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;
|
||||
|
||||
import io.netty.channel.DefaultFileRegion;
|
||||
import io.netty.channel.unix.FileDescriptor;
|
||||
import io.netty.channel.unix.PeerCredentials;
|
||||
import io.netty.channel.unix.Socket;
|
||||
import io.netty.util.internal.NativeLibraryLoader;
|
||||
import io.netty.util.internal.PlatformDependent;
|
||||
import io.netty.util.internal.SystemPropertyUtil;
|
||||
import io.netty.util.internal.ThrowableUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.channels.Selector;
|
||||
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);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@ -55,11 +88,17 @@ final class Native {
|
||||
return new FileDescriptor(eventFd());
|
||||
}
|
||||
|
||||
public static native void ioUringExit(RingBuffer ringBuffer);
|
||||
|
||||
private static native int eventFd();
|
||||
|
||||
// for testing(it is only temporary)
|
||||
public static native int createFile();
|
||||
|
||||
public static Socket newSocketStream() {
|
||||
return Socket.newSocketStream();
|
||||
}
|
||||
|
||||
private Native() {
|
||||
// utility
|
||||
}
|
||||
|
@ -33,4 +33,8 @@ final class RingBuffer {
|
||||
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