Hi,
I just discovered yet another problem that arises for overlapped I/O on normal disk files, more correctly, for any file on a block device.
Obviously IO requests on block devices on Linux are _always blocking_. I wrote a very simple test program for reading from a floppy disk and found exactly this behaviour, no matter if O_NONBLOCK was set or not. "man 2 open" also says that O_NONBLOCK may or may not have any effect on non-socket fd's and for block devices it clearly has none.
I don't know the reason for this, but it may have to do with Linux' caching algorithms. This means that
- with ReadFile() etc. on regular files, the asynch code will never be executed. Instead, the call will block when trying to read immediately, and then return success.
- I am not 100% sure in what context the asynchronous handlers are executed, but the read() write() calls there will be blocking as well. I assume this is not what we want.
- I guess that for programs that "know" some IO is going to take a lot of time (read()s on floppies, network file systems, ...) will potentially be broken if they try to do overlapped IO and "do something else" while the IO is executing. I do see the need, therefore, to have an approach that mimics Windows' behaviour here.
- The only simple approach that I can see for making this happen is creating a separate thread for reading/writing asynchronous IO. The simplest approach would actually be to do a clone() for each async request with CLONE_FILES | CLONE_VM | CLONE_PARENT. I don't know how this would fit into Wine's general synchronization approach - please give me hints.
- The separate thread itself would be very simple for files on block devices, because it can simply execute the blocking read and finish when the read finishes, leaving some status information somewhere.
- For other devices that _do_ support O_NONBLOCK, it may be cool to mimic this simple behaviour by clone()ing too, dup() ing the fd, resetting the O_NONBLOCK flag, and doing a blocking IO request just the same. That means to basically leave it up to the kernel to handle synchronization.
This would also mean that we wouldn't have to worry about differences between files and sockets/pipes, because I'm 99% sure the kernel would do it right.
I don't understand the concept of the wine service thread well enough yet to judge if that could be used for doing what I just suggested. Perhaps someone can help me out with that, I'll be studying the sources in the meantime.
Cheers, Martin
PS. I guess another possible approach would be using raw I/O, but I am very certain this is not what we want.