View Javadoc
1   /*
2    * Copyright 2024 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.channel.uring;
17  
18  import io.netty.channel.IoOps;
19  
20  /**
21   * {@link IoOps} for implementation for
22   * <a href="https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h">Io_uring</a>.
23   */
24  public final class IoUringIoOps implements IoOps {
25  
26      private final byte opcode;
27      private final byte flags;
28      private final short ioPrio;
29      private final int fd;
30      private final long union1;
31      private final long union2;
32      private final int len;
33      private final int union3;
34      private final short data;
35      private final short personality;
36      private final short union4;
37      private final int union5;
38      private final long union6;
39  
40      /**
41       * Create a new instance which represents the {@code io_uring_sqe} struct.
42       *
43       * <pre>{@code
44       *  struct io_uring_sqe {
45       *      __u8    opcode;    // type of operation for this sqe
46       *      __u8    flags;     // IOSQE_ flags
47       *      __u16   ioprio;    // ioprio for the request
48       *      __s32   fd;        // file descriptor to do IO on
49       *
50       *      union {            // union1
51       *          __u64 off;     // offset into file
52       *          __u64 addr2;
53       *          struct {
54       *              __u32 cmd_op;
55       *              __u32 __pad1;
56       *          };
57       *      };
58       *
59       *      union {             // union2
60       *          __u64 addr;    // pointer to buffer or iovecs
61       *          __u64 splice_off_in;
62       *          struct {
63       *              __u32 level;
64       *              __u32 optname;
65       *          };
66       *      };
67       *      __u32 len;        // buffer size or number of iovecs
68       *
69       *      union {           // union3
70       *          __kernel_rwf_t rw_flags;
71       *          __u32 fsync_flags;
72       *          __u16 poll_events;    // compatibility
73       *          __u32 poll32_events; // word-reversed for BE
74       *          __u32 sync_range_flags;
75       *          __u32 msg_flags;
76       *          __u32 timeout_flags;
77       *          __u32 accept_flags;
78       *          __u32 cancel_flags;
79       *          __u32 open_flags;
80       *          __u32 statx_flags;
81       *          __u32 fadvise_advice;
82       *          __u32 splice_flags;
83       *          __u32 rename_flags;
84       *          __u32 unlink_flags;
85       *          __u32 hardlink_flags;
86       *          __u32 xeattr_flags;
87       *          __u32 msg_ring_flags;
88       *          __u32 uring_cmd_flags;
89       *          __u32 waitid_flags;
90       *          __u32 futex_flags;
91       *          __u32 install_fd_flags;
92       *          __u32 nop_flags;
93       *      };
94       *      __u64 user_data;    // data to be passed back at completion time
95       *                          // pack this to avoid bogus arm OABI complaints
96       *
97       *      union {             // union4
98       *
99       *          // index into fixed buffers, if used
100      *          __u16 buf_index;
101      *          // for grouped buffer selection
102      *          __u16 buf_group;
103      *      }__attribute__((packed));
104      *      // personality to use, if used
105      *      __u16 personality;
106      *
107      *      union {            // union5
108      *
109      *          __s32 splice_fd_in;
110      *          __u32 file_index;
111      *          __u32 optlen;
112      *          struct {
113      *              __u16 addr_len;
114      *              __u16 __pad3[ 1];
115      *          };
116      *      };
117      *
118      *      union {           // union6
119      *
120      *          struct {
121      *              __u64 addr3;
122      *              __u64 __pad2[ 1];
123      *          };
124      *          __u64 optval;
125      *          //
126      *          // If the ring is initialized with IORING_SETUP_SQE128, then
127      *          // this field is used for 80 bytes of arbitrary command data
128      *          __u8 cmd[ 0];
129      *      };
130      *  };
131      * }
132      * </pre>
133      */
134     public IoUringIoOps(byte opcode, byte flags, short ioPrio, int fd, long union1, long union2, int len, int union3,
135                         short data, short union4, short personality, int union5, long union6) {
136         this.opcode = opcode;
137         this.flags = flags;
138         this.ioPrio = ioPrio;
139         this.fd = fd;
140         this.union1 = union1;
141         this.union2 = union2;
142         this.len = len;
143         this.union3 = union3;
144         this.data = data;
145         this.union4 = union4;
146         this.personality = personality;
147         this.union5 = union5;
148         this.union6 = union6;
149     }
150 
151     byte opcode() {
152         return opcode;
153     }
154 
155     byte flags() {
156         return flags;
157     }
158 
159     short ioPrio() {
160         return ioPrio;
161     }
162 
163     int fd() {
164         return fd;
165     }
166 
167     long union1() {
168         return union1;
169     }
170 
171     long union2() {
172         return union2;
173     }
174 
175     int len() {
176         return len;
177     }
178 
179     int union3() {
180         return union3;
181     }
182 
183     short data() {
184         return data;
185     }
186 
187     short personality() {
188         return personality;
189     }
190 
191     short union4() {
192         return union4;
193     }
194 
195     int union5() {
196         return union5;
197     }
198 
199     long union6() {
200         return union6;
201     }
202 
203     @Override
204     public String toString() {
205         return "IOUringIoOps{" +
206                 "opcode=" + opcode +
207                 ", flags=" + flags +
208                 ", ioPrio=" + ioPrio +
209                 ", fd=" + fd +
210                 ", union1=" + union1 +
211                 ", union2=" + union2 +
212                 ", len=" + len +
213                 ", union3=" + union3 +
214                 ", data=" + data +
215                 ", union4=" + union4 +
216                 ", personality=" + personality +
217                 ", union5=" + union5 +
218                 ", union6=" + union6 +
219                 '}';
220     }
221 
222     /**
223      * Returns a new {@code OP_ASYNC_CANCEL} {@link IoUringIoOps}.
224      *
225      * @param flags     the flags.
226      * @param userData  the user data that identify a previous submitted {@link IoUringIoOps} that should be cancelled.
227      *                  The value to use here is returned by {@link io.netty.channel.IoRegistration#submit(IoOps)}.
228      * @param data      the data
229      * @return          ops.
230      */
231     static IoUringIoOps newAsyncCancel(byte flags, long userData, short data) {
232         // Best effort to cancel the
233         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L679
234         return new IoUringIoOps(Native.IORING_OP_ASYNC_CANCEL, flags, (short) 0, -1, 0, userData, 0, 0,
235                 data, (short) 0, (short) 0, 0, 0);
236     }
237 
238     /**
239      * Returns a new {@code OP_CLOSE} {@link IoUringIoOps}.
240      *
241      * @param fd        the filedescriptor
242      * @param flags     the flags.
243      * @param data      the data
244      * @return          ops.
245      */
246     static IoUringIoOps newClose(int fd, byte flags, short data) {
247         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L764
248         return new IoUringIoOps(Native.IORING_OP_CLOSE, flags, (short) 0, fd, 0L, 0L, 0, 0, data,
249                 (short) 0, (short) 0, 0, 0);
250     }
251 
252     /**
253      * Returns a new {@code OP_POLL_ADD} {@link IoUringIoOps}.
254      *
255      * @param fd        the filedescriptor
256      * @param flags     the flags.
257      * @param mask      the mask.
258      * @param len       the len.
259      * @param data      the data.
260      * @return          ops.
261      */
262     static IoUringIoOps newPollAdd(int fd, byte flags, int mask, int len, short data) {
263         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L554
264         return new IoUringIoOps(Native.IORING_OP_POLL_ADD, flags, (short) 0, fd, 0L, 0L, len, mask, data,
265                 (short) 0, (short) 0, 0, 0);
266     }
267 
268     /**
269      * Returns a new {@code OP_SENDMSG} {@link IoUringIoOps}.
270      *
271      * @param fd        the filedescriptor
272      * @param flags     the flags.
273      * @param msgFlags  the msg flags.
274      * @param data      the data
275      * @return          ops.
276      */
277     static IoUringIoOps newSendmsg(int fd, byte flags, int msgFlags, long address, short data) {
278         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L539
279         return new IoUringIoOps(Native.IORING_OP_SENDMSG, flags, (short) 0, fd, 0L, address, 1, msgFlags, data,
280                 (short) 0, (short) 0, 0, 0);
281     }
282 
283     /**
284      * Returns a new {@code OP_CONNECT} {@link IoUringIoOps}.
285      *
286      * @param fd                    the filedescriptor
287      * @param flags                 the flags.
288      * @param remoteMemoryAddress   the memory address of the sockaddr_storage.
289      * @param data                  the data
290      * @return                      ops.
291      */
292     static IoUringIoOps newConnect(int fd, byte flags, long remoteMemoryAddress, short data) {
293         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L695
294         return newConnect(
295                 fd, flags,
296                 remoteMemoryAddress, Native.SIZEOF_SOCKADDR_STORAGE,
297                 data
298         );
299     }
300 
301     /**
302      * Returns a new {@code OP_CONNECT} {@link IoUringIoOps}.
303      *
304      * @param fd                    the filedescriptor
305      * @param flags                 the flags.
306      * @param remoteMemoryAddress   the memory address of the sockaddr_storage.
307      * @param addrLen               then remoteMemory storage length.
308      * @param data                  the data
309      * @return                      ops.
310      */
311     static IoUringIoOps newConnect(int fd, byte flags, long remoteMemoryAddress, int addrLen, short data) {
312         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L695
313         return new IoUringIoOps(Native.IORING_OP_CONNECT, flags, (short) 0, fd, addrLen,
314                 remoteMemoryAddress, 0, 0, data, (short) 0, (short) 0, 0, 0);
315     }
316 
317     /**
318      * Returns a new {@code OP_ACCEPT} {@link IoUringIoOps}.
319      *
320      * @param fd                                    the filedescriptor
321      * @param flags                                 the flags.
322      * @param acceptFlags                           the flags for ACCEPT itself
323      * @param ioPrio                                io_prio
324      * @param acceptedAddressMemoryAddress          the memory address of the sockaddr_storage.
325      * @param acceptedAddressLengthMemoryAddress    the memory address of the length that will be updated once a new
326      *                                              connection was accepted.
327      * @param data                                  the data
328      * @return                                      ops.
329      */
330     static IoUringIoOps newAccept(int fd, byte flags, int acceptFlags, short ioPrio, long acceptedAddressMemoryAddress,
331                                          long acceptedAddressLengthMemoryAddress, short data) {
332         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L625
333         return new IoUringIoOps(Native.IORING_OP_ACCEPT, flags, ioPrio, fd, acceptedAddressLengthMemoryAddress,
334                 acceptedAddressMemoryAddress, 0, acceptFlags, data, (short) 0, (short) 0, 0, 0);
335     }
336 
337     /**
338      * Returns a new {@code OP_WRITEV} {@link IoUringIoOps}.
339      *
340      * @param fd                                    the filedescriptor
341      * @param flags                                 the flags.
342      * @param writevFlags                           the writev flags.
343      * @param memoryAddress                         the memory address of the io_vec array.
344      * @param length                                the length of the io_vec array.
345      * @param data                                  the data
346      * @return                                      ops.
347      */
348     static IoUringIoOps newWritev(int fd, byte flags, int writevFlags, long memoryAddress,
349                                          int length, short data) {
350         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L500
351         return new IoUringIoOps(Native.IORING_OP_WRITEV, flags, (short) 0, fd,
352                 0, memoryAddress, length, writevFlags, data, (short) 0, (short) 0, 0, 0);
353     }
354 
355     /**
356      * Returns a new {@code OP_WRITE} {@link IoUringIoOps}.
357      *
358      * @param fd                                    the filedescriptor
359      * @param flags                                 the flags.
360      * @param writeFlags                            the write flags.
361      * @param memoryAddress                         the memory address of the buffer
362      * @param length                                the length of the buffer.
363      * @param data                                  the data
364      * @return                                      ops.
365      */
366     static IoUringIoOps newWrite(
367             int fd, byte flags, int writeFlags, long memoryAddress, int length, short data) {
368         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L794
369         return new IoUringIoOps(Native.IORING_OP_WRITE, flags, (short) 0, fd,
370                 0, memoryAddress, length, writeFlags, data, (short) 0, (short) 0, 0, 0);
371     }
372 
373     /**
374      * Returns a new {@code OP_RECV} {@link IoUringIoOps}.
375      *
376      * @param fd                                    the filedescriptor
377      * @param flags                                 the flags.
378      * @param ioPrio                                the ioPrio.
379      * @param recvFlags                             the recv flags.
380      * @param memoryAddress                         the memory address of the buffer
381      * @param length                                the length of the buffer.
382      * @param data                                  the data
383      * @return                                      ops.
384      */
385     static IoUringIoOps newRecv(
386             int fd, byte flags, short ioPrio, int recvFlags, long memoryAddress, int length, short data) {
387         return newRecv(fd, flags, ioPrio, recvFlags, memoryAddress, length, data, (short) 0);
388     }
389 
390     static IoUringIoOps newRecv(
391             int fd, byte flags, short ioPrio, int recvFlags, long memoryAddress, int length, short data, short bid) {
392         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L898
393         return new IoUringIoOps(Native.IORING_OP_RECV, flags, ioPrio, fd,
394                 0, memoryAddress, length, recvFlags, data, bid, (short) 0, 0, 0);
395     }
396 
397     /**
398      * Returns a new {@code OP_RECVMSG} {@link IoUringIoOps}.
399      *
400      * @param fd                                    the filedescriptor
401      * @param flags                                 the flags.
402      * @param msgFlags                              the recvmsg flags.
403      * @param memoryAddress                         the memory address of the msghdr struct
404      * @param data                                  the data
405      * @return                                      ops.
406      */
407     static IoUringIoOps newRecvmsg(int fd, byte flags, int msgFlags, long memoryAddress, short data) {
408         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L523
409         return new IoUringIoOps(
410                 Native.IORING_OP_RECVMSG, flags, (short) 0, fd, 0L, memoryAddress, 1, msgFlags, data,
411                 (short) 0, (short) 0, 0, 0);
412     }
413 
414     /**
415      * Returns a new {@code OP_SEND} {@link IoUringIoOps}.
416      *
417      * @param fd                                    the filedescriptor
418      * @param flags                                 the flags.
419      * @param sendFlags                             the send flags.
420      * @param memoryAddress                         the memory address of the buffer.
421      * @param length                                the length of the buffer.
422      * @param data                                  the data
423      * @return                                      ops.
424      */
425     static IoUringIoOps newSend(
426             int fd, byte flags, int sendFlags, long memoryAddress, int length, short data) {
427         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L839
428         return new IoUringIoOps(Native.IORING_OP_SEND, flags, (short) 0, fd,
429                 0, memoryAddress, length, sendFlags, data, (short) 0, (short) 0, 0, 0);
430     }
431 
432     /**
433      * Returns a new {@code OP_SHUTDOWN} {@link IoUringIoOps}.
434      *
435      * @param fd                                    the filedescriptor
436      * @param flags                                 the flags.
437      * @param how                                   how the shutdown will be done.
438      * @param data                                  the data
439      * @return                                      ops.
440      */
441     static IoUringIoOps newShutdown(int fd, byte flags, int how, short data) {
442         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L1023
443         return new IoUringIoOps(Native.IORING_OP_SHUTDOWN, flags, (short) 0, fd, 0, 0, how, 0, data,
444                 (short) 0, (short) 0, 0, 0);
445     }
446 
447     /**
448      *
449      * Returns a new {@code OP_SPLICE} {@link IoUringIoOps}.
450      *
451      * @param fd_in                                     the filedescriptor
452      * @param off_in                                    the filedescriptor offset
453      * @param fd_out                                    the filedescriptor
454      * @param off_out                                   the filedescriptor offset
455      * @param nbytes                                    splice bytes
456      * @param splice_flags                              the flag
457      * @param data                                      the data
458      * @return                                          ops.
459      */
460     static IoUringIoOps newSplice(int fd_in, long off_in,
461                                          int fd_out, long off_out,
462                                          int nbytes,
463                                          int splice_flags,
464                                          short data) {
465         // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L454
466         return new IoUringIoOps(
467                 Native.IORING_OP_SPLICE, (byte) 0, (short) 0, fd_out, off_out, off_in,
468                 nbytes, splice_flags, data, (short) 0, (short) 0, fd_in, 0
469         );
470     }
471 }