From ba83a8840f6383904202cf8254c5ac1ff20e8ac9 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Mon, 23 Nov 2020 14:03:32 +0100 Subject: [PATCH] IovArray should support when there is no unsafe present (#10814) Motivation: In some enviroments sun.misc.Unsafe is not present. We should support these as well. Modifications: Fallback to JNI if we can't directly access the memoryAddress of the buffer. Result: Fixes https://github.com/netty/netty/issues/10813 --- .../epoll/EpollKQueueIovArrayTest.java | 28 +++++++++ .../channel/kqueue/KQueueIovArrayTest.java | 28 +++++++++ .../channel/unix/tests/IovArrayTest.java | 63 +++++++++++++++++++ .../java/io/netty/channel/unix/IovArray.java | 8 ++- 4 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollKQueueIovArrayTest.java create mode 100644 transport-native-kqueue/src/test/java/io/netty/channel/kqueue/KQueueIovArrayTest.java create mode 100644 transport-native-unix-common-tests/src/main/java/io/netty/channel/unix/tests/IovArrayTest.java diff --git a/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollKQueueIovArrayTest.java b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollKQueueIovArrayTest.java new file mode 100644 index 0000000000..ab72958114 --- /dev/null +++ b/transport-native-epoll/src/test/java/io/netty/channel/epoll/EpollKQueueIovArrayTest.java @@ -0,0 +1,28 @@ +/* + * 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: + * + * https://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.epoll; + +import io.netty.channel.unix.tests.IovArrayTest; +import org.junit.Assume; +import org.junit.BeforeClass; + +public class EpollKQueueIovArrayTest extends IovArrayTest { + + @BeforeClass + public static void loadNative() { + Assume.assumeTrue(Epoll.isAvailable()); + } +} diff --git a/transport-native-kqueue/src/test/java/io/netty/channel/kqueue/KQueueIovArrayTest.java b/transport-native-kqueue/src/test/java/io/netty/channel/kqueue/KQueueIovArrayTest.java new file mode 100644 index 0000000000..f59db0cc36 --- /dev/null +++ b/transport-native-kqueue/src/test/java/io/netty/channel/kqueue/KQueueIovArrayTest.java @@ -0,0 +1,28 @@ +/* + * 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: + * + * https://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.kqueue; + +import io.netty.channel.unix.tests.IovArrayTest; +import org.junit.Assume; +import org.junit.BeforeClass; + +public class KQueueIovArrayTest extends IovArrayTest { + + @BeforeClass + public static void loadNative() { + Assume.assumeTrue(KQueue.isAvailable()); + } +} diff --git a/transport-native-unix-common-tests/src/main/java/io/netty/channel/unix/tests/IovArrayTest.java b/transport-native-unix-common-tests/src/main/java/io/netty/channel/unix/tests/IovArrayTest.java new file mode 100644 index 0000000000..e6052fdb15 --- /dev/null +++ b/transport-native-unix-common-tests/src/main/java/io/netty/channel/unix/tests/IovArrayTest.java @@ -0,0 +1,63 @@ +/* + * 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: + * + * https://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.unix.tests; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.buffer.UnpooledByteBufAllocator; +import io.netty.buffer.UnpooledDirectByteBuf; +import io.netty.channel.unix.IovArray; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public abstract class IovArrayTest { + + @Test + public void testNotFailsWihtoutMemoryAddress() { + ByteBuf buffer = new NoMemoryAddressByteBuf(128); + IovArray array = new IovArray(buffer); + + ByteBuf buf = Unpooled.directBuffer().writeZero(8); + ByteBuf buf2 = new NoMemoryAddressByteBuf(8).writeZero(8); + assertTrue(array.add(buf, 0, buf.readableBytes())); + assertTrue(array.add(buf, 0, buf2.readableBytes())); + assertEquals(2, array.count()); + assertEquals(16, array.size()); + assertTrue(buf.release()); + assertTrue(buf2.release()); + array.release(); + assertEquals(0, buffer.refCnt()); + } + + private static final class NoMemoryAddressByteBuf extends UnpooledDirectByteBuf { + + NoMemoryAddressByteBuf(int capacity) { + super(UnpooledByteBufAllocator.DEFAULT, capacity, Integer.MAX_VALUE); + } + + @Override + public boolean hasMemoryAddress() { + return false; + } + + @Override + public long memoryAddress() { + throw new UnsupportedOperationException(); + } + } +} diff --git a/transport-native-unix-common/src/main/java/io/netty/channel/unix/IovArray.java b/transport-native-unix-common/src/main/java/io/netty/channel/unix/IovArray.java index 6717250dd2..6cf16ac0fc 100644 --- a/transport-native-unix-common/src/main/java/io/netty/channel/unix/IovArray.java +++ b/transport-native-unix-common/src/main/java/io/netty/channel/unix/IovArray.java @@ -62,6 +62,7 @@ public final class IovArray implements MessageProcessor { */ private static final int MAX_CAPACITY = IOV_MAX * IOV_SIZE; + private final long memoryAddress; private final ByteBuf memory; private int count; private long size; @@ -77,6 +78,12 @@ public final class IovArray implements MessageProcessor { assert memory.readerIndex() == 0; this.memory = PlatformDependent.hasUnsafe() ? memory : memory.order( PlatformDependent.BIG_ENDIAN_NATIVE_ORDER ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN); + if (memory.hasMemoryAddress()) { + memoryAddress = memory.memoryAddress(); + } else { + // Fallback to using JNI as we were not be able to access the address otherwise. + memoryAddress = Buffer.memoryAddress(memory.internalNioBuffer(0, memory.capacity())); + } } public void clear() { @@ -97,7 +104,6 @@ public final class IovArray implements MessageProcessor { // No more room! return false; } - long memoryAddress = memory.memoryAddress(); if (buf.nioBufferCount() == 1) { if (len == 0) { return true;