> However, there is an assumption that file I/O will never block "indefinitely"
No, there absolutely is not.
> unless something is severely broken, the kernel will always finish the operation in finite time probably measured in milliseconds at most
Systems get busy all the time and encounter delays larger than this all the time. I have fixed many supposedly low latency systems which incorrectly (as you suggest) assume that local disk writes ought to be fast because usually it hits a disk cache. It's very, very easy to break this assumption, like by copying a moderately sized file.
You cannot assume that a disk write will finish quickly. That is not the guarantee.
> Reads and writes of memory also may block.
Not really, no. There are many orders of magnitude of difference.
> If you really think about it, the only real difference between main memory blocking and disk blocking is the amount of time they may block.
All syscalls take time, but the difference here is many orders of magnitude. If a syscall is expected to take a meaningful (or in the case of i/o, infinitely variable) amount of time we label it a blocking call.
> In fact, memory reads may very well block on disk, if you use swap!
System calls can't swap. High latency jobs will often mark themselves unswappable for exactly this reason, or systems will simply run swapless.
> Given all this, it stops being so clear that async file I/O really makes sense.
No. No no no. This is flatly wrong. You will ship broken systems if you do this and people will have to call someone who knows what they're doing to fix it.
The best you can say is that statistically it won't happen often and maybe your users (or, management) won't notice until it's not your problem anymore.
> But... you can just as easily start a thread in userspace. So... maybe just do that?
Async i/o in glibc was historically implemented as simply a separate thread, fyi (prior to io_uring - I haven't looked in a decade). This is a form of async i/o.
> Not really, no. There are many orders of magnitude of difference.
If the kernel has locked your pages so it can merge or unmerge them under transparent huge pages or if you are using swap, page faults can take a really long time. People who care about async file I/O are probably already ensuring that these circumstances don't come up though.
No, there absolutely is not.
> unless something is severely broken, the kernel will always finish the operation in finite time probably measured in milliseconds at most
Systems get busy all the time and encounter delays larger than this all the time. I have fixed many supposedly low latency systems which incorrectly (as you suggest) assume that local disk writes ought to be fast because usually it hits a disk cache. It's very, very easy to break this assumption, like by copying a moderately sized file.
You cannot assume that a disk write will finish quickly. That is not the guarantee.
> Reads and writes of memory also may block.
Not really, no. There are many orders of magnitude of difference.
> If you really think about it, the only real difference between main memory blocking and disk blocking is the amount of time they may block.
All syscalls take time, but the difference here is many orders of magnitude. If a syscall is expected to take a meaningful (or in the case of i/o, infinitely variable) amount of time we label it a blocking call.
> In fact, memory reads may very well block on disk, if you use swap!
System calls can't swap. High latency jobs will often mark themselves unswappable for exactly this reason, or systems will simply run swapless.
> Given all this, it stops being so clear that async file I/O really makes sense.
No. No no no. This is flatly wrong. You will ship broken systems if you do this and people will have to call someone who knows what they're doing to fix it.
The best you can say is that statistically it won't happen often and maybe your users (or, management) won't notice until it's not your problem anymore.
> But... you can just as easily start a thread in userspace. So... maybe just do that?
Async i/o in glibc was historically implemented as simply a separate thread, fyi (prior to io_uring - I haven't looked in a decade). This is a form of async i/o.