io_uringIt’s easy to poll an fd. First initialize io_uring object (io_uring_queue_init) and get SQE (io_uring_get_sqe) as all
io_uringOperations are necessary, as described above, there is no much explanation here. Once you get the sqe, initialize the SQE pointer using io_uring_prep_poll_add.
static inline void io_uring_prep_poll_add(struct io_uring_sqe *sqe, int fd, short poll_mask);
The first parameter is the SQE pointer obtained earlier; the second parameter is the file descriptor you want to poll; and the third parameter is the flag bit, where io_uring does not introduce a new flag (macro), but follows.
poll(2)Defined flags, such as POLLIN, POLLOUT, etc.
Like other I/O requests, each SQE can set a user’s own value inside, using
You can see that only one poll request can be added at a time. If there are more than one fd, the call is repeated
io_uring_get_sqeGet multiple SQE pointers separately
io_uring_get_sqeIt’s not that system calls don’t go into the kernel.
io_uring_prep_poll_addIt is simple structure parameter assignment, so there is no speed problem.
Use after adding the required request
io_uring_submitUniform submission and use
io_uring_peek_cqeOperations such as obtaining completion are consistent with standard asynchronous I/O requests.
io_uringThere is a big difference between polling and epoll, poll’s default mode.
io_uringPolling always works in one-shot mode (equivalent to epoll’s)
EPOLLONESHOTThat is, once a poll operation is completed, the user must resubmit the poll request or no new event will be triggered, thus ensuring that each poll request has and only one response. Then, since it is one-shot mode, there is no difference between LT and ET modes in epoll.
Clear the polling request in progress using io_uring_prep_poll_remove
static inline void io_uring_prep_poll_remove(struct io_uring_sqe *sqe, void *user_data);
It also needs SQE and submit. You can see that this function is very specific and directly requires the user_data parameter. The kernel deletes requests with equal values by comparing the user_data submitted previously with the user_data you now specify.
The initial requirement in network programming is asynchronous listening for client access (O_NONBLOCK accept), which is also a code example of many epolls. use
int sockfd = socket(...); bind(...); listen(...); struct io_uring ring; io_uring_queue_init(32, &ring, 0); struct io_uring_sqe *sqe = io_uring_get_sqe(&ring); io_uring_prep_poll_add(sqe, sockfd, POLLIN); io_uring_submit(&ring); struct io_uring_cqe *cqe; io_uring_wait_cqe(&ring, &cqe); int clientfd = accept(sockfd, ...);
Personal feeling if take
io_uringThere is no advantage in doing polling alone. take
io_uringThe most useful thing about polling is to monitor and process the completion events of polling and AIO in a unified way. Imagine using clientfd immediately after you get it
io_uring_prep_readvRead the request body and reuse it
io_uring_prep_poll_addAccept access from other clients, which is really asynchronous programming.