First running prototype 🎉

Motivation:
missing eventLoop completionQueue logic

Modification:
-mapping between channel and eventloop
-added new prototype blocking example

Result:
First running prototype
This commit is contained in:
Josef Grieb 2020-07-20 22:43:40 +02:00
parent 339d5f1565
commit 8c9b874a2d
33 changed files with 697 additions and 325 deletions

View File

@ -471,18 +471,6 @@ public final class PlatformDependent {
return new ConcurrentHashMap<K, V>(map); return new ConcurrentHashMap<K, V>(map);
} }
public static void loadFence() {
PlatformDependent0.loadFence();
}
public static void storeFence() {
PlatformDependent0.storeFence();
}
public static void fullFence() {
PlatformDependent0.fullFence();
}
/** /**
* Try to deallocate the specified direct {@link ByteBuffer}. Please note this method does nothing if * Try to deallocate the specified direct {@link ByteBuffer}. Please note this method does nothing if
* the current platform does not support this operation or the specified buffer is not a direct buffer. * the current platform does not support this operation or the specified buffer is not a direct buffer.
@ -523,6 +511,14 @@ public final class PlatformDependent {
return PlatformDependent0.getInt(address); return PlatformDependent0.getInt(address);
} }
public static int getIntVolatalile(long address) {
return PlatformDependent0.getIntVolatile(address);
}
public static void putIntOrdered(long adddress, int newValue) {
PlatformDependent0.putIntOrdered(adddress, newValue);
}
public static long getLong(long address) { public static long getLong(long address) {
return PlatformDependent0.getLong(address); return PlatformDependent0.getLong(address);
} }

View File

@ -529,6 +529,14 @@ final class PlatformDependent0 {
return UNSAFE.getInt(address); return UNSAFE.getInt(address);
} }
static int getIntVolatile(long address) {
return UNSAFE.getIntVolatile(null, address);
}
static void putIntOrdered(long adddress, int newValue) {
UNSAFE.putOrderedInt(null, adddress, newValue);
}
static long getLong(long address) { static long getLong(long address) {
return UNSAFE.getLong(address); return UNSAFE.getLong(address);
} }

View File

@ -43,6 +43,13 @@
<artifactId>netty-buffer</artifactId> <artifactId>netty-buffer</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netty-transport-native-io_uring</artifactId>
<version>${project.version}</version>
<classifier>linux-x86_64</classifier>
</dependency>
<dependency> <dependency>
<groupId>${project.groupId}</groupId> <groupId>${project.groupId}</groupId>
<artifactId>netty-transport</artifactId> <artifactId>netty-transport</artifactId>

View File

@ -0,0 +1,65 @@
/*
* 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.example.uring;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.uring.IOUringEventLoopGroup;
import io.netty.channel.uring.IOUringServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
//temporary prototype example
public class EchoIOUringServer {
private static final int PORT = Integer.parseInt(System.getProperty("port", "8080"));
public static void main(String []args) {
EventLoopGroup bossGroup = new IOUringEventLoopGroup(1);
EventLoopGroup workerGroup = new IOUringEventLoopGroup(1);
final EchoIOUringServerHandler serverHandler = new EchoIOUringServerHandler();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(IOUringServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
//p.addLast(new LoggingHandler(LogLevel.INFO));
p.addLast(serverHandler);
}
});
// Start the server.
ChannelFuture f = b.bind(PORT).sync();
// Wait until the server socket is closed.
f.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// Shut down all event loops to terminate all threads.
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

View File

@ -0,0 +1,43 @@
/*
* 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.example.uring;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
//temporary prototype example
@Sharable
public class EchoIOUringServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ctx.write(msg);
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// Close the connection when an exception is raised.
cause.printStackTrace();
ctx.close();
}
}

View File

@ -1,5 +1,6 @@
#!/bin/bash -e #!/bin/bash -e
EXAMPLE_MAP=( EXAMPLE_MAP=(
'uring:io.netty.example.uring.EchoIOUringServer'
'discard-client:io.netty.example.discard.DiscardClient' 'discard-client:io.netty.example.discard.DiscardClient'
'discard-server:io.netty.example.discard.DiscardServer' 'discard-server:io.netty.example.discard.DiscardServer'
'echo-client:io.netty.example.echo.EchoClient' 'echo-client:io.netty.example.echo.EchoClient'

View File

@ -565,7 +565,7 @@ static JNINativeMethod* createDynamicMethodsTable(const char* packagePrefix) {
} }
memset(dynamicMethods, 0, size); memset(dynamicMethods, 0, size);
memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table)); memcpy(dynamicMethods, fixed_method_table, sizeof(fixed_method_table));
JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size]; JNINativeMethod* dynamicMethod = &dynamicMethods[fixed_method_table_size];
NETTY_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;II)I", dynamicTypeName, error); NETTY_PREPEND(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket;II)I", dynamicTypeName, error);
NETTY_PREPEND("(IZ[L", dynamicTypeName, dynamicMethod->signature, error); NETTY_PREPEND("(IZ[L", dynamicTypeName, dynamicMethod->signature, error);

View File

@ -1,9 +1,27 @@
/* SPDX-License-Identifier: MIT */ /*
* 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.
*/
#include <linux/io_uring.h> #include <linux/io_uring.h>
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include "netty_unix_errors.h"
#include "netty_unix_filedescriptor.h"
#include "netty_unix_jni.h"
#include "netty_unix_socket.h"
#include "netty_unix_util.h"
#ifndef LIB_TEST #ifndef LIB_TEST
#define LIB_TEST #define LIB_TEST

View File

@ -1,10 +1,20 @@
/*
* 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.
*/
#define _GNU_SOURCE // RTLD_DEFAULT #define _GNU_SOURCE // RTLD_DEFAULT
#include "io_uring.h" #include "io_uring.h"
#include "netty_unix_errors.h"
#include "netty_unix_filedescriptor.h"
#include "netty_unix_jni.h"
#include "netty_unix_socket.h"
#include "netty_unix_util.h"
#include <dlfcn.h> #include <dlfcn.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>

View File

@ -1,6 +1,17 @@
/* SPDX-License-Identifier: MIT */
/* /*
* Will go away once libc support is there * 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.
*/ */
#include "syscall.h" #include "syscall.h"
#include <signal.h> #include <signal.h>

View File

@ -1,4 +1,18 @@
/* SPDX-License-Identifier: MIT */ /*
* 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.
*/
#include <linux/io_uring.h> #include <linux/io_uring.h>
#include <signal.h> #include <signal.h>
#ifndef LIBURING_SYSCALL_H #ifndef LIBURING_SYSCALL_H

View File

@ -24,8 +24,10 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelMetadata; import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelOutboundBuffer; import io.netty.channel.ChannelOutboundBuffer;
import io.netty.channel.ChannelPromise; import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelConfig;
import io.netty.channel.EventLoop; import io.netty.channel.EventLoop;
import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.RecvByteBufAllocator;
import io.netty.channel.unix.FileDescriptor;
import io.netty.channel.unix.UnixChannel; import io.netty.channel.unix.UnixChannel;
import io.netty.channel.unix.UnixChannelUtil; import io.netty.channel.unix.UnixChannelUtil;
import io.netty.util.ReferenceCountUtil; import io.netty.util.ReferenceCountUtil;
@ -36,17 +38,26 @@ import java.nio.channels.UnresolvedAddressException;
import static io.netty.util.internal.ObjectUtil.*; import static io.netty.util.internal.ObjectUtil.*;
public abstract class AbstractIOUringChannel extends AbstractChannel implements UnixChannel { abstract class AbstractIOUringChannel extends AbstractChannel implements UnixChannel {
private volatile SocketAddress local;
private static final ChannelMetadata METADATA = new ChannelMetadata(false); private static final ChannelMetadata METADATA = new ChannelMetadata(false);
final LinuxSocket socket; final LinuxSocket socket;
protected volatile boolean active; protected volatile boolean active;
boolean uringInReadyPending; boolean uringInReadyPending;
private volatile SocketAddress local;
private volatile SocketAddress remote;
AbstractIOUringChannel(final Channel parent, LinuxSocket fd) { AbstractIOUringChannel(final Channel parent, LinuxSocket fd) {
super(parent); super(parent);
this.socket = checkNotNull(fd, "fd"); this.socket = checkNotNull(fd, "fd");
this.active = true; this.active = true;
if (active) {
// Directly cache the remote and local addresses
// See https://github.com/netty/netty/issues/2359
this.local = fd.localAddress();
this.remote = fd.remoteAddress();
}
} }
public boolean isOpen() { public boolean isOpen() {
@ -63,6 +74,11 @@ public abstract class AbstractIOUringChannel extends AbstractChannel implements
return METADATA; return METADATA;
} }
@Override
public FileDescriptor fd() {
return socket;
}
@Override @Override
protected abstract AbstractUringUnsafe newUnsafe(); protected abstract AbstractUringUnsafe newUnsafe();
@ -86,6 +102,8 @@ public abstract class AbstractIOUringChannel extends AbstractChannel implements
event.setAbstractIOUringChannel(this); event.setAbstractIOUringChannel(this);
submissionQueue.add(eventId, EventType.READ, socket.getFd(), byteBuf.memoryAddress(), submissionQueue.add(eventId, EventType.READ, socket.getFd(), byteBuf.memoryAddress(),
byteBuf.writerIndex(), byteBuf.capacity()); byteBuf.writerIndex(), byteBuf.capacity());
ioUringEventLoop.addNewEvent(event);
submissionQueue.submit();
} }
} }
@ -128,6 +146,7 @@ public abstract class AbstractIOUringChannel extends AbstractChannel implements
@Override @Override
protected void doClose() throws Exception { protected void doClose() throws Exception {
socket.close();
} }
// Channel/ChannelHandlerContext.read() was called // Channel/ChannelHandlerContext.read() was called
@ -140,9 +159,15 @@ public abstract class AbstractIOUringChannel extends AbstractChannel implements
} }
} }
public void executeReadEvent() {
final AbstractUringUnsafe unsafe = (AbstractUringUnsafe) unsafe();
unsafe.executeUringReadOperator();
}
@Override @Override
protected void doWrite(ChannelOutboundBuffer in) throws Exception { protected void doWrite(ChannelOutboundBuffer in) throws Exception {
if (in.size() == 1) { //Todo write until there is nothing left in the buffer
if (in.size() >= 1) {
Object msg = in.current(); Object msg = in.current();
if (msg instanceof ByteBuf) { if (msg instanceof ByteBuf) {
doWriteBytes((ByteBuf) msg); doWriteBytes((ByteBuf) msg);
@ -150,7 +175,7 @@ public abstract class AbstractIOUringChannel extends AbstractChannel implements
} }
} }
protected final void doWriteBytes(ByteBuf buf) throws Exception { protected final void doWriteBytes(ByteBuf buf) {
if (buf.hasMemoryAddress()) { if (buf.hasMemoryAddress()) {
IOUringEventLoop ioUringEventLoop = (IOUringEventLoop) eventLoop(); IOUringEventLoop ioUringEventLoop = (IOUringEventLoop) eventLoop();
IOUringSubmissionQueue submissionQueue = ioUringEventLoop.getRingBuffer().getIoUringSubmissionQueue(); IOUringSubmissionQueue submissionQueue = ioUringEventLoop.getRingBuffer().getIoUringSubmissionQueue();
@ -161,6 +186,8 @@ public abstract class AbstractIOUringChannel extends AbstractChannel implements
event.setAbstractIOUringChannel(this); event.setAbstractIOUringChannel(this);
submissionQueue.add(eventId, EventType.WRITE, socket.getFd(), buf.memoryAddress(), buf.readerIndex(), submissionQueue.add(eventId, EventType.WRITE, socket.getFd(), buf.memoryAddress(), buf.readerIndex(),
buf.writerIndex()); buf.writerIndex());
ioUringEventLoop.addNewEvent(event);
submissionQueue.submit();
} }
} }
@ -174,26 +201,23 @@ public abstract class AbstractIOUringChannel extends AbstractChannel implements
} }
}; };
/** IOUringRecvByteAllocatorHandle newIOUringHandle(RecvByteBufAllocator.ExtendedHandle handle) {
* Create a new {@link } instance.
*
* @param handle The handle to wrap with EPOLL specific logic.
*/
IOUringRecvByteAllocatorHandle newEpollHandle(RecvByteBufAllocator.ExtendedHandle handle) {
return new IOUringRecvByteAllocatorHandle(handle); return new IOUringRecvByteAllocatorHandle(handle);
} }
@Override @Override
public IOUringRecvByteAllocatorHandle recvBufAllocHandle() { public IOUringRecvByteAllocatorHandle recvBufAllocHandle() {
if (allocHandle == null) { if (allocHandle == null) {
allocHandle = newEpollHandle((RecvByteBufAllocator.ExtendedHandle) super.recvBufAllocHandle()); allocHandle = newIOUringHandle((RecvByteBufAllocator.ExtendedHandle) super.recvBufAllocHandle());
} }
return allocHandle; return allocHandle;
} }
//Todo
@Override @Override
public void connect(final SocketAddress remoteAddress, final SocketAddress localAddress, public void connect(final SocketAddress remoteAddress, final SocketAddress localAddress,
final ChannelPromise promise) { final ChannelPromise promise) {
promise.setFailure(new Exception());
} }
final void executeUringReadOperator() { final void executeUringReadOperator() {
@ -217,7 +241,7 @@ public abstract class AbstractIOUringChannel extends AbstractChannel implements
} }
@Override @Override
public void doBind(final SocketAddress localAddress) throws Exception { public void doBind(final SocketAddress local) throws Exception {
if (local instanceof InetSocketAddress) { if (local instanceof InetSocketAddress) {
checkResolvable((InetSocketAddress) local); checkResolvable((InetSocketAddress) local);
} }
@ -236,15 +260,15 @@ public abstract class AbstractIOUringChannel extends AbstractChannel implements
@Override @Override
protected SocketAddress localAddress0() { protected SocketAddress localAddress0() {
return null; return local;
} }
@Override @Override
protected SocketAddress remoteAddress0() { protected SocketAddress remoteAddress0() {
return null; return remote;
} }
public LinuxSocket getSocket() { public LinuxSocket getSocket() {
return socket; return socket;
} }
} }

View File

@ -16,19 +16,15 @@
package io.netty.channel.uring; package io.netty.channel.uring;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelOutboundBuffer; import io.netty.channel.ChannelOutboundBuffer;
import io.netty.channel.ChannelPromise; import io.netty.channel.ChannelPromise;
import io.netty.channel.ServerChannel; import io.netty.channel.ServerChannel;
import io.netty.channel.unix.FileDescriptor;
import java.net.SocketAddress; import java.net.SocketAddress;
public abstract class AbstractIOUringServerChannel extends AbstractIOUringChannel implements ServerChannel { abstract class AbstractIOUringServerChannel extends AbstractIOUringChannel implements ServerChannel {
private volatile SocketAddress local; AbstractIOUringServerChannel(int fd) {
AbstractIOUringServerChannel(int fd) {
super(null, new LinuxSocket(fd)); super(null, new LinuxSocket(fd));
} }
@ -41,31 +37,16 @@ public abstract class AbstractIOUringServerChannel extends AbstractIOUringChanne
return new UringServerChannelUnsafe(); return new UringServerChannelUnsafe();
} }
@Override
protected SocketAddress localAddress0() {
return null;
}
@Override
protected SocketAddress remoteAddress0() {
return null;
}
@Override @Override
protected void doWrite(ChannelOutboundBuffer in) throws Exception { protected void doWrite(ChannelOutboundBuffer in) throws Exception {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override
public FileDescriptor fd() {
return null;
}
public AbstractIOUringChannel getChannel() { public AbstractIOUringChannel getChannel() {
return this; return this;
} }
abstract Channel newChildChannel(int fd, IOUringSubmissionQueue submissionQueue) throws Exception; abstract Channel newChildChannel(int fd) throws Exception;
final class UringServerChannelUnsafe extends AbstractIOUringChannel.AbstractUringUnsafe { final class UringServerChannelUnsafe extends AbstractIOUringChannel.AbstractUringUnsafe {
private final byte[] acceptedAddress = new byte[26]; private final byte[] acceptedAddress = new byte[26];
@ -87,9 +68,11 @@ public abstract class AbstractIOUringServerChannel extends AbstractIOUringChanne
event.setOp(EventType.ACCEPT); event.setOp(EventType.ACCEPT);
event.setAbstractIOUringChannel(getChannel()); event.setAbstractIOUringChannel(getChannel());
//todo get network addresses //Todo get network addresses
submissionQueue.add(eventId, EventType.ACCEPT, getChannel().getSocket().getFd(), 0, 0, 0); submissionQueue.add(eventId, EventType.ACCEPT, getChannel().getSocket().getFd(), 0, 0, 0);
ioUringEventLoop.addNewEvent(event); ioUringEventLoop.addNewEvent(event);
submissionQueue.submit();
} }
} }
} }

View File

@ -17,7 +17,7 @@ package io.netty.channel.uring;
import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBuf;
public class Event { final class Event {
private long id; private long id;
private ByteBuf readBuffer; private ByteBuf readBuffer;
@ -56,4 +56,3 @@ public class Event {
this.op = op; this.op = op;
} }
} }

View File

@ -15,7 +15,7 @@
*/ */
package io.netty.channel.uring; package io.netty.channel.uring;
public enum EventType { enum EventType {
ACCEPT(13), ACCEPT(13),
READ(22), READ(22),
WRITE(23); WRITE(23);

View File

@ -1,3 +1,18 @@
/*
* 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; package io.netty.channel.uring;
import io.netty.channel.Channel; import io.netty.channel.Channel;

View File

@ -21,13 +21,13 @@ public class IOUringCompletionQueue {
//these offsets are used to access specific properties //these offsets are used to access specific properties
//CQE (https://github.com/axboe/liburing/blob/master/src/include/liburing/io_uring.h#L162) //CQE (https://github.com/axboe/liburing/blob/master/src/include/liburing/io_uring.h#L162)
private final int CQE_USER_DATA_FIELD = 0; private static final int CQE_USER_DATA_FIELD = 0;
private final int CQE_RES_FIELD = 8; private static final int CQE_RES_FIELD = 8;
private final int CQE_FLAGS_FIELD = 12; private static final int CQE_FLAGS_FIELD = 12;
private final int CQE_SIZE = 16; private static final int CQE_SIZE = 16;
private final int IORING_ENTER_GETEVENTS = 1; private static final int IORING_ENTER_GETEVENTS = 1;
//these unsigned integer pointers(shared with the kernel) will be changed by the kernel //these unsigned integer pointers(shared with the kernel) will be changed by the kernel
private final long kHeadAddress; private final long kHeadAddress;
@ -55,12 +55,10 @@ public class IOUringCompletionQueue {
this.ringFd = ringFd; this.ringFd = ringFd;
} }
private IOUringCqe peek() { public IOUringCqe peek() {
long cqe = 0; long cqe = 0;
long head = toUnsignedLong(PlatformDependent.getInt(kHeadAddress)); long head = toUnsignedLong(PlatformDependent.getIntVolatalile(kHeadAddress));
//aquire memory barrier https://openjdk.java.net/jeps/171
PlatformDependent.loadFence();
if (head != toUnsignedLong(PlatformDependent.getInt(kTailAddress))) { if (head != toUnsignedLong(PlatformDependent.getInt(kTailAddress))) {
long index = head & toUnsignedLong(PlatformDependent.getInt(kringMaskAddress)); long index = head & toUnsignedLong(PlatformDependent.getInt(kringMaskAddress));
cqe = index * CQE_SIZE + completionQueueArrayAddress; cqe = index * CQE_SIZE + completionQueueArrayAddress;
@ -70,8 +68,7 @@ public class IOUringCompletionQueue {
long flags = toUnsignedLong(PlatformDependent.getInt(cqe + CQE_FLAGS_FIELD)); long flags = toUnsignedLong(PlatformDependent.getInt(cqe + CQE_FLAGS_FIELD));
//Ensure that the kernel only sees the new value of the head index after the CQEs have been read. //Ensure that the kernel only sees the new value of the head index after the CQEs have been read.
PlatformDependent.storeFence(); PlatformDependent.putIntOrdered(kHeadAddress, (int) (head + 1));
PlatformDependent.putInt(kHeadAddress, (int) (head + 1));
return new IOUringCqe(eventId, res, flags); return new IOUringCqe(eventId, res, flags);
} }

View File

@ -15,12 +15,12 @@
*/ */
package io.netty.channel.uring; package io.netty.channel.uring;
public class IOUringCqe { class IOUringCqe {
private final long eventId; private final long eventId;
private final int res; private final int res;
private final long flags; private final long flags;
public IOUringCqe(long eventId, int res, long flags) { IOUringCqe(long eventId, int res, long flags) {
this.eventId = eventId; this.eventId = eventId;
this.res = res; this.res = res;
this.flags = flags; this.flags = flags;

View File

@ -15,23 +15,22 @@
*/ */
package io.netty.channel.uring; package io.netty.channel.uring;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup; import io.netty.channel.EventLoopGroup;
import io.netty.channel.SingleThreadEventLoop; import io.netty.channel.SingleThreadEventLoop;
import io.netty.util.collection.IntObjectHashMap;
import io.netty.util.collection.IntObjectMap;
import io.netty.util.collection.LongObjectHashMap; import io.netty.util.collection.LongObjectHashMap;
import io.netty.util.concurrent.RejectedExecutionHandler;
import java.util.HashMap;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import static io.netty.channel.unix.Errors.*;
class IOUringEventLoop extends SingleThreadEventLoop { class IOUringEventLoop extends SingleThreadEventLoop {
private final IntObjectMap<AbstractIOUringChannel> channels = new IntObjectHashMap<AbstractIOUringChannel>(4096);
// events should be unique to identify which event type that was // events should be unique to identify which event type that was
private long eventIdCounter; private long eventIdCounter;
private final LongObjectHashMap<Event> events = new LongObjectHashMap<Event>(); private final LongObjectHashMap<Event> events = new LongObjectHashMap<Event>();
private final RingBuffer ringBuffer; private RingBuffer ringBuffer;
protected IOUringEventLoop(final EventLoopGroup parent, final Executor executor, final boolean addTaskWakesUp) { protected IOUringEventLoop(final EventLoopGroup parent, final Executor executor, final boolean addTaskWakesUp) {
super(parent, executor, addTaskWakesUp); super(parent, executor, addTaskWakesUp);
@ -40,6 +39,7 @@ class IOUringEventLoop extends SingleThreadEventLoop {
public long incrementEventIdCounter() { public long incrementEventIdCounter() {
long eventId = eventIdCounter; long eventId = eventIdCounter;
System.out.println(" incrementEventIdCounter EventId: " + eventId);
eventIdCounter++; eventIdCounter++;
return eventId; return eventId;
} }
@ -50,26 +50,104 @@ class IOUringEventLoop extends SingleThreadEventLoop {
@Override @Override
protected void run() { protected void run() {
//Todo
for (;;) { for (;;) {
// wait until an event has finished final IOUringCompletionQueue ioUringCompletionQueue = ringBuffer.getIoUringCompletionQueue();
//final long cqe = Native.ioUringWaitCqe(io_uring); final IOUringCqe ioUringCqe = ioUringCompletionQueue.peek(); // or waiting
//final Event event = events.get(Native.ioUringGetEventId(cqe));
//final int ret = Native.ioUringGetRes(cqe); if (ioUringCqe != null) {
// switch (event.getOp()) { final Event event = events.get(ioUringCqe.getEventId());
// case ACCEPT: System.out.println("Completion EventId: " + ioUringCqe.getEventId());
// // serverChannel is necessary to call newChildchannel
// // create a new accept event if (event != null) {
// break; switch (event.getOp()) {
// case READ: case ACCEPT:
// // need to save the Bytebuf before I execute the read operation System.out.println("EventLoop Accept Res: " + ioUringCqe.getRes());
// // fireChannelRead(byteBuf) if (ioUringCqe.getRes() != -1 && ioUringCqe.getRes() != ERRNO_EAGAIN_NEGATIVE &&
// break; ioUringCqe.getRes() != ERRNO_EWOULDBLOCK_NEGATIVE) {
// case WRITE: AbstractIOUringServerChannel abstractIOUringServerChannel =
// // you have to store Bytebuf to continue writing (AbstractIOUringServerChannel) event.getAbstractIOUringChannel();
// break; System.out.println("EventLoop Fd: " + abstractIOUringServerChannel.getSocket().getFd());
// } final IOUringRecvByteAllocatorHandle allocHandle =
// processing Tasks (IOUringRecvByteAllocatorHandle) event.getAbstractIOUringChannel().unsafe()
.recvBufAllocHandle();
final ChannelPipeline pipeline = event.getAbstractIOUringChannel().pipeline();
allocHandle.lastBytesRead(ioUringCqe.getRes());
if (allocHandle.lastBytesRead() != -1) {
allocHandle.incMessagesRead(1);
try {
pipeline.fireChannelRead(abstractIOUringServerChannel
.newChildChannel(allocHandle.lastBytesRead()));
} catch (Exception e) {
e.printStackTrace();
}
allocHandle.readComplete();
pipeline.fireChannelReadComplete();
}
}
long eventId = incrementEventIdCounter();
event.setId(eventId);
ringBuffer.getIoUringSubmissionQueue()
.add(eventId, EventType.ACCEPT, event.getAbstractIOUringChannel().getSocket().getFd(),
0,
0,
0);
addNewEvent(event);
ringBuffer.getIoUringSubmissionQueue().submit();
break;
case READ:
System.out.println("Eventlloop Read Res: " + ioUringCqe.getRes());
System.out.println("Eventloop Fd: " + event.getAbstractIOUringChannel().getSocket().getFd());
ByteBuf byteBuf = event.getReadBuffer();
int localReadAmount = ioUringCqe.getRes();
if (localReadAmount > 0) {
byteBuf.writerIndex(byteBuf.writerIndex() + localReadAmount);
}
final IOUringRecvByteAllocatorHandle allocHandle =
(IOUringRecvByteAllocatorHandle) event.getAbstractIOUringChannel().unsafe()
.recvBufAllocHandle();
final ChannelPipeline pipeline = event.getAbstractIOUringChannel().pipeline();
allocHandle.lastBytesRead(localReadAmount);
if (allocHandle.lastBytesRead() <= 0) {
// nothing was read, release the buffer.
byteBuf.release();
byteBuf = null;
break;
}
allocHandle.incMessagesRead(1);
//readPending = false;
pipeline.fireChannelRead(byteBuf);
byteBuf = null;
allocHandle.readComplete();
pipeline.fireChannelReadComplete();
event.getAbstractIOUringChannel().executeReadEvent();
break;
case WRITE:
System.out.println("Eventloop Write Res: " + ioUringCqe.getRes());
System.out.println("Eventloop Fd: " + event.getAbstractIOUringChannel().getSocket().getFd());
//remove bytes
int localFlushAmount = ioUringCqe.getRes();
if (localFlushAmount > 0) {
event.getAbstractIOUringChannel().unsafe().outboundBuffer().removeBytes(localFlushAmount);
}
break;
}
} else {
System.out.println("Event is null!!!! ");
}
}
//run tasks
if (hasTasks()) {
runAllTasks();
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
} }
} }

View File

@ -27,31 +27,41 @@ import io.netty.util.concurrent.RejectedExecutionHandlers;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadFactory;
public class IOUringEventLoopGroup extends MultithreadEventLoopGroup { public final class IOUringEventLoopGroup extends MultithreadEventLoopGroup {
/**
* Create a new instance using the default number of threads and the default {@link ThreadFactory}.
*/
public IOUringEventLoopGroup() { public IOUringEventLoopGroup() {
this(0); this(0);
} }
/**
* Create a new instance using the specified number of threads and the default {@link ThreadFactory}.
*/
public IOUringEventLoopGroup(int nThreads) { public IOUringEventLoopGroup(int nThreads) {
this(nThreads, (ThreadFactory) null); this(nThreads, (ThreadFactory) null);
} }
/**
* Create a new instance using the default number of threads and the given {@link ThreadFactory}.
*/
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public IOUringEventLoopGroup(ThreadFactory threadFactory) { public IOUringEventLoopGroup(ThreadFactory threadFactory) {
this(0, threadFactory, 0); this(0, threadFactory, 0);
} }
/**
* Create a new instance using the specified number of threads and the default {@link ThreadFactory}.
*/
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public IOUringEventLoopGroup(int nThreads, SelectStrategyFactory selectStrategyFactory) { public IOUringEventLoopGroup(int nThreads, SelectStrategyFactory selectStrategyFactory) {
this(nThreads, (ThreadFactory) null, selectStrategyFactory); this(nThreads, (ThreadFactory) null, selectStrategyFactory);
} }
/**
* Create a new instance using the specified number of threads and the given {@link ThreadFactory}.
*/
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public IOUringEventLoopGroup(int nThreads, ThreadFactory threadFactory) { public IOUringEventLoopGroup(int nThreads, ThreadFactory threadFactory) {
this(nThreads, threadFactory, 0); this(nThreads, threadFactory, 0);
@ -61,17 +71,33 @@ public class IOUringEventLoopGroup extends MultithreadEventLoopGroup {
this(nThreads, executor, DefaultSelectStrategyFactory.INSTANCE); this(nThreads, executor, DefaultSelectStrategyFactory.INSTANCE);
} }
/**
* Create a new instance using the specified number of threads and the given {@link ThreadFactory}.
*/
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
public IOUringEventLoopGroup(int nThreads, ThreadFactory threadFactory, public IOUringEventLoopGroup(int nThreads, ThreadFactory threadFactory,
SelectStrategyFactory selectStrategyFactory) { SelectStrategyFactory selectStrategyFactory) {
this(nThreads, threadFactory, 0, selectStrategyFactory); this(nThreads, threadFactory, 0, selectStrategyFactory);
} }
/**
* Create a new instance using the specified number of threads, the given {@link ThreadFactory} and the given
* maximal amount of epoll events to handle per epollWait(...).
*
* @deprecated Use {@link #IOUringEventLoopGroup(int)} or {@link #IOUringEventLoopGroup(int, ThreadFactory)}
*/
@Deprecated @Deprecated
public IOUringEventLoopGroup(int nThreads, ThreadFactory threadFactory, int maxEventsAtOnce) { public IOUringEventLoopGroup(int nThreads, ThreadFactory threadFactory, int maxEventsAtOnce) {
this(nThreads, threadFactory, maxEventsAtOnce, DefaultSelectStrategyFactory.INSTANCE); this(nThreads, threadFactory, maxEventsAtOnce, DefaultSelectStrategyFactory.INSTANCE);
} }
/**
* Create a new instance using the specified number of threads, the given {@link ThreadFactory} and the given
* maximal amount of epoll events to handle per epollWait(...).
*
* @deprecated Use {@link #IOUringEventLoopGroup(int)}, {@link #IOUringEventLoopGroup(int, ThreadFactory)}, or
* {@link #IOUringEventLoopGroup(int, SelectStrategyFactory)}
*/
@Deprecated @Deprecated
public IOUringEventLoopGroup(int nThreads, ThreadFactory threadFactory, int maxEventsAtOnce, public IOUringEventLoopGroup(int nThreads, ThreadFactory threadFactory, int maxEventsAtOnce,
SelectStrategyFactory selectStrategyFactory) { SelectStrategyFactory selectStrategyFactory) {
@ -101,6 +127,9 @@ public class IOUringEventLoopGroup extends MultithreadEventLoopGroup {
selectStrategyFactory, rejectedExecutionHandler, queueFactory); selectStrategyFactory, rejectedExecutionHandler, queueFactory);
} }
/**
* @deprecated This method will be removed in future releases, and is not guaranteed to have any impacts.
*/
@Deprecated @Deprecated
public void setIoRatio(int ioRatio) { public void setIoRatio(int ioRatio) {
if (ioRatio <= 0 || ioRatio > 100) { if (ioRatio <= 0 || ioRatio > 100) {
@ -108,9 +137,14 @@ public class IOUringEventLoopGroup extends MultithreadEventLoopGroup {
} }
} }
//Todo
@Override @Override
protected EventLoop newChild(Executor executor, Object... args) throws Exception { protected EventLoop newChild(Executor executor, Object... args) throws Exception {
//EventLoopTaskQueueFactory queueFactory = args.length == 4? (EventLoopTaskQueueFactory) args[3] : null; //EventLoopTaskQueueFactory queueFactory = args.length == 4? (EventLoopTaskQueueFactory) args[3] : null;
// return new IOUringEventLoop(this, executor, (Integer) args[0],
// ((SelectStrategyFactory) args[1]).newSelectStrategy(),
// (RejectedExecutionHandler) args[2], queueFactory);
return new IOUringEventLoop(this, executor, false); return new IOUringEventLoop(this, executor, false);
} }
} }

View File

@ -21,7 +21,7 @@ import io.netty.channel.RecvByteBufAllocator;
import io.netty.channel.unix.PreferredDirectByteBufAllocator; import io.netty.channel.unix.PreferredDirectByteBufAllocator;
import io.netty.util.UncheckedBooleanSupplier; import io.netty.util.UncheckedBooleanSupplier;
public class IOUringRecvByteAllocatorHandle extends RecvByteBufAllocator.DelegatingHandle final class IOUringRecvByteAllocatorHandle extends RecvByteBufAllocator.DelegatingHandle
implements RecvByteBufAllocator.ExtendedHandle { implements RecvByteBufAllocator.ExtendedHandle {
private final PreferredDirectByteBufAllocator preferredDirectByteBufAllocator = private final PreferredDirectByteBufAllocator preferredDirectByteBufAllocator =
new PreferredDirectByteBufAllocator(); new PreferredDirectByteBufAllocator();
@ -37,19 +37,19 @@ public class IOUringRecvByteAllocatorHandle extends RecvByteBufAllocator.Delegat
} }
@Override @Override
public final ByteBuf allocate(ByteBufAllocator alloc) { public ByteBuf allocate(ByteBufAllocator alloc) {
// We need to ensure we always allocate a direct ByteBuf as we can only use a direct buffer to read via JNI. // We need to ensure we always allocate a direct ByteBuf as we can only use a direct buffer to read via JNI.
preferredDirectByteBufAllocator.updateAllocator(alloc); preferredDirectByteBufAllocator.updateAllocator(alloc);
return delegate().allocate(preferredDirectByteBufAllocator); return delegate().allocate(preferredDirectByteBufAllocator);
} }
@Override @Override
public final boolean continueReading(UncheckedBooleanSupplier maybeMoreDataSupplier) { public boolean continueReading(UncheckedBooleanSupplier maybeMoreDataSupplier) {
return ((RecvByteBufAllocator.ExtendedHandle) delegate()).continueReading(maybeMoreDataSupplier); return ((RecvByteBufAllocator.ExtendedHandle) delegate()).continueReading(maybeMoreDataSupplier);
} }
@Override @Override
public final boolean continueReading() { public boolean continueReading() {
return false; return false;
} }
} }

View File

@ -1,3 +1,18 @@
/*
* 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; package io.netty.channel.uring;
import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufAllocator;

View File

@ -17,6 +17,7 @@ package io.netty.channel.uring;
import io.netty.channel.Channel; import io.netty.channel.Channel;
import io.netty.channel.socket.ServerSocketChannel; import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.unix.FileDescriptor;
import io.netty.channel.unix.Socket; import io.netty.channel.unix.Socket;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -26,29 +27,17 @@ public class IOUringServerSocketChannel extends AbstractIOUringServerChannel imp
private final IOUringServerSocketChannelConfig config; private final IOUringServerSocketChannelConfig config;
public IOUringServerSocketChannel() { public IOUringServerSocketChannel() {
super(Socket.newSocketStream().getFd()); super(Socket.newSocketStreamBlocking().getFd());
this.config = new IOUringServerSocketChannelConfig(this); this.config = new IOUringServerSocketChannelConfig(this);
} }
@Override
public void doBind(SocketAddress localAddress) throws Exception {
super.doBind(localAddress);
}
@Override @Override
public IOUringServerSocketChannelConfig config() { public IOUringServerSocketChannelConfig config() {
return config; return config;
} }
@Override @Override
public boolean isOpen() { Channel newChildChannel(int fd) throws Exception {
return false;
}
@Override
Channel newChildChannel(int fd, IOUringSubmissionQueue submissionQueue) throws Exception {
return new IOUringSocketChannel(this, new LinuxSocket(fd)); return new IOUringSocketChannel(this, new LinuxSocket(fd));
} }
@ -66,4 +55,16 @@ public class IOUringServerSocketChannel extends AbstractIOUringServerChannel imp
public InetSocketAddress localAddress() { public InetSocketAddress localAddress() {
return (InetSocketAddress) super.localAddress(); return (InetSocketAddress) super.localAddress();
} }
}
@Override
public void doBind(SocketAddress localAddress) throws Exception {
super.doBind(localAddress);
socket.listen(500);
active = true;
}
@Override
public FileDescriptor fd() {
return super.fd();
}
}

View File

@ -1,3 +1,18 @@
/*
* 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; package io.netty.channel.uring;
import io.netty.channel.socket.ServerSocketChannelConfig; import io.netty.channel.socket.ServerSocketChannelConfig;

View File

@ -21,7 +21,9 @@ import io.netty.channel.Channel;
import io.netty.channel.ChannelConfig; import io.netty.channel.ChannelConfig;
import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelPromise; import io.netty.channel.ChannelPromise;
import io.netty.channel.DefaultChannelConfig;
import io.netty.channel.RecvByteBufAllocator; import io.netty.channel.RecvByteBufAllocator;
import io.netty.channel.socket.DefaultSocketChannelConfig;
import io.netty.channel.socket.ServerSocketChannel; import io.netty.channel.socket.ServerSocketChannel;
import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.SocketChannelConfig; import io.netty.channel.socket.SocketChannelConfig;
@ -43,11 +45,6 @@ public class IOUringSocketChannel extends AbstractIOUringChannel implements Sock
return (ServerSocketChannel) super.parent(); return (ServerSocketChannel) super.parent();
} }
@Override
public IOUringSocketChannelConfig config() {
return config;
}
@Override @Override
protected AbstractUringUnsafe newUnsafe() { protected AbstractUringUnsafe newUnsafe() {
return new AbstractUringUnsafe() { return new AbstractUringUnsafe() {
@ -67,7 +64,8 @@ public class IOUringSocketChannel extends AbstractIOUringChannel implements Sock
} }
@Override @Override
public void doBind(SocketAddress localAddress) throws Exception { public IOUringSocketChannelConfig config() {
return config;
} }
@Override @Override
@ -117,17 +115,17 @@ public class IOUringSocketChannel extends AbstractIOUringChannel implements Sock
@Override @Override
public FileDescriptor fd() { public FileDescriptor fd() {
return null; return super.fd();
} }
@Override @Override
protected SocketAddress localAddress0() { protected SocketAddress localAddress0() {
return null; return super.localAddress0();
} }
@Override @Override
protected SocketAddress remoteAddress0() { protected SocketAddress remoteAddress0() {
return null; return super.remoteAddress0();
} }
@Override @Override

View File

@ -1,3 +1,18 @@
/*
* 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; package io.netty.channel.uring;
import io.netty.buffer.ByteBufAllocator; import io.netty.buffer.ByteBufAllocator;
@ -20,7 +35,6 @@ public class IOUringSocketChannelConfig extends IOUringChannelConfig implements
super(channel); super(channel);
} }
@Override @Override
public int getReceiveBufferSize() { public int getReceiveBufferSize() {
try { try {

View File

@ -19,203 +19,208 @@ import io.netty.util.internal.PlatformDependent;
public class IOUringSubmissionQueue { public class IOUringSubmissionQueue {
private final int SQE_SIZE = 64; private static final int SQE_SIZE = 64;
private final int INT_SIZE = 4; private static final int INT_SIZE = Integer.BYTES; //no 32 Bit support?
//these offsets are used to access specific properties //these offsets are used to access specific properties
//SQE https://github.com/axboe/liburing/blob/master/src/include/liburing/io_uring.h#L21 //SQE https://github.com/axboe/liburing/blob/master/src/include/liburing/io_uring.h#L21
private final int SQE_OP_CODE_FIELD = 0; private static final int SQE_OP_CODE_FIELD = 0;
private final int SQE_FLAGS_FIELD = 1; private static final int SQE_FLAGS_FIELD = 1;
private final int SQE_IOPRIO_FIELD = 2; // u16 private static final int SQE_IOPRIO_FIELD = 2; // u16
private final int SQE_FD_FIELD = 4; // s32 private static final int SQE_FD_FIELD = 4; // s32
private final int SQE_OFFSET_FIELD = 8; private static final int SQE_OFFSET_FIELD = 8;
private final int SQE_ADDRESS_FIELD = 16; private static final int SQE_ADDRESS_FIELD = 16;
private final int SQE_LEN_FIELD = 24; private static final int SQE_LEN_FIELD = 24;
private final int SQE_RW_FLAGS_FIELD = 28; private static final int SQE_RW_FLAGS_FIELD = 28;
private final int SQE_USER_DATA_FIELD = 32; private static final int SQE_USER_DATA_FIELD = 32;
private final int SQE_PAD_FIELD = 40; private static final int SQE_PAD_FIELD = 40;
//these unsigned integer pointers(shared with the kernel) will be changed by the kernel //these unsigned integer pointers(shared with the kernel) will be changed by the kernel
private final long kHeadAddress; private final long kHeadAddress;
private final long kTailAddress; private final long kTailAddress;
private final long kRingMaskAddress; private final long kRingMaskAddress;
private final long kRingEntriesAddress; private final long kRingEntriesAddress;
private final long fFlagsAdress; private final long fFlagsAdress;
private final long kDroppedAddress; private final long kDroppedAddress;
private final long arrayAddress; private final long arrayAddress;
private final long submissionQueueArrayAddress; private final long submissionQueueArrayAddress;
private long sqeHead; private long sqeHead;
private long sqeTail; private long sqeTail;
private final int ringSize; private final int ringSize;
private final long ringAddress; private final long ringAddress;
private final int ringFd; private final int ringFd;
public IOUringSubmissionQueue(long kHeadAddress, long kTailAddress, long kRingMaskAddress, long kRingEntriesAddress, public IOUringSubmissionQueue(long kHeadAddress, long kTailAddress, long kRingMaskAddress, long kRingEntriesAddress,
long fFlagsAdress, long kDroppedAddress, long arrayAddress, long submissionQueueArrayAddress, int ringSize, long fFlagsAdress, long kDroppedAddress, long arrayAddress,
long ringAddress, int ringFd) { long submissionQueueArrayAddress, int ringSize,
this.kHeadAddress = kHeadAddress; long ringAddress, int ringFd) {
this.kTailAddress = kTailAddress; this.kHeadAddress = kHeadAddress;
this.kRingMaskAddress = kRingMaskAddress; this.kTailAddress = kTailAddress;
this.kRingEntriesAddress = kRingEntriesAddress; this.kRingMaskAddress = kRingMaskAddress;
this.fFlagsAdress = fFlagsAdress; this.kRingEntriesAddress = kRingEntriesAddress;
this.kDroppedAddress = kDroppedAddress; this.fFlagsAdress = fFlagsAdress;
this.arrayAddress = arrayAddress; this.kDroppedAddress = kDroppedAddress;
this.submissionQueueArrayAddress = submissionQueueArrayAddress; this.arrayAddress = arrayAddress;
this.ringSize = ringSize; this.submissionQueueArrayAddress = submissionQueueArrayAddress;
this.ringAddress = ringAddress; this.ringSize = ringSize;
this.ringFd = ringFd; this.ringAddress = ringAddress;
} this.ringFd = ringFd;
public long getSqe() {
long next = sqeTail + 1;
long kRingEntries = toUnsignedLong(PlatformDependent.getInt(kRingEntriesAddress));
long sqe = 0;
if ((next - sqeHead) <= kRingEntries) {
long index = sqeTail & toUnsignedLong(PlatformDependent.getInt(kRingMaskAddress));
sqe = SQE_SIZE * index + submissionQueueArrayAddress;
sqeTail = next;
}
return sqe;
}
private void setData(long sqe, long eventId, EventType type, int fd, long bufferAddress, int length, long offset) {
//Todo cleaner
//set sqe(submission queue) properties
PlatformDependent.putByte(sqe + SQE_OP_CODE_FIELD, (byte) type.getOp());
PlatformDependent.putByte(sqe + SQE_FLAGS_FIELD, (byte) 0);
PlatformDependent.putShort(sqe + SQE_IOPRIO_FIELD, (short) 0);
PlatformDependent.putInt(sqe + SQE_FD_FIELD, fd);
PlatformDependent.putLong(sqe + SQE_OFFSET_FIELD, offset);
PlatformDependent.putLong(sqe + SQE_ADDRESS_FIELD, bufferAddress);
PlatformDependent.putInt(sqe + SQE_LEN_FIELD, length);
PlatformDependent.putInt(sqe + SQE_RW_FLAGS_FIELD, 0);
PlatformDependent.putLong(sqe + SQE_USER_DATA_FIELD, eventId);
// pad field array -> all fields should be zero
long offsetIndex = 0;
for (int i = 0; i < 3; i++) {
PlatformDependent.putLong(sqe + SQE_PAD_FIELD + offsetIndex, 0);
offsetIndex += 8;
} }
System.out.println("OPField: " + PlatformDependent.getByte(sqe + SQE_OP_CODE_FIELD)); public long getSqe() {
System.out.println("UserDataField: " + PlatformDependent.getByte(sqe + SQE_USER_DATA_FIELD)); long next = sqeTail + 1;
} long kRingEntries = toUnsignedLong(PlatformDependent.getInt(kRingEntriesAddress));
long sqe = 0;
public boolean add(long eventId, EventType type, int fd, long bufferAddress, int pos, int limit) { if ((next - sqeHead) <= kRingEntries) {
long sqe = getSqe(); long index = sqeTail & toUnsignedLong(PlatformDependent.getInt(kRingMaskAddress));
if (sqe == 0) { sqe = SQE_SIZE * index + submissionQueueArrayAddress;
return false; sqeTail = next;
} }
setData(sqe, eventId, type, fd, bufferAddress + pos, limit - pos, 0); return sqe;
return true;
}
private int flushSqe() {
long kTail = toUnsignedLong(PlatformDependent.getInt(kTailAddress));
long kHead = toUnsignedLong(PlatformDependent.getInt(kHeadAddress));
long kRingMask = toUnsignedLong(PlatformDependent.getInt(kRingMaskAddress));
System.out.println("Ktail: " + kTail);
System.out.println("Ktail: " + kHead);
System.out.println("SqeHead: " + sqeHead);
System.out.println("SqeTail: " + sqeTail);
if (sqeHead == sqeTail) {
return (int) (kTail - kHead);
} }
long toSubmit = sqeTail - sqeHead; private void setData(long sqe, long eventId, EventType type, int fd, long bufferAddress, int length, long offset) {
while (toSubmit > 0) { //Todo cleaner
long index = kTail & kRingMask; //set sqe(submission queue) properties
PlatformDependent.putByte(sqe + SQE_OP_CODE_FIELD, (byte) type.getOp());
PlatformDependent.putByte(sqe + SQE_FLAGS_FIELD, (byte) 0);
PlatformDependent.putShort(sqe + SQE_IOPRIO_FIELD, (short) 0);
PlatformDependent.putInt(sqe + SQE_FD_FIELD, fd);
PlatformDependent.putLong(sqe + SQE_OFFSET_FIELD, offset);
PlatformDependent.putLong(sqe + SQE_ADDRESS_FIELD, bufferAddress);
PlatformDependent.putInt(sqe + SQE_LEN_FIELD, length);
PlatformDependent.putInt(sqe + SQE_RW_FLAGS_FIELD, 0);
PlatformDependent.putLong(sqe + SQE_USER_DATA_FIELD, eventId);
PlatformDependent.putInt(arrayAddress + index * INT_SIZE, (int) (sqeHead & kRingMask)); // pad field array -> all fields should be zero
long offsetIndex = 0;
for (int i = 0; i < 3; i++) {
PlatformDependent.putLong(sqe + SQE_PAD_FIELD + offsetIndex, 0);
offsetIndex += 8;
}
sqeHead++; System.out.println("OPField: " + PlatformDependent.getByte(sqe + SQE_OP_CODE_FIELD));
kTail++; System.out.println("UserDataField: " + PlatformDependent.getLong(sqe + SQE_USER_DATA_FIELD));
toSubmit--; System.out.println("BufferAddress: " + PlatformDependent.getLong(sqe + SQE_ADDRESS_FIELD));
System.out.println("Length: " + PlatformDependent.getInt(sqe + SQE_LEN_FIELD));
System.out.println("Offset: " + PlatformDependent.getLong(sqe + SQE_OFFSET_FIELD));
} }
//release memory barrier //Todo ring buffer errors for example if submission queue is full
PlatformDependent.storeFence(); public boolean add(long eventId, EventType type, int fd, long bufferAddress, int pos, int limit) {
long sqe = getSqe();
PlatformDependent.putInt(kTailAddress, (int) kTail); if (sqe == 0) {
return false;
return (int) (kTail - kHead); }
} System.out.println("fd " + fd);
System.out.println("BufferAddress + pos: " + (bufferAddress + pos));
public void submit() { System.out.println("limit + pos " + (limit - pos));
int submitted = flushSqe(); setData(sqe, eventId, type, fd, bufferAddress + pos, limit - pos, 0);
System.out.println("Submitted: " + submitted); return true;
int ret = Native.ioUringEnter(ringFd, submitted, 0, 0);
if (ret < 0) {
throw new RuntimeException("ioUringEnter syscall");
} }
}
public void setSqeHead(long sqeHead) { private int flushSqe() {
this.sqeHead = sqeHead; long kTail = toUnsignedLong(PlatformDependent.getInt(kTailAddress));
} long kHead = toUnsignedLong(PlatformDependent.getIntVolatalile(kHeadAddress));
long kRingMask = toUnsignedLong(PlatformDependent.getInt(kRingMaskAddress));
public void setSqeTail(long sqeTail) { System.out.println("Ktail: " + kTail);
this.sqeTail = sqeTail; System.out.println("Ktail: " + kHead);
} System.out.println("SqeHead: " + sqeHead);
System.out.println("SqeTail: " + sqeTail);
public long getKHeadAddress() { if (sqeHead == sqeTail) {
return this.kHeadAddress; return (int) (kTail - kHead);
} }
public long getKTailAddress() { long toSubmit = sqeTail - sqeHead;
return this.kTailAddress; while (toSubmit > 0) {
} long index = kTail & kRingMask;
public long getKRingMaskAddress() { PlatformDependent.putInt(arrayAddress + index * INT_SIZE, (int) (sqeHead & kRingMask));
return this.kRingMaskAddress;
}
public long getKRingEntriesAddress() { sqeHead++;
return this.kRingEntriesAddress; kTail++;
} toSubmit--;
}
public long getFFlagsAdress() { PlatformDependent.putIntOrdered(kTailAddress, (int) kTail);
return this.fFlagsAdress;
}
public long getKDroppedAddress() { return (int) (kTail - kHead);
return this.kDroppedAddress; }
}
public long getArrayAddress() { public void submit() {
return this.arrayAddress; int submitted = flushSqe();
} System.out.println("Submitted: " + submitted);
public long getSubmissionQueueArrayAddress() { int ret = Native.ioUringEnter(ringFd, submitted, 0, 0);
return this.submissionQueueArrayAddress; if (ret < 0) {
} throw new RuntimeException("ioUringEnter syscall");
}
}
public long getSqeHead() { public void setSqeHead(long sqeHead) {
return this.sqeHead; this.sqeHead = sqeHead;
} }
public long getSqeTail() { public void setSqeTail(long sqeTail) {
return this.sqeTail; this.sqeTail = sqeTail;
} }
public int getRingSize() { public long getKHeadAddress() {
return this.ringSize; return this.kHeadAddress;
} }
public long getRingAddress() { public long getKTailAddress() {
return this.ringAddress; return this.kTailAddress;
} }
//Todo Integer.toUnsignedLong -> maven checkstyle error public long getKRingMaskAddress() {
public static long toUnsignedLong(int x) { return this.kRingMaskAddress;
return ((long) x) & 0xffffffffL; }
}
public long getKRingEntriesAddress() {
return this.kRingEntriesAddress;
}
public long getFFlagsAdress() {
return this.fFlagsAdress;
}
public long getKDroppedAddress() {
return this.kDroppedAddress;
}
public long getArrayAddress() {
return this.arrayAddress;
}
public long getSubmissionQueueArrayAddress() {
return this.submissionQueueArrayAddress;
}
public long getSqeHead() {
return this.sqeHead;
}
public long getSqeTail() {
return this.sqeTail;
}
public int getRingSize() {
return this.ringSize;
}
public long getRingAddress() {
return this.ringAddress;
}
//Todo Integer.toUnsignedLong -> maven checkstyle error
public static long toUnsignedLong(int x) {
return ((long) x) & 0xffffffffL;
}
} }

View File

@ -25,18 +25,7 @@ public class LinuxSocket extends Socket {
this.fd = fd; this.fd = fd;
} }
//Todo public int getFd() {
return fd;
// public int readEvent(long ring, long eventId, long bufferAddress, int pos, int limit) { }
// return Native.ioUringRead(ring, fd, eventId, bufferAddress, pos, limit);
// }
// public int writeEvent(long ring, long eventId, long bufferAddress, int pos, int limit) {
// return Native.ioUringWrite(ring, fd, eventId, bufferAddress, pos, limit);
// }
// public int acceptEvent(long ring, long eventId, byte[] addr) {
// return Native.ioUringAccept(ring, eventId, addr);
// }
} }

View File

@ -25,7 +25,6 @@ import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory; import io.netty.util.internal.logging.InternalLoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.nio.channels.Selector;
import java.util.Locale; import java.util.Locale;
public final class Native { public final class Native {
@ -33,6 +32,7 @@ public 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 {
loadNativeLibrary(); loadNativeLibrary();
Socket.initialize();
} }
public static RingBuffer createRingBuffer(int ringSize) { public static RingBuffer createRingBuffer(int ringSize) {

View File

@ -15,13 +15,12 @@
*/ */
package io.netty.channel.uring; package io.netty.channel.uring;
import io.netty.util.internal.PlatformDependent;
public class RingBuffer { class RingBuffer {
private final IOUringSubmissionQueue ioUringSubmissionQueue; private final IOUringSubmissionQueue ioUringSubmissionQueue;
private final IOUringCompletionQueue ioUringCompletionQueue; private final IOUringCompletionQueue ioUringCompletionQueue;
public RingBuffer(IOUringSubmissionQueue ioUringSubmissionQueue, IOUringCompletionQueue ioUringCompletionQueue) { RingBuffer(IOUringSubmissionQueue ioUringSubmissionQueue, IOUringCompletionQueue ioUringCompletionQueue) {
this.ioUringSubmissionQueue = ioUringSubmissionQueue; this.ioUringSubmissionQueue = ioUringSubmissionQueue;
this.ioUringCompletionQueue = ioUringCompletionQueue; this.ioUringCompletionQueue = ioUringCompletionQueue;
} }

View File

@ -15,6 +15,7 @@
*/ */
package io.netty.channel.uring; package io.netty.channel.uring;
import io.netty.channel.unix.Socket;
import org.junit.Test; import org.junit.Test;
import java.io.FileInputStream; import java.io.FileInputStream;

View File

@ -69,6 +69,11 @@ static int nettyNonBlockingSocket(int domain, int type, int protocol) {
#endif #endif
} }
//only temporary
static int nettyBlockingSocket(int domain, int type, int protocol) {
return socket(domain, type, protocol);
}
int netty_unix_socket_ipAddressLength(const struct sockaddr_storage* addr) { int netty_unix_socket_ipAddressLength(const struct sockaddr_storage* addr) {
if (addr->ss_family == AF_INET) { if (addr->ss_family == AF_INET) {
return 4; return 4;
@ -613,6 +618,17 @@ static jint netty_unix_socket_newSocketStreamFd(JNIEnv* env, jclass clazz, jbool
return _socket(env, clazz, domain, SOCK_STREAM); return _socket(env, clazz, domain, SOCK_STREAM);
} }
//only temporary
static jint netty_unix_socket_newSocketStreamFd_blocking(JNIEnv* env, jclass clazz, jboolean ipv6) {
int domain = ipv6 == JNI_TRUE ? AF_INET6 : AF_INET;
int fd = nettyBlockingSocket(domain, SOCK_STREAM, 0);
if (fd == -1) {
return -errno;
}
return fd;
}
static jint netty_unix_socket_newSocketDomainFd(JNIEnv* env, jclass clazz) { static jint netty_unix_socket_newSocketDomainFd(JNIEnv* env, jclass clazz) {
int fd = nettyNonBlockingSocket(PF_UNIX, SOCK_STREAM, 0); int fd = nettyNonBlockingSocket(PF_UNIX, SOCK_STREAM, 0);
if (fd == -1) { if (fd == -1) {
@ -979,6 +995,7 @@ static const JNINativeMethod fixed_method_table[] = {
{ "localAddress", "(I)[B", (void *) netty_unix_socket_localAddress }, { "localAddress", "(I)[B", (void *) netty_unix_socket_localAddress },
{ "newSocketDgramFd", "(Z)I", (void *) netty_unix_socket_newSocketDgramFd }, { "newSocketDgramFd", "(Z)I", (void *) netty_unix_socket_newSocketDgramFd },
{ "newSocketStreamFd", "(Z)I", (void *) netty_unix_socket_newSocketStreamFd }, { "newSocketStreamFd", "(Z)I", (void *) netty_unix_socket_newSocketStreamFd },
{ "newSocketStreamFdBlocking", "(Z)I", (void *) netty_unix_socket_newSocketStreamFd_blocking }, //temporary
{ "newSocketDomainFd", "()I", (void *) netty_unix_socket_newSocketDomainFd }, { "newSocketDomainFd", "()I", (void *) netty_unix_socket_newSocketDomainFd },
{ "sendTo", "(IZLjava/nio/ByteBuffer;II[BII)I", (void *) netty_unix_socket_sendTo }, { "sendTo", "(IZLjava/nio/ByteBuffer;II[BII)I", (void *) netty_unix_socket_sendTo },
{ "sendToAddress", "(IZJII[BII)I", (void *) netty_unix_socket_sendToAddress }, { "sendToAddress", "(IZJII[BII)I", (void *) netty_unix_socket_sendToAddress },

View File

@ -397,6 +397,11 @@ public class Socket extends FileDescriptor {
return new Socket(newSocketStream0()); return new Socket(newSocketStream0());
} }
public static Socket newSocketStreamBlocking() {
System.out.println("newSocketStreamBlocking");
return new Socket(newSocketStreamBlocking(isIPv6Preferred()));
}
public static Socket newSocketDgram() { public static Socket newSocketDgram() {
return new Socket(newSocketDgram0()); return new Socket(newSocketDgram0());
} }
@ -423,6 +428,15 @@ public class Socket extends FileDescriptor {
return res; return res;
} }
//only temporary
protected static int newSocketStreamBlocking(boolean ipv6) {
int res = newSocketStreamFdBlocking(ipv6);
if (res < 0) {
throw new ChannelException(newIOException("newSocketStream", res));
}
return res;
}
protected static int newSocketDgram0() { protected static int newSocketDgram0() {
return newSocketDgram0(isIPv6Preferred()); return newSocketDgram0(isIPv6Preferred());
} }
@ -471,6 +485,7 @@ public class Socket extends FileDescriptor {
private static native int sendFd(int socketFd, int fd); private static native int sendFd(int socketFd, int fd);
private static native int newSocketStreamFd(boolean ipv6); private static native int newSocketStreamFd(boolean ipv6);
private static native int newSocketStreamFdBlocking(boolean ipv6);
private static native int newSocketDgramFd(boolean ipv6); private static native int newSocketDgramFd(boolean ipv6);
private static native int newSocketDomainFd(); private static native int newSocketDomainFd();