Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

To set nonblocking-mode on streams or not? #218

Open
serzhiio opened this issue Mar 18, 2023 · 1 comment
Open

To set nonblocking-mode on streams or not? #218

serzhiio opened this issue Mar 18, 2023 · 1 comment

Comments

@serzhiio
Copy link
Contributor

Could anyone answer me what is the difference in io-uring bahavior between using non-blocking and blocking streams?

@fabracht
Copy link

I'm not an expert, but I was studying this for my current project, so here's my current understanding of it. I'll use an example with the recv operation on a socket, this could be a stream type socket (TCP).
When you submit a recv operation using a non-blocking socket with io_uring, several steps occur within the kernel. Among them we have:
Submission queue processing: The kernel processes the operations in the submission queue. It reads the io_uring_sqe entries and converts them into kernel-internal request structures. For the recv operation, it initializes an internal recvmsg request.

Polling or readiness check: If the socket is non-blocking, the kernel checks whether the data is available for reading on the socket. If the data is not available, it registers a callback to be triggered when the data becomes available. The kernel also sets the request to be in the "in-flight" state.
Here's a handy link: https://www.kernel.org/doc/html/latest/block/stat.html
Asynchronous execution: The kernel processes the recvmsg request asynchronously. If data becomes available on the socket, the kernel triggers the registered callback and proceeds with the recv operation. Once data is available, the kernel reads the data from the socket into the specified buffer. If the operation is successful, the kernel updates the request structure with the number of bytes read.
This will continue with the completion queue entry and so on.

In the blocking case, the internal mechanism now must account for the fact that the recv operation in the kernel will block, so the kernel must also handle the blocking behavior. Instead of simply registering a callback and setting the request to be in the "in-flight" state, the kernel may need to set up a wait queue or other synchronization primitives, which will block a kernel thread until the data becomes available. This adds an overhead in terms of kernel resource management and increases the complexity of the operation handling. When data becomes available on the socket, the kernel not only triggers the registered callback (as in the non-blocking case) but also needs to wake up the blocked kernel thread, allowing it to continue processing the request. This wake-up process introduces some additional overhead due to synchronization and signaling.

So, I think that the main difference lies in the internal handling by the kernel.

Let me know your thoughts on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants