You don't need async for a proper concurrent system. Systems have been concurrent before async IO. The trick is that when a process does an IO you yield it and put it on a wait list and run literally anything else until the kernel receives the OK from the hardware control and resumes the process.
Using Async IO in Linux merely means your specific thread won't be immediately suspended until you get data (or it's in a reasonably close cache)
It would be quite silly if Linux would wait for every IO synchronously, any single core system would immediately grind to a halt.
Linux offers some async io features, but does not offer async throughout.
In a fully async platform you would be able to do general-purpose programming without ever needing to use multithreading.
Example of a situation you can't do in linux: have a program doing select(2)
or equivalent on both keyboard input and network input, in a single thread.
Since linux does not support this, you are steered to adapt solutions that are more complicated than a pure async model would be,
* Spin constantly looking for activity. These heats up your computer and uses battery.
* Have short timeouts on epoll, and then glance for keyboard input. This leads to jerky IO.
* Have child processes block on these operations and use unix domain sockets to feed back to a multiplexor (fiddly, kernel contention).
* The child-process thing but with shmem (fiddly)
* Something equivalent to the child process thing, but with multiple threads in a single process. (fiddly)
You would think that x-windows might help out here. What if you had a socket to X, and then multiplexed on that, instead of looking for keyboard input from a terminal? This opens new issues: what if X has only written half of an event to your socket when select notifies you? Will your X library handle this without crashing?
Rurban's comment above is correct. Linux is not async throughout.
On OSs that offer kevent you can get a fair bit further, but (I believe) you
still can't do file creation/deletion asynchronously.
This is broken. (Woke from a sleep, face-palmed. I have been in Windows IPC land and got my wires crossed, sorry.) In linux you can select on both the stdin fd and network sockets in a single call. There is a way to get a fd for AIO also. AFAIK the sync-only file creation/deletion stands.
Linux is async throughout since it can do task switching on blocking.
You're not the only task running.
Or do you expect Linux to pause the system when you read a file until the DMA is answered?
Linux itself is fully async, anything blocking (even interrupts to some extend) will be scheduled to resume when the reason it blocked is gone or alternatively check back regularly to resume.
A program running on Linux can do a lot of things async as mentioned via POSIX AIO. It's not impossible, go seems to do fine on that front too (goroutines are put to sleep when doing blocking syscalls unless you do RawSyscall).
The conclusion that lack of 100% asynchronity means it can't be properly concurrent is also wrong. As evident that sending something to disk also doesn't not halt the kernel.
There are some Linux specific APIs that build on this and I've got the most experience with Linux so I was refering to that.
But Async IO is part of POSIX.
I was mostly responding to the comment which cited synchronous IO as a problem with POSIX. Linux is most widely used so on top of being my primary domain on the issue, it's going to ensure best understanding.
Is there an example of an os which doesn't have blocking io? To me it seems that blocking io will be needed at some level. You can of course put wrappers around it and present it as async. But in many applications you want to go as low as possible, and in my imagination blocking calls will be the lowest.
It's the other way around. Low level is all async everywhere, blocking is sort of just telling the kernel to wait for async op to complete before running the process.
The goal is to avoid blocking, not to offer async also. That's a lost cause.
Fuchsia once had the goal to offer async only, but then some manager decided that he needs some blocking, and then it was gone.
non-blocking only is lower level than blocking. You can always wait indefinitely for that callback, but usually you have a default timeout.
L4 for example offers that API.