1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.uring;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.ChannelOption;
20 import io.netty.channel.unix.Buffer;
21 import io.netty.channel.unix.Limits;
22 import io.netty.util.internal.PlatformDependent;
23 import io.netty.util.internal.SystemPropertyUtil;
24 import io.netty.util.internal.logging.InternalLogger;
25 import io.netty.util.internal.logging.InternalLoggerFactory;
26
27 public final class IoUring {
28
29 private static final Throwable UNAVAILABILITY_CAUSE;
30 private static final boolean IORING_CQE_F_SOCK_NONEMPTY_SUPPORTED;
31 private static final boolean IORING_SPLICE_SUPPORTED;
32 private static final boolean IORING_ACCEPT_NO_WAIT_SUPPORTED;
33 private static final boolean IORING_ACCEPT_MULTISHOT_SUPPORTED;
34 private static final boolean IORING_RECV_MULTISHOT_SUPPORTED;
35 private static final boolean IORING_RECVSEND_BUNDLE_SUPPORTED;
36 private static final boolean IORING_POLL_ADD_MULTISHOT_SUPPORTED;
37 private static final boolean IORING_REGISTER_IOWQ_MAX_WORKERS_SUPPORTED;
38 private static final boolean IORING_SETUP_SUBMIT_ALL_SUPPORTED;
39 private static final boolean IORING_SETUP_CQ_SIZE_SUPPORTED;
40 private static final boolean IORING_SETUP_SINGLE_ISSUER_SUPPORTED;
41 private static final boolean IORING_SETUP_DEFER_TASKRUN_SUPPORTED;
42 private static final boolean IORING_REGISTER_BUFFER_RING_SUPPORTED;
43 private static final boolean IORING_REGISTER_BUFFER_RING_INC_SUPPORTED;
44 private static final boolean IORING_ACCEPT_MULTISHOT_ENABLED;
45 private static final boolean IORING_RECV_MULTISHOT_ENABLED;
46 private static final boolean IORING_RECVSEND_BUNDLE_ENABLED;
47 private static final boolean IORING_POLL_ADD_MULTISHOT_ENABLED;
48
49 static final int NUM_ELEMENTS_IOVEC;
50
51 private static final InternalLogger logger;
52
53 static {
54 logger = InternalLoggerFactory.getInstance(IoUring.class);
55 Throwable cause = null;
56 boolean socketNonEmptySupported = false;
57 boolean spliceSupported = false;
58 boolean acceptSupportNoWait = false;
59 boolean acceptMultishotSupported = false;
60 boolean recvsendBundleSupported = false;
61 boolean recvMultishotSupported = false;
62 boolean pollAddMultishotSupported = false;
63 boolean registerIowqWorkersSupported = false;
64 boolean submitAllSupported = false;
65 boolean setUpCqSizeSupported = false;
66 boolean singleIssuerSupported = false;
67 boolean deferTaskrunSupported = false;
68 boolean registerBufferRingSupported = false;
69 boolean registerBufferRingIncSupported = false;
70 int numElementsIoVec = 10;
71
72 String kernelVersion = "[unknown]";
73 try {
74 if (SystemPropertyUtil.getBoolean("io.netty.transport.noNative", false)) {
75 cause = new UnsupportedOperationException(
76 "Native transport was explicit disabled with -Dio.netty.transport.noNative=true");
77 } else {
78 kernelVersion = Native.kernelVersion();
79 Native.checkKernelVersion(kernelVersion);
80 if (PlatformDependent.javaVersion() >= 9) {
81 RingBuffer ringBuffer = null;
82 try {
83 ringBuffer = Native.createRingBuffer(1, 0);
84 if ((ringBuffer.features() & Native.IORING_FEAT_SUBMIT_STABLE) == 0) {
85
86 throw new UnsupportedOperationException("IORING_FEAT_SUBMIT_STABLE not supported!");
87 }
88
89
90 numElementsIoVec = SystemPropertyUtil.getInt(
91 "io.netty.iouring.numElementsIoVec", 10 * Limits.IOV_MAX);
92 Native.checkAllIOSupported(ringBuffer.fd());
93 socketNonEmptySupported = Native.isCqeFSockNonEmptySupported(ringBuffer.fd());
94 spliceSupported = Native.isSpliceSupported(ringBuffer.fd());
95 recvsendBundleSupported = (ringBuffer.features() & Native.IORING_FEAT_RECVSEND_BUNDLE) != 0;
96
97 acceptSupportNoWait = recvsendBundleSupported;
98
99
100
101
102
103 recvsendBundleSupported = false;
104 acceptMultishotSupported = Native.isAcceptMultishotSupported(ringBuffer.fd());
105 recvMultishotSupported = Native.isRecvMultishotSupported();
106 pollAddMultishotSupported = Native.isPollAddMultiShotSupported(ringBuffer.fd());
107 registerIowqWorkersSupported = Native.isRegisterIoWqWorkerSupported(ringBuffer.fd());
108 submitAllSupported = Native.ioUringSetupSupportsFlags(Native.IORING_SETUP_SUBMIT_ALL);
109 setUpCqSizeSupported = Native.ioUringSetupSupportsFlags(Native.IORING_SETUP_CQSIZE);
110 singleIssuerSupported = Native.ioUringSetupSupportsFlags(Native.IORING_SETUP_SINGLE_ISSUER);
111
112
113 deferTaskrunSupported = Native.ioUringSetupSupportsFlags(
114 Native.IORING_SETUP_SINGLE_ISSUER | Native.IORING_SETUP_DEFER_TASKRUN);
115 registerBufferRingSupported = Native.isRegisterBufferRingSupported(ringBuffer.fd(), 0);
116 registerBufferRingIncSupported = Native.isRegisterBufferRingSupported(ringBuffer.fd(),
117 Native.IOU_PBUF_RING_INC);
118 } finally {
119 if (ringBuffer != null) {
120 try {
121 ringBuffer.close();
122 } catch (Exception ignore) {
123
124 }
125 }
126 }
127 } else {
128 cause = new UnsupportedOperationException("Java 9+ is required");
129 }
130 }
131 } catch (Throwable t) {
132 cause = t;
133 }
134 if (cause != null) {
135 if (logger.isTraceEnabled()) {
136 logger.debug("IoUring support is not available using kernel {}", kernelVersion, cause);
137 } else if (logger.isDebugEnabled()) {
138 logger.debug("IoUring support is not available using kernel {}: {}", kernelVersion, cause.getMessage());
139 }
140 } else {
141 if (logger.isDebugEnabled()) {
142 logger.debug("IoUring support is available using kernel {} (" +
143 "CQE_F_SOCK_NONEMPTY_SUPPORTED={}, " +
144 "SPLICE_SUPPORTED={}, " +
145 "ACCEPT_NO_WAIT_SUPPORTED={}, " +
146 "ACCEPT_MULTISHOT_SUPPORTED={}, " +
147 "POLL_ADD_MULTISHOT_SUPPORTED={} " +
148 "RECV_MULTISHOT_SUPPORTED={}, " +
149 "IORING_RECVSEND_BUNDLE_SUPPORTED={}, " +
150 "REGISTER_IOWQ_MAX_WORKERS_SUPPORTED={}, " +
151 "SETUP_SUBMIT_ALL_SUPPORTED={}, " +
152 "SETUP_SINGLE_ISSUER_SUPPORTED={}, " +
153 "SETUP_DEFER_TASKRUN_SUPPORTED={}, " +
154 "REGISTER_BUFFER_RING_SUPPORTED={}, " +
155 "REGISTER_BUFFER_RING_INC_SUPPORTED={}" +
156 ")", kernelVersion, socketNonEmptySupported, spliceSupported, acceptSupportNoWait,
157 acceptMultishotSupported, pollAddMultishotSupported, recvMultishotSupported,
158 recvsendBundleSupported, registerIowqWorkersSupported, submitAllSupported,
159 singleIssuerSupported, deferTaskrunSupported,
160 registerBufferRingSupported, registerBufferRingIncSupported);
161 }
162 }
163 UNAVAILABILITY_CAUSE = cause;
164 IORING_CQE_F_SOCK_NONEMPTY_SUPPORTED = socketNonEmptySupported;
165 IORING_SPLICE_SUPPORTED = spliceSupported;
166 IORING_ACCEPT_NO_WAIT_SUPPORTED = acceptSupportNoWait;
167 IORING_ACCEPT_MULTISHOT_SUPPORTED = acceptMultishotSupported;
168 IORING_RECV_MULTISHOT_SUPPORTED = recvMultishotSupported;
169 IORING_RECVSEND_BUNDLE_SUPPORTED = recvsendBundleSupported;
170 IORING_POLL_ADD_MULTISHOT_SUPPORTED = pollAddMultishotSupported;
171 IORING_REGISTER_IOWQ_MAX_WORKERS_SUPPORTED = registerIowqWorkersSupported;
172 IORING_SETUP_SUBMIT_ALL_SUPPORTED = submitAllSupported;
173 IORING_SETUP_CQ_SIZE_SUPPORTED = setUpCqSizeSupported;
174 IORING_SETUP_SINGLE_ISSUER_SUPPORTED = singleIssuerSupported;
175 IORING_SETUP_DEFER_TASKRUN_SUPPORTED = deferTaskrunSupported;
176 IORING_REGISTER_BUFFER_RING_SUPPORTED = registerBufferRingSupported;
177 IORING_REGISTER_BUFFER_RING_INC_SUPPORTED = registerBufferRingIncSupported;
178
179 IORING_ACCEPT_MULTISHOT_ENABLED = IORING_ACCEPT_MULTISHOT_SUPPORTED && SystemPropertyUtil.getBoolean(
180 "io.netty.iouring.acceptMultiShotEnabled", true);
181 IORING_RECV_MULTISHOT_ENABLED = IORING_RECV_MULTISHOT_SUPPORTED && SystemPropertyUtil.getBoolean(
182 "io.netty.iouring.recvMultiShotEnabled", true);
183 IORING_RECVSEND_BUNDLE_ENABLED = IORING_RECVSEND_BUNDLE_SUPPORTED && SystemPropertyUtil.getBoolean(
184 "io.netty.iouring.recvsendBundleEnabled", true);
185 IORING_POLL_ADD_MULTISHOT_ENABLED = IORING_POLL_ADD_MULTISHOT_SUPPORTED && SystemPropertyUtil.getBoolean(
186 "io.netty.iouring.pollAddMultishotEnabled", true);
187 NUM_ELEMENTS_IOVEC = numElementsIoVec;
188 }
189
190 public static boolean isAvailable() {
191 return UNAVAILABILITY_CAUSE == null;
192 }
193
194
195
196
197
198
199
200 public static boolean isTcpFastOpenClientSideAvailable() {
201 return isAvailable() && Native.IS_SUPPORTING_TCP_FASTOPEN_CLIENT;
202 }
203
204
205
206
207
208
209
210 public static boolean isTcpFastOpenServerSideAvailable() {
211 return isAvailable() && Native.IS_SUPPORTING_TCP_FASTOPEN_SERVER;
212 }
213
214 static boolean isCqeFSockNonEmptySupported() {
215 return IORING_CQE_F_SOCK_NONEMPTY_SUPPORTED;
216 }
217
218
219
220
221
222
223 public static boolean isSpliceSupported() {
224 return IORING_SPLICE_SUPPORTED;
225 }
226
227 static boolean isAcceptNoWaitSupported() {
228 return IORING_ACCEPT_NO_WAIT_SUPPORTED;
229 }
230
231 static boolean isAcceptMultishotSupported() {
232 return IORING_ACCEPT_MULTISHOT_SUPPORTED;
233 }
234
235 static boolean isRecvMultishotSupported() {
236 return IORING_RECV_MULTISHOT_SUPPORTED;
237 }
238
239 static boolean isRecvsendBundleSupported() {
240 return IORING_RECVSEND_BUNDLE_SUPPORTED;
241 }
242
243 static boolean isPollAddMultishotSupported() {
244 return IORING_POLL_ADD_MULTISHOT_SUPPORTED;
245 }
246
247 static boolean isRegisterIowqMaxWorkersSupported() {
248 return IORING_REGISTER_IOWQ_MAX_WORKERS_SUPPORTED;
249 }
250
251 static boolean isSetupCqeSizeSupported() {
252 return IORING_SETUP_CQ_SIZE_SUPPORTED;
253 }
254
255 static boolean isSetupSubmitAllSupported() {
256 return IORING_SETUP_SUBMIT_ALL_SUPPORTED;
257 }
258
259 static boolean isSetupSingleIssuerSupported() {
260 return IORING_SETUP_SINGLE_ISSUER_SUPPORTED;
261 }
262
263 static boolean isSetupDeferTaskrunSupported() {
264 return IORING_SETUP_DEFER_TASKRUN_SUPPORTED;
265 }
266
267
268
269
270
271
272 public static boolean isRegisterBufferRingSupported() {
273 return IORING_REGISTER_BUFFER_RING_SUPPORTED;
274 }
275
276
277
278
279
280
281 public static boolean isRegisterBufferRingIncSupported() {
282 return IORING_REGISTER_BUFFER_RING_INC_SUPPORTED;
283 }
284
285
286
287
288
289
290 public static boolean isAcceptMultishotEnabled() {
291 return IORING_ACCEPT_MULTISHOT_ENABLED;
292 }
293
294
295
296
297
298
299 public static boolean isRecvMultishotEnabled() {
300 return IORING_RECV_MULTISHOT_ENABLED;
301 }
302
303
304
305
306
307
308 public static boolean isRecvsendBundleEnabled() {
309 return IORING_RECVSEND_BUNDLE_ENABLED;
310 }
311
312
313
314
315
316
317 public static boolean isPollAddMultishotEnabled() {
318 return IORING_POLL_ADD_MULTISHOT_ENABLED;
319 }
320
321 public static void ensureAvailability() {
322 if (UNAVAILABILITY_CAUSE != null) {
323 throw (Error) new UnsatisfiedLinkError(
324 "failed to load the required native library").initCause(UNAVAILABILITY_CAUSE);
325 }
326 }
327
328 static long memoryAddress(ByteBuf buffer) {
329 if (buffer.hasMemoryAddress()) {
330 return buffer.memoryAddress();
331 }
332 return Buffer.memoryAddress(buffer.internalNioBuffer(0, buffer.capacity()));
333 }
334
335 public static Throwable unavailabilityCause() {
336 return UNAVAILABILITY_CAUSE;
337 }
338
339 private IoUring() {
340 }
341 }