1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.channel.kqueue;
17
18 import io.netty5.channel.unix.Buffer;
19 import io.netty5.util.internal.PlatformDependent;
20
21 import java.nio.ByteBuffer;
22
23
24
25
26
27
28
29
30
31
32
33
34
35 final class KQueueEventArray {
36 private static final int KQUEUE_EVENT_SIZE = Native.sizeofKEvent();
37 private static final int KQUEUE_IDENT_OFFSET = Native.offsetofKEventIdent();
38 private static final int KQUEUE_FILTER_OFFSET = Native.offsetofKEventFilter();
39 private static final int KQUEUE_FFLAGS_OFFSET = Native.offsetofKEventFFlags();
40 private static final int KQUEUE_FLAGS_OFFSET = Native.offsetofKEventFlags();
41 private static final int KQUEUE_DATA_OFFSET = Native.offsetofKeventData();
42
43 private ByteBuffer memory;
44 private long memoryAddress;
45 private int size;
46 private int capacity;
47
48 KQueueEventArray(int capacity) {
49 if (capacity < 1) {
50 throw new IllegalArgumentException("capacity must be >= 1 but was " + capacity);
51 }
52 memory = Buffer.allocateDirectWithNativeOrder(calculateBufferCapacity(capacity));
53 memoryAddress = Buffer.nativeAddressOf(memory);
54 this.capacity = capacity;
55 }
56
57
58
59
60 long memoryAddress() {
61 return memoryAddress;
62 }
63
64
65
66
67
68 int capacity() {
69 return capacity;
70 }
71
72 int size() {
73 return size;
74 }
75
76 void clear() {
77 size = 0;
78 }
79
80 void evSet(AbstractKQueueChannel ch, short filter, short flags, int fflags) {
81 reallocIfNeeded();
82 evSet(getKEventOffset(size++) + memoryAddress, ch.socket.intValue(), filter, flags, fflags);
83 }
84
85 private void reallocIfNeeded() {
86 if (size == capacity) {
87 realloc(true);
88 }
89 }
90
91
92
93
94 void realloc(boolean throwIfFail) {
95
96 int newLength = capacity <= 65536 ? capacity << 1 : capacity + capacity >> 1;
97
98 try {
99 ByteBuffer buffer = Buffer.allocateDirectWithNativeOrder(calculateBufferCapacity(newLength));
100
101
102 memory.position(0).limit(size);
103 buffer.put(memory);
104 buffer.position(0);
105
106 Buffer.free(memory);
107 memory = buffer;
108 memoryAddress = Buffer.nativeAddressOf(buffer);
109 } catch (OutOfMemoryError e) {
110 if (throwIfFail) {
111 OutOfMemoryError error = new OutOfMemoryError(
112 "unable to allocate " + newLength + " new bytes! Existing capacity is: " + capacity);
113 error.initCause(e);
114 throw error;
115 }
116 }
117 }
118
119
120
121
122 void free() {
123 Buffer.free(memory);
124 memoryAddress = size = capacity = 0;
125 }
126
127 private static int getKEventOffset(int index) {
128 return index * KQUEUE_EVENT_SIZE;
129 }
130
131 private long getKEventOffsetAddress(int index) {
132 return getKEventOffset(index) + memoryAddress;
133 }
134
135 private short getShort(int index, int offset) {
136 if (PlatformDependent.hasUnsafe()) {
137 return PlatformDependent.getShort(getKEventOffsetAddress(index) + offset);
138 }
139 return memory.getShort(getKEventOffset(index) + offset);
140 }
141
142 short flags(int index) {
143 return getShort(index, KQUEUE_FLAGS_OFFSET);
144 }
145
146 short filter(int index) {
147 return getShort(index, KQUEUE_FILTER_OFFSET);
148 }
149
150 short fflags(int index) {
151 return getShort(index, KQUEUE_FFLAGS_OFFSET);
152 }
153
154 int fd(int index) {
155 if (PlatformDependent.hasUnsafe()) {
156 return PlatformDependent.getInt(getKEventOffsetAddress(index) + KQUEUE_IDENT_OFFSET);
157 }
158 return memory.getInt(getKEventOffset(index) + KQUEUE_IDENT_OFFSET);
159 }
160
161 long data(int index) {
162 if (PlatformDependent.hasUnsafe()) {
163 return PlatformDependent.getLong(getKEventOffsetAddress(index) + KQUEUE_DATA_OFFSET);
164 }
165 return memory.getLong(getKEventOffset(index) + KQUEUE_DATA_OFFSET);
166 }
167
168 private static int calculateBufferCapacity(int capacity) {
169 return capacity * KQUEUE_EVENT_SIZE;
170 }
171
172 private static native void evSet(long keventAddress, int ident, short filter, short flags, int fflags);
173 }