1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty5.channel.unix;
17
18 import io.netty5.buffer.api.Buffer;
19 import io.netty5.buffer.api.ReadableComponent;
20 import io.netty5.buffer.api.ReadableComponentProcessor;
21 import io.netty5.buffer.api.WritableComponent;
22 import io.netty5.buffer.api.WritableComponentProcessor;
23 import io.netty5.channel.ChannelOutboundBuffer.MessageProcessor;
24 import io.netty5.util.internal.PlatformDependent;
25
26 import java.nio.ByteBuffer;
27 import java.nio.ByteOrder;
28
29 import static io.netty5.channel.unix.Buffer.addressSize;
30 import static io.netty5.channel.unix.Buffer.allocateDirectWithNativeOrder;
31 import static io.netty5.channel.unix.Buffer.free;
32 import static io.netty5.channel.unix.Buffer.nativeAddressOf;
33 import static io.netty5.channel.unix.Limits.IOV_MAX;
34 import static io.netty5.channel.unix.Limits.SSIZE_MAX;
35 import static io.netty5.util.internal.ObjectUtil.checkPositive;
36 import static java.lang.Math.min;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 public final class IovArray implements MessageProcessor, ReadableComponentProcessor<RuntimeException>,
56 WritableComponentProcessor<RuntimeException> {
57
58
59 private static final int ADDRESS_SIZE = addressSize();
60
61
62
63
64
65 public static final int IOV_SIZE = 2 * ADDRESS_SIZE;
66
67
68
69
70
71 private static final int MAX_CAPACITY = IOV_MAX * IOV_SIZE;
72
73 private final long memoryAddress;
74 private final ByteBuffer memory;
75 private int count;
76 private long size;
77 private long maxBytes = SSIZE_MAX;
78
79 public IovArray() {
80 this(allocateDirectWithNativeOrder(MAX_CAPACITY));
81 }
82
83 public IovArray(ByteBuffer memory) {
84 assert memory.position() == 0;
85 if (!memory.isDirect()) {
86 memory = ByteBuffer.allocateDirect(memory.capacity());
87 }
88 if (memory.order() != ByteOrder.nativeOrder()) {
89 memory = memory.order(ByteOrder.nativeOrder());
90 }
91 this.memory = memory;
92 memoryAddress = nativeAddressOf(memory);
93 }
94
95 public void clear() {
96 count = 0;
97 size = 0;
98 }
99
100 private boolean add(long memoryAddress, long addr, int len) {
101 assert addr != 0;
102
103
104
105 if (maxBytes - len < size && count > 0 ||
106
107 memory.capacity() < (count + 1) * IOV_SIZE) {
108
109
110
111
112
113
114 return false;
115 }
116 final int baseOffset = idx(count);
117 final int lengthOffset = baseOffset + ADDRESS_SIZE;
118
119 size += len;
120 ++count;
121
122 if (ADDRESS_SIZE == 8) {
123
124 if (PlatformDependent.hasUnsafe()) {
125 PlatformDependent.putLong(baseOffset + memoryAddress, addr);
126 PlatformDependent.putLong(lengthOffset + memoryAddress, len);
127 } else {
128 memory.putLong(baseOffset, addr);
129 memory.putLong(lengthOffset, len);
130 }
131 } else {
132 assert ADDRESS_SIZE == 4;
133 if (PlatformDependent.hasUnsafe()) {
134 PlatformDependent.putInt(baseOffset + memoryAddress, (int) addr);
135 PlatformDependent.putInt(lengthOffset + memoryAddress, len);
136 } else {
137 memory.putInt(baseOffset, (int) addr);
138 memory.putInt(lengthOffset, len);
139 }
140 }
141 return true;
142 }
143
144
145
146
147 public int count() {
148 return count;
149 }
150
151
152
153
154 public long size() {
155 return size;
156 }
157
158
159
160
161
162
163
164
165
166
167
168
169 public void maxBytes(long maxBytes) {
170 this.maxBytes = min(SSIZE_MAX, checkPositive(maxBytes, "maxBytes"));
171 }
172
173
174
175
176
177 public long maxBytes() {
178 return maxBytes;
179 }
180
181
182
183
184 public long memoryAddress(int index) {
185 return memoryAddress + idx(index);
186 }
187
188
189
190
191 public void release() {
192 free(memory);
193 }
194
195 @Override
196 public boolean processMessage(Object msg) {
197 if (msg instanceof io.netty5.buffer.api.Buffer) {
198 var buffer = (io.netty5.buffer.api.Buffer) msg;
199 if (buffer.readableBytes() == 0) {
200 return true;
201 }
202 return buffer.forEachReadable(0, this) >= 0;
203 }
204 return false;
205 }
206
207 private static int idx(int index) {
208 return IOV_SIZE * index;
209 }
210
211 @Override
212 public boolean process(int index, ReadableComponent component) {
213 return process(component, component.readableBytes());
214 }
215
216 public boolean process(ReadableComponent component, int byteCount) {
217 if (count == IOV_MAX) {
218
219 return false;
220 }
221 long nativeAddress = component.readableNativeAddress();
222 assert nativeAddress != 0;
223 return add(memoryAddress, nativeAddress, byteCount);
224 }
225
226 @Override
227 public boolean process(int index, WritableComponent component) {
228 return process(component, component.writableBytes());
229 }
230
231 public boolean process(WritableComponent component, int byteCount) {
232 if (count == IOV_MAX) {
233
234 return false;
235 }
236 long nativeAddress = component.writableNativeAddress();
237 assert nativeAddress != 0;
238 return add(memoryAddress, nativeAddress, byteCount);
239 }
240 }