No. They would return E_AGAIN after the data has been read or written in blocking mode. If select comes back and says "read is ready on socket 4" then user code does read on socket 4 and gets (say) 4K of data followed by E_AGAIN. Getting that 4K of data happens in a blocking mode. To make it non-blocking you would provide a pointer to your user space buffer to the kernel and it would determine when IO is ready _and_ proceed to put that data in the buffer.
The way you are using the term "blocking" is non-standard and not that useful. You are calling the syscall "blocking" just because it performs its work inline (in this case, copying a kernel buffer into a user-space buffer). By this definition, every syscall is blocking, even aio_read() because even aio_read() performs some work inline (namely enqueing a read request).
In common usage, an I/O operation is considered "blocking" if the system call does not return until data is available. If on the other hand you set O_NONBLOCK on a fd, you will get EAGAIN when no data is available, so clearly that is the accepted meaning of "nonblocking."
> You are calling the syscall "blocking" just because it performs its work inline.
Yes because there is _another_ mode of IO where it doesn't have to do that. So the reason that is called "blocking" is because there is another mode of operation (albeit it is exotic) where the process does not block while performing IO -- the kernel reads/writes the data on behalf of the process. If this second mode of performing IO did not ever exist you could just interchange arbitrarily asynchronous and non-blocking as synonyms.
Since you didn't bother reading the link I posted here is the basic matrix of IO operations:
I think the DeveloperWorks article you've cited is simply wrong, and that's sent you into a tailspin. Select and poll aren't "ways to implement asynchronous blocking I/O".
I think you'll find these links more helpful than the misleading one you've been using.
> Since you didn't bother reading the link I posted here is the basic matrix of IO operations.
Actually I did. You are misinterpreting what it is saying. The reason it is calling the select() model "blocking" is because you block during the select(), not because the read() itself is blocking.
This is also non-standard usage: most people wouldn't refer to a select()-based loop as blocking I/O, because a program generally only calls select() when it has nothing else to do but service I/O, so the select() does not "block" the application.
A process blocks when it needs to be rescheduled, yielding back to the process scheduler pending I/O. That's what "block" means. It doesn't mean "all the time consumed by any operation performed by the process". For instance, a process doesn't "block" when a hash table lookup unexpectedly trends O(n) due to collisions.
On a nonblocking socket, the I/O operations you're talking about are simple u/k and k/u buffer copies.
I think between aio_+ and the C10k page, you may have gotten a bit scrambled. Whether you have an event loop or not, disk I/O is often transparently blocking, even when you try to set descriptors nonblocking. But I/O operations on a nonblocking socket don't wait the process. If there's data in the buffer, you get the data; if there isn't, you get the error.
> On a nonblocking socket, the I/O operations you're talking about are simple u/k and k/u buffer copies.
But because there is an IO mode where these copies are done by the kernel when data arrives not by the user process (after a kernel notification), there is now a differentiation between blocking and asynchronous. Asynchronous refers to IO readiness notifications, "blocking" refers to the copying of data (the actual IO if you will).
> A process blocks when it needs to be rescheduled, yielding back to the process scheduler pending I/O. That's what "block" means.
However when your process is copying data it is in the running state and preventing other processes from running. It could be doing something else or it let other processes run in the meantime.
> The I/O operations you're talking about are simple u/k and k/u buffer copies.
That is true, however if the data comes in very small chunks very fast you are doing a lot of switching to user space and a lot of small context switches to, say copy 1K of data. When you could just request that the kernel fill up your 10MB buffer with data from a socket and tell you when it is ready. If there is anything I learned is to never just say "it is a simple copy". Today's memory is not very fast compared to CPU speeds and copying is not something to be taking lightly. It is one thing when looking at a toy example, another thing when dealing with realtime systems or large data sets.
A blocked process is a process which is not in a running or ready state in the kernel. The userland process entering the kernel on its stack isn't sufficient to change this state; nor is starting or finishing a memory copy operation, particularly one which is done on the CPU (things might be different if DMA were involved). Blocked, running, ready etc. are process scheduling concepts and are about sharing a limited resource, specifically the CPU. A process busy copying memory, but using the CPU, is not blocked, because another process may not be running on that CPU instead.
I don't believe that "blocking" refers to the copying of data. I don't believe that a process can be "blocking" and "running". Where are you getting this from?
I guess "blocking" is overloaded here. To me it refers to the process of performing IO, but you think about process states from the point of view of the scheduler (as in RUNNING state vs BLOCKING (or IOWAIT)).
Yes, if aio_* system was never invented, we wouldn't be arguing, but because it exists it introduces a new possible way of doing IO. It is a general enough way of doing IO and at hardware level we have DMA but in the land of syscalls we have aio_.
Ok, just curious, what words would you use to describe what aio_ calls do?
Over the years many have thought of a way to bring that style of IO to networking. So far it works for disk IO very well. For example take a look at this benchmark from lighttpd for a sendfile:
It looks like there is a consistent 50% improvement in speed when using aio with a 1MB block.
Wouldn't it be nice to have that kind of improvement for network sockets as well? I think it would be and there have been many attempts over the years but nothing good yet has happened.
It would be good to have more I/O API calls available that don't require as much copying but so far there simply aren't any such APIs that are mature and stable. POSIX AIO is only supported in a very limited way; on Linux it only works for files, not sockets. splice() only works between files/pipes and TCP sockets but not Unix domain sockets. Etc etc.
I am not talking about in-kernel hardware mechanisms like DMA and such. Or about memory mapping a file. It is about the system call interface to perform IO. Yeah, I guess you can call it memory-mapped but I don't think that is quite accurate in this context.
The system call interface to perform I/O cannot be described as "memory mapped"; the read/write system calls are programmed I/O. The opposite of memory mapped. You're letting terminology get you into trouble. You should just let go of your definitions and make the broader point you're trying to make, which might still be salvageable.
I agree, "memory mapped" is the wrong term. I was just letting the original poster who called it this way keep that as a concession or a mental model. That was my mistake as it just confuses everyone even more.