io.netty.channel.epoll.IovArray Maven / Gradle / Ivy
Go to download
This artifact provides a single jar that contains all classes required to use remote Jakarta Enterprise Beans and Jakarta Messaging, including
all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and
Jakarta Messaging BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up
with different versions on classes on the class path).
/*
* Copyright 2014 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.epoll;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.channel.ChannelOutboundBuffer.MessageProcessor;
import io.netty.util.internal.PlatformDependent;
import java.nio.ByteBuffer;
/**
* Represent an array of struct array and so can be passed directly over via JNI without the need to do any more
* array copies.
*
* The buffers are written out directly into direct memory to match the struct iov. See also {@code man writev}.
*
*
* struct iovec {
* void *iov_base;
* size_t iov_len;
* };
*
*
* See also
* Efficient JNI programming IV: Wrapping native data objects.
*/
final class IovArray implements MessageProcessor {
/** The size of an address which should be 8 for 64 bits and 4 for 32 bits. */
private static final int ADDRESS_SIZE = PlatformDependent.addressSize();
/**
* The size of an {@code iovec} struct in bytes. This is calculated as we have 2 entries each of the size of the
* address.
*/
private static final int IOV_SIZE = 2 * ADDRESS_SIZE;
/**
* The needed memory to hold up to {@link Native#IOV_MAX} iov entries, where {@link Native#IOV_MAX} signified
* the maximum number of {@code iovec} structs that can be passed to {@code writev(...)}.
*/
private static final int CAPACITY = Native.IOV_MAX * IOV_SIZE;
private final long memoryAddress;
private int count;
private long size;
IovArray() {
memoryAddress = PlatformDependent.allocateMemory(CAPACITY);
}
void clear() {
count = 0;
size = 0;
}
/**
* Try to add the given {@link ByteBuf}. Returns {@code true} on success,
* {@code false} otherwise.
*/
boolean add(ByteBuf buf) {
if (count == Native.IOV_MAX) {
// No more room!
return false;
}
final int len = buf.readableBytes();
if (len == 0) {
// No need to add an empty buffer.
// We return true here because we want ChannelOutboundBuffer.forEachFlushedMessage() to continue
// fetching the next buffers.
return true;
}
final long addr = buf.memoryAddress();
final int offset = buf.readerIndex();
add(addr, offset, len);
return true;
}
private void add(long addr, int offset, int len) {
if (len == 0) {
// No need to add an empty buffer.
return;
}
final long baseOffset = memoryAddress(count++);
final long lengthOffset = baseOffset + ADDRESS_SIZE;
if (ADDRESS_SIZE == 8) {
// 64bit
PlatformDependent.putLong(baseOffset, addr + offset);
PlatformDependent.putLong(lengthOffset, len);
} else {
assert ADDRESS_SIZE == 4;
PlatformDependent.putInt(baseOffset, (int) addr + offset);
PlatformDependent.putInt(lengthOffset, len);
}
size += len;
}
/**
* Try to add the given {@link CompositeByteBuf}. Returns {@code true} on success,
* {@code false} otherwise.
*/
boolean add(CompositeByteBuf buf) {
ByteBuffer[] buffers = buf.nioBuffers();
if (count + buffers.length >= Native.IOV_MAX) {
// No more room!
return false;
}
for (int i = 0; i < buffers.length; i++) {
ByteBuffer nioBuffer = buffers[i];
int offset = nioBuffer.position();
int len = nioBuffer.limit() - nioBuffer.position();
if (len == 0) {
// No need to add an empty buffer so just continue
continue;
}
long addr = PlatformDependent.directBufferAddress(nioBuffer);
add(addr, offset, len);
}
return true;
}
/**
* Process the written iov entries. This will return the length of the iov entry on the given index if it is
* smaller then the given {@code written} value. Otherwise it returns {@code -1}.
*/
long processWritten(int index, long written) {
long baseOffset = memoryAddress(index);
long lengthOffset = baseOffset + ADDRESS_SIZE;
if (ADDRESS_SIZE == 8) {
// 64bit
long len = PlatformDependent.getLong(lengthOffset);
if (len > written) {
long offset = PlatformDependent.getLong(baseOffset);
PlatformDependent.putLong(baseOffset, offset + written);
PlatformDependent.putLong(lengthOffset, len - written);
return -1;
}
return len;
} else {
assert ADDRESS_SIZE == 4;
long len = PlatformDependent.getInt(lengthOffset);
if (len > written) {
int offset = PlatformDependent.getInt(baseOffset);
PlatformDependent.putInt(baseOffset, (int) (offset + written));
PlatformDependent.putInt(lengthOffset, (int) (len - written));
return -1;
}
return len;
}
}
/**
* Returns the number if iov entries.
*/
int count() {
return count;
}
/**
* Returns the size in bytes
*/
long size() {
return size;
}
/**
* Returns the {@code memoryAddress} for the given {@code offset}.
*/
long memoryAddress(int offset) {
return memoryAddress + IOV_SIZE * offset;
}
/**
* Release the {@link IovArray}. Once release further using of it may crash the JVM!
*/
void release() {
PlatformDependent.freeMemory(memoryAddress);
}
@Override
public boolean processMessage(Object msg) throws Exception {
if (msg instanceof ByteBuf) {
if (msg instanceof CompositeByteBuf) {
return add((CompositeByteBuf) msg);
} else {
return add((ByteBuf) msg);
}
}
return false;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy