After checking Threaded.zig I found that all the openDirFile* functions return File with .flags = .{ .nonblocking = false }, does it mean that every file we open will block on read? I am not sure if we suppose to set this flag manually, like the batchAwaitAsync function of the Io interface when implemented as Threaded expects nonblocking to be true for concurrent execution: batchDrainSubmittedWindows
The Io APIs are designed to be blocking from the perspective of the caller. When you want nonblocking you have to explicitly use io.async or io.concurrent depending on your needs. How it accomplishes that is up to the implementation.
On async or concurrent, Threaded will just run the task on another thread using blocking syscalls, since it’s on another thread, the caller of async or concurrent doesn’t block.
Other implementations may take advantage of nonblocking syscalls, and do more complex and efficient task management than threads can provide.
For instance the WIP Evented implementation (idk if its usable yet), uses nonblocking syscalls, and green threads/fibres.
Hmm, so this block is there for some niche builtin usage probably, like this here in Threaded.Environ?
Hmm, say we use Threaded Io implementation to open a file and then use some other implementation to read the file by mistake. Ah, it should get caught early on I assume.
And one last thing I noticed in dirOpenFileWtf16 it should be always .SYNCHRONOUS_NONALERT right? if Threaded Io implementation is supposed to always use the blocking syscall in a background thread.
At least on Linux and the BSDs, I don’t believe that O_NONBLOCK has any impact on normal files.
does it mean that every file we open will block on read?
Yes, because a file is always “ready for reading” on those operating systems. The same as a socket with data in its receive buffer.
Makes sense, zigs progress protocol should never block your program.
In case you are unaware, that is an api and protocol for reporting progress on operations both in a single process and across multiple processes, hence why it has integration with Io.
It also has fancy printing of progress in the terminal, this is what you see when you run the build system, which does use multiple processes.
There will be a DebugIo that should catch this, implementations won’t know what files belong to them unless they track it themselves.
I can’t say how often it would work or break, but it’s the same issue allocators have, just don’t mix them. In fact, it should be easier to not mix Io implementations since you will certainly have less of them compared to allocators.
There is no reason Threaded can’t use non-blocking calls, you already mentioned a case where it should use non-blocking calls.
I think still misunderstand the Io APIs. They will always block the current task, even if they use non-blocking calls.
You use io.async or io.concurrent to create a new task to run code in.
Threaded just puts them on another thread, and generally can’t take advantage of nonblocking calls, but that doesn’t mean you can’t take advantage of nonblocking calls. The progress protocol for example should never block even in a single threaded environment.
On the other hand, Evented will be able to take advantage of non-blocking calls and switch the task being run on the thread, allowing concurrency even in single threaded environments.
I get it, I mentioned that because once somewhere read that for NtRead/NtWrite to work properly in a blocking manner, you usually have to open/create the file with FILE_SYNCHRONOUS_IO_* flag but I couldn’t find the doc anymore maybe I missed something that time, but anyways if that were the case we will find it out sooner or later. Thanks.