1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.epoll;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.ChannelOutboundBuffer.MessageProcessor;
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
39
40
41 final class IovArray implements MessageProcessor {
42
43
44 private static final int ADDRESS_SIZE = PlatformDependent.addressSize();
45
46
47
48
49
50 private static final int IOV_SIZE = 2 * ADDRESS_SIZE;
51
52
53
54
55
56 private static final int CAPACITY = Native.IOV_MAX * IOV_SIZE;
57
58 private final long memoryAddress;
59 private int count;
60 private long size;
61
62 IovArray() {
63 memoryAddress = PlatformDependent.allocateMemory(CAPACITY);
64 }
65
66 void clear() {
67 count = 0;
68 size = 0;
69 }
70
71
72
73
74
75 boolean add(ByteBuf buf) {
76 int nioBufferCount = buf.nioBufferCount();
77 if (count + nioBufferCount > Native.IOV_MAX) {
78
79 return false;
80 }
81
82 if (nioBufferCount == 1) {
83 final int len = buf.readableBytes();
84 if (len == 0) {
85
86
87
88 return true;
89 }
90
91 final long addr = buf.memoryAddress();
92 final int offset = buf.readerIndex();
93 return add(addr, offset, len);
94 } else {
95 ByteBuffer[] buffers = buf.nioBuffers();
96 for (ByteBuffer nioBuffer : buffers) {
97 int len = nioBuffer.remaining();
98 if (len == 0) {
99
100 continue;
101 }
102 int offset = nioBuffer.position();
103 long addr = PlatformDependent.directBufferAddress(nioBuffer);
104
105 if (!add(addr, offset, len)) {
106 return false;
107 }
108 }
109 return true;
110 }
111 }
112
113 private boolean add(long addr, int offset, int len) {
114 if (len == 0) {
115
116 return true;
117 }
118
119 final long baseOffset = memoryAddress(count++);
120 final long lengthOffset = baseOffset + ADDRESS_SIZE;
121
122 if (Native.SSIZE_MAX - len < size) {
123
124
125
126
127
128
129 return false;
130 }
131 size += len;
132
133 if (ADDRESS_SIZE == 8) {
134
135 PlatformDependent.putLong(baseOffset, addr + offset);
136 PlatformDependent.putLong(lengthOffset, len);
137 } else {
138 assert ADDRESS_SIZE == 4;
139 PlatformDependent.putInt(baseOffset, (int) addr + offset);
140 PlatformDependent.putInt(lengthOffset, len);
141 }
142 return true;
143 }
144
145
146
147
148
149 long processWritten(int index, long written) {
150 long baseOffset = memoryAddress(index);
151 long lengthOffset = baseOffset + ADDRESS_SIZE;
152 if (ADDRESS_SIZE == 8) {
153
154 long len = PlatformDependent.getLong(lengthOffset);
155 if (len > written) {
156 long offset = PlatformDependent.getLong(baseOffset);
157 PlatformDependent.putLong(baseOffset, offset + written);
158 PlatformDependent.putLong(lengthOffset, len - written);
159 return -1;
160 }
161 return len;
162 } else {
163 assert ADDRESS_SIZE == 4;
164 long len = PlatformDependent.getInt(lengthOffset);
165 if (len > written) {
166 int offset = PlatformDependent.getInt(baseOffset);
167 PlatformDependent.putInt(baseOffset, (int) (offset + written));
168 PlatformDependent.putInt(lengthOffset, (int) (len - written));
169 return -1;
170 }
171 return len;
172 }
173 }
174
175
176
177
178 int count() {
179 return count;
180 }
181
182
183
184
185 long size() {
186 return size;
187 }
188
189
190
191
192 long memoryAddress(int offset) {
193 return memoryAddress + IOV_SIZE * offset;
194 }
195
196
197
198
199 void release() {
200 PlatformDependent.freeMemory(memoryAddress);
201 }
202
203 @Override
204 public boolean processMessage(Object msg) throws Exception {
205 if (msg instanceof ByteBuf) {
206 return add((ByteBuf) msg);
207 }
208 return false;
209 }
210 }