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
110 ByteBuffer oldContent = memory.duplicate();
111 oldContent.position(0).limit(calculateBufferCapacity(size));
112 buffer.buffer().put(oldContent);
113 buffer.buffer().position(0);
114
115 memoryCleanable.clean();
116 memoryCleanable = buffer;
117 memory = buffer.buffer();
118 memoryAddress = Buffer.memoryAddress(memory);
119 capacity = newLength;
120 } catch (OutOfMemoryError e) {
121 if (throwIfFail) {
122 OutOfMemoryError error = new OutOfMemoryError(
123 "unable to allocate " + newLength + " new bytes! Existing capacity is: " + capacity);
124 error.initCause(e);
125 throw error;
126 }
127 }
128 }
129
130
131
132
133 void free() {
134 memoryCleanable.clean();
135 memoryAddress = size = capacity = 0;
136 }
137
138 private static int getKEventOffset(int index) {
139 return index * KQUEUE_EVENT_SIZE;
140 }
141
142 private long getKEventOffsetAddress(int index) {
143 return getKEventOffset(index) + memoryAddress;
144 }
145
146 private short getShort(int index, int offset) {
147 if (PlatformDependent.hasUnsafe()) {
148 return PlatformDependent.getShort(getKEventOffsetAddress(index) + offset);
149 }
150 return memory.getShort(getKEventOffset(index) + offset);
151 }
152
153 short flags(int index) {
154 return getShort(index, KQUEUE_FLAGS_OFFSET);
155 }
156
157 short filter(int index) {
158 return getShort(index, KQUEUE_FILTER_OFFSET);
159 }
160
161 short fflags(int index) {
162 return getShort(index, KQUEUE_FFLAGS_OFFSET);
163 }
164
165 int ident(int index) {
166 if (PlatformDependent.hasUnsafe()) {
167 return PlatformDependent.getInt(getKEventOffsetAddress(index) + KQUEUE_IDENT_OFFSET);
168 }
169 return memory.getInt(getKEventOffset(index) + KQUEUE_IDENT_OFFSET);
170 }
171
172 long data(int index) {
173 return getLong(index, KQUEUE_DATA_OFFSET);
174 }
175
176 long udata(int index) {
177 return getLong(index, KQUEUE_UDATA_OFFSET);
178 }
179
180 private long getLong(int index, int offset) {
181 if (PlatformDependent.hasUnsafe()) {
182 return PlatformDependent.getLong(getKEventOffsetAddress(index) + offset);
183 }
184 return memory.getLong(getKEventOffset(index) + offset);
185 }
186
187 private static int calculateBufferCapacity(int capacity) {
188 return capacity * KQUEUE_EVENT_SIZE;
189 }
190
191 private static native void evSet(
192 long keventAddress, int ident, short filter, short flags, int fflags, long data, long udata);
193 }