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