package io.netty.channel.kqueue;
import io.netty.util.internal.PlatformDependent;
final class KQueueEventArray {
private static final int KQUEUE_EVENT_SIZE = Native.sizeofKEvent();
private static final int KQUEUE_IDENT_OFFSET = Native.offsetofKEventIdent();
private static final int KQUEUE_FILTER_OFFSET = Native.offsetofKEventFilter();
private static final int KQUEUE_FFLAGS_OFFSET = Native.offsetofKEventFFlags();
private static final int KQUEUE_FLAGS_OFFSET = Native.offsetofKEventFlags();
private static final int KQUEUE_DATA_OFFSET = Native.offsetofKeventData();
private long memoryAddress;
private int size;
private int capacity;
KQueueEventArray(int capacity) {
if (capacity < 1) {
throw new IllegalArgumentException("capacity must be >= 1 but was " + capacity);
}
memoryAddress = PlatformDependent.allocateMemory(capacity * KQUEUE_EVENT_SIZE);
this.capacity = capacity;
}
long memoryAddress() {
return memoryAddress;
}
int capacity() {
return capacity;
}
int size() {
return size;
}
void clear() {
size = 0;
}
void evSet(AbstractKQueueChannel ch, short filter, short flags, int fflags) {
checkSize();
evSet(getKEventOffset(size++), ch, ch.socket.intValue(), filter, flags, fflags);
}
private void checkSize() {
if (size == capacity) {
realloc(true);
}
}
void realloc(boolean throwIfFail) {
int newLength = capacity <= 65536 ? capacity << 1 : capacity + capacity >> 1;
long newMemoryAddress = PlatformDependent.reallocateMemory(memoryAddress, newLength * KQUEUE_EVENT_SIZE);
if (newMemoryAddress != 0) {
memoryAddress = newMemoryAddress;
capacity = newLength;
return;
}
if (throwIfFail) {
throw new OutOfMemoryError("unable to allocate " + newLength + " new bytes! Existing capacity is: "
+ capacity);
}
}
void free() {
PlatformDependent.freeMemory(memoryAddress);
memoryAddress = size = capacity = 0;
}
long getKEventOffset(int index) {
return memoryAddress + index * KQUEUE_EVENT_SIZE;
}
short flags(int index) {
return PlatformDependent.getShort(getKEventOffset(index) + KQUEUE_FLAGS_OFFSET);
}
short filter(int index) {
return PlatformDependent.getShort(getKEventOffset(index) + KQUEUE_FILTER_OFFSET);
}
short fflags(int index) {
return PlatformDependent.getShort(getKEventOffset(index) + KQUEUE_FFLAGS_OFFSET);
}
int fd(int index) {
return PlatformDependent.getInt(getKEventOffset(index) + KQUEUE_IDENT_OFFSET);
}
long data(int index) {
return PlatformDependent.getLong(getKEventOffset(index) + KQUEUE_DATA_OFFSET);
}
AbstractKQueueChannel channel(int index) {
return getChannel(getKEventOffset(index));
}
private static native void evSet(long keventAddress, AbstractKQueueChannel ch,
int ident, short filter, short flags, int fflags);
private static native AbstractKQueueChannel getChannel(long keventAddress);
static native void deleteGlobalRefs(long channelAddressStart, long channelAddressEnd);
}