News for hackers. Stuff that matters.
Re:What's So Bad About Posix I/O? by jhallenworld on Tuesday September 12, 2017 @12:29AM (#15224826)
I'm surprised there is no mention of the lack of non-blocking filesystem reads and opens. In other words, I should be able to submit a read request, and then select()/poll()/epoll() for when the data is available like network I/O.
Re:What's So Bad About Posix I/O? by geocar on Tuesday September 12, 2017 @02:35AM (#15225250)
Most unixes (including Linux) always report files to be readable under select()/poll()/epoll() so this doesn't actually help read from disks (even when they're backed by network/shared storage). That's why you often see this kind of seeming "nonsense" in HPC startup scripts:

    for x in *; do cat "$x" & done | pipeline ...
Furthermore, in a networked-environment, select()/poll()/epoll() actually decrease concurrency compared to threads because now you need another system call to go fetch the data from the kernel. If I've got the CPUs I'd rather use threads.

In the Windows model (in contrast), the programmer says "when this data is available (from this socket, file, etc), put it here (into this memory buffer)" and then waits for the kernel to do something. As a result, you skip that extra syscall -- but you also skip any other read you might have needed to do for data that's arrived at (roughly) the same time. AIO[1] is potentially similar, but it never seems to benchmark well in my experience.

[1]: http://man7.org/linux/man-pages/man7/aio.7.html

Re:What's So Bad About Posix I/O? by gpderetta on Tuesday September 12, 2017 @04:36AM (#15225739)
> Most unixes (including Linux) always report files to be readable under select()/poll()/epoll()

There is no other choice really. Let's say you want to read a specific page from a file. No page is currently in the kernel buffers. If poll where to return non-ready (and remember that poll has no idea which pages you are interested in), what action, within posix, would you take to change it?

poll and friends just do not make sense for plain file descriptors. In linux, splice add an interesting twist, but it is still awkward to use.

Re:What's So Bad About Posix I/O? by geocar on Tuesday September 12, 2017 @05:56AM (#15226016)
> Let's say you want to read a specific page from a file.

pread() is an unusual case. I'd be happy if poll() simply indicated read() would succeed, and I'm happy doing an lseek() before every read().

However a pread() with O_NONBLOCK could return EAGAIN and poll() would then know what pages I'm interested in.

> what action, within posix, would you take to change it?

The general (POSIX-compatible) strategy (as I indicated) has been to fork a thread off to handle reading so that my application is notified when the data is in the fifo. This works for me when I'm reading (say) five files from a slow (or remote) storage, but it's not ideal since it causes a copy.

Re:What's So Bad About Posix I/O? by gpderetta on Tuesday September 12, 2017 @06:05AM (#15226054)
poll can't guarantee that the next read will succeed because first of all doesn't know how many pages you are interested in reading and any relevant page in the page cache might be evicted between the poll and the read.

Also having pread, which is designed for concurrency and scalability, carry state around for poll (an unbounded amount of state btw: you can have multiple threads issuing concurrent preads on the same fd) makes it completely pointless.

There are linux patches floating to add flags to preadv2 so that on a page not present it returns EAGAIN, so that you can optimistically do a sync read an fall back to a thread pool in the slow case. It still doesn't involve poll and friend.

Re:What's So Bad About Posix I/O? by geocar on Tuesday September 12, 2017 @07:53AM (#15226520)
poll() can't guarantee that the next read will succeed anyway, because something else might drain the socket or fifo (e.g. another thread). Programmers simply use O_NONBLOCK anyway and use poll() is wait until the process should try again.
Re:What's So Bad About Posix I/O? by hoytech on Tuesday September 12, 2017 @10:03AM (#15227321)
I agree completely. Pedantically, there is one other option: return an error like windows select does (WSAENOTSOCK). But then apps need special cases to deal with files and life is horrible.
Re:What's So Bad About Posix I/O? by Jasper_ on Tuesday September 12, 2017 @12:28PM (#15228685)
> If poll where to return non-ready (and remember that poll has no idea which pages you are interested in), what action, within posix, would you take to change it?

readahead(2) ? posix_fadvise(2) ?

Re:What's So Bad About Posix I/O? by cturner on Tuesday September 12, 2017 @01:50PM (#15229520)
From man page of readahead(2), "readahead() blocks until the specified data has been read." The other one claims async functionality. But says it is not reliable.

An idea for how it could be implemented in linux: kernel would offer a new kind of file descriptor. It would have a limited, in-kernel buffer, much like a socket has an arrival space. Once you have it, call something like,

   newkind_page_copy(newkind_fd, disk_fd, page_count, timeout) 
Timeout could be unlimited.

The buffer would behave like socket for the purpose of the read and error lists in select/poll/epoll. If you closed either descriptor, it goes to error-state. Within the kernel, it would watch real_file_fd, using code to similar to whatever is underneath inotify. Like inotify, this would not work for NFS.

Re:What's So Bad About Posix I/O? by Jasper_ on Tuesday September 12, 2017 @02:58PM (#15230527)
> From man page of readahead(2), "readahead() blocks until the specified data has been read."

? What man page are you reading? The goal of readahead is to prime the cache and return immediately. http://man7.org/linux/man-pages/man2/readahead.2.html

Re:What's So Bad About Posix I/O? by cturner on Wednesday September 13, 2017 @03:02PM (#15241496)
I quoted from this one, https://linux.die.net/man/2/readahead

There is a second obstacle I have in mind, around the robustness of this. Imagine if we had an implementation of that which reliably returned quickly. But we take our time doing the subsequent read. By the time we do, the value has already been chased out of the cache. It is an edge-case, and you could probably avoid it in practice, but it would be significant effort to to verify your mechanism, and would create cognitive load.

Re:What's So Bad About Posix I/O? by twic on Tuesday September 12, 2017 @09:07AM (#15226944)
I think this would be pretty straightforward if O_NONBLOCK was allowed to have an effect for regular files. The rules would be:

1. If a read for a range of bytes on a non-blocking file descriptor can be wholly or partly satisfied from the cache, put that data in the read buffer, and return the amount of it

2. If a read on a non-blocking file descriptor can't be satisfied from the cache, return -1, set errno to EAGAIN, and kick off an asynchronous task to load that range of bytes into the cache (an 'asynchronous load')

2a. If there is already an asynchronous load for that range running, don't start another one

3. When an asynchronous load finishes, mark that range as available

1a (surprise!). If that range of bytes was marked as available, remove the mark

4. If there are a nonzero number of available ranges for a file descriptor, return POLLIN from poll()

The way a program with lightweight threads (Node, Go, etc) would use this:

1. Open files as non-blocking

2. Make reads as usual

3. If a read succeeds, or fails other than with EAGAIN, pass the result to the thread and carry on

4. If a read fails with EAGAIN, suspend the thread, and remember the range it was reading

Meanwhile, in a background IO thread ...

5. Repeatedly poll all file descriptors for which there are remembered reads

6. If a file descriptor shows up as POLLIN, run through all the remembered reads for it, and make them again

7. If a read fails with EAGAIN, cool, leave it remembered and carry on

8. If a read succeeds, or fails other than with EAGAIN, pass the result to the thread and resume it

Would that work?

I haven't really thought about partial results of asynchronous reads. If a read asks for two blocks, and one gets loaded, should poll return POLLIN or not? I lean towards yes, because the program can make use of that data. That raises the question of whether to remove the availability mark after the following read. Again, i lean towards yes, because it means asynchronous reads have the same behaviour as ones which partially hit cache. The OS can carry on reading the rest of the range into the cache, but it won't signal the arrival of that data to the program. That should be fine, as the program will probably try to read it soon anyway.

If a program takes too long to get round to reading data once it is available, it might have been pushed out of the cache by then. Too bad. The read will fail with EAGAIN and the whole cycle repeats.

If two threads in a program independently read the same range, only one asynchronous load will be run, and only one thread will end up removing the mark. Programs will need to be careful not to trip up over this; they probably need to coalesce reads on their side of the API.

It sucks to have to retry every outstanding read for a file when it shows POLLIN, but i can't see a way to return information about which ranges are available through the existing calls. A program could keep its list of outstanding reads in time order, scan it from earliest to latest, and stop when it gets a non-EAGAIN result. If there is more than one available range, poll will return POLLIN again and the program will go back and pick it up. If asynchronous loads complete one at a time in order, this reduces the cost to O(1), with a smooth increase in cost as that is less and less the case.

Basically, what i'm saying is that everyone should just implement the kqueue API from BSD.

Re:What's So Bad About Posix I/O? by wahern on Tuesday September 12, 2017 @05:22PM (#15232892)

  2. If a read on a non-blocking file descriptor can't be
  satisfied from the cache, return -1, set errno to EAGAIN,
  and kick off an asynchronous task to load that range of
  bytes into the cache (an 'asynchronous load')
The way Windows and Unix operating systems are written, that "asynchronous load" will always be implemented by using a pool of kernel-scheduled threads. The filesystem is a stack of software, several layers deep, with tentacles reaching all over the place (e.g. modern file buffer and VM page caches are unified). Existing APIs and implementations simply do not support truly asynchronous operation throughout the entire stack. This is one reason why AIO on Linux is limited to direct I/O--to cut out all the middle layers--and even then it's not truly asynchronous (e.g. file opens). Windows asynchronous I/O just uses a kernel thread pool. So does FreeBSD. And so does every Linux proposal for buffered AIO.

If you want pollable file reads, just use eventfd and roll your own. Linux threads are lightweight enough that there's not much reason to care whether they're "kernel" or "user" threads. But pollable file I/O will really only be a win for streaming reads and writes, so you could just use sendfile(), in which case you're reading or writing to a pollable socket; you use a dedicated thread pool to pump data from sockets to the file descriptors, or vice-versa, without any copying.

BTW, Go doesn't need this solution (timeouts notwithstanding) because Go schedules multiple goroutines across multiple kernel-scheduled threads.

If you're really worried about file I/O latency, you should be at least as worried about VM pagefault latency. I disable swap on all my Linux servers. And I also disable overcommit. But my languages of choice (C and Lua) are capable of gracefully handling allocation failure (contrast Python or Go), and I implement my solutions to handle allocation failure without crashing the entire service. Too many other languages make the assumption that memory is infinite. (Alas, large parts of the Linux kernel do this as well, even with overcommit disabled :( Solaris and Windows are the only major OSs I'm familiar with that implement strict and rigorous memory accounting, permitting the system to stay alive (and consistent) under memory exhaustion. FreeBSD might as well, I'm not sure.

Re:What's So Bad About Posix I/O? by crest on Wednesday September 13, 2017 @08:38AM (#15237673)
In theory FreeBSD supports a sane aio_read/write/fsync() implementation by extending sigevent to include the generation of kqueue events, but there are no aio_open/close/fstat/rename() syscalls and if you need a thread pool to deal with those remaining blocking file system calls there are few advantages to using the in-kernel thread pool implementing the aio_*() syscalls. An other problem is that filesystem aio calls are limited to local file systems, because accesses to network file systems could block indefinitely starving local file system accesses by blocking all threads in the pool.
Re:What's So Bad About Posix I/O? by FooBarWidget on Tuesday September 12, 2017 @02:43AM (#15225273)
What is surprising to me is that it is 2017 and nobody has attempted to solve these problems. Maybe the current mechanisms, with all their faults, are considered good enough?
Re:What's So Bad About Posix I/O? by geocar on Tuesday September 12, 2017 @04:11AM (#15225626)
I think that's unfair: A lot of people have attempted to solve these problems(), and the Windows Way™ has it's own problems. The real answer is probably between elastic infrastructure and the fact that computers got faster and cheaper, and so -- at least for a while the number of people needing solutions here went down.

https://lwn.net/Articles/219954/

* https://lwn.net/Articles/223899/

* https://lwn.net/Articles/221913/

* https://lwn.net/Articles/316806/

* https://lwn.net/Articles/612038/

* https://lwn.net/Articles/671658/

* http://www.fsl.cs.sunysb.edu/~vass/linux-aio.txt

* http://ogris.de/howtos/splice.html

And so on.

However a few companies have seen real commercial benefit from actually analysing their data, so we're seeing a lot of "big data" interest. Some of these companies have noticed that a bunch of hadoop/mongo/whatever boxes can't even approach the performance of one "big" box tuned right, so we're seeing somewhat of a resurgence in interest here.

Re:What's So Bad About Posix I/O? by int_19h on Tuesday September 12, 2017 @05:28AM (#15225928)
> and the Windows Way™ has it's own problems

Could you expand on that?

(I'm assuming that by the "Windows Way", you mean I/O completion ports.)

Re:What's So Bad About Posix I/O? by dom0 on Tuesday September 12, 2017 @04:54AM (#15225809)
Other systems (Windows and I think Solaris, but some more obscure systems likely do this as well) can do asynchronous disk IO, but it's not perfect, either.

I think the main reason Linux doesn't really do it is that asynchronous IO is an intrusive change and there would be just too much work to implement it in all the file systems etc.; i.e. "not worth it".

Many applications which are not OK with synchronous disk I/O seem to find thread pools good enough: reasonably easy to implement, reasonably portable, usually performs ok.

Re:What's So Bad About Posix I/O? by adrianratnapala on Wednesday September 13, 2017 @10:40AM (#15238708)
I only half buy the "not worth it".

Traditional unix, including Linux pretends to support poll() etc for file I/O (i.e. it supports the interfaces, but the reality is synchronous). The reason for this is that an application that expects async I/O can kinda-sorta-work with real files -- and "kinda sorta" will not be too bad because local disks are fast enough to paper over any problem.

But then if the disks aren't local, why not actually make non-blocking I/O work as advertised?

Actually I can guess the answere: there are 101 corner cases that mean I can't neatly separate out the apps design for noblocking I/O. And that's why I half buy the argument.

But only half.

Re:What's So Bad About Posix I/O? by AstralStorm on Tuesday September 12, 2017 @03:24AM (#15225438)
Generally epoll and event io are good enough for millions of simultaneous files or sockets. Nobody tells you to use direct read or write instead of mmap either.
Re:What's So Bad About Posix I/O? by cturner on Tuesday September 12, 2017 @01:31PM (#15229325)
Mmap - I can't think of a scenario where it improves over read or write in the context discussed here: async access. Mmap is synchronous, and you can't do select/poll on it.
Re:What's So Bad About Posix I/O? by geocar on Wednesday September 13, 2017 @09:46AM (#15238165)
Re:What's So Bad About Posix I/O? by cturner on Thursday September 14, 2017 @03:02PM (#15251384)
Not sure why you were downvoted.

That's some seriously hairy stuff there. I reckon I'd move to building my app as a kernel module more readily than trying to make a robust async arrangement using that mechanism :) Call me demanding, but I think we should can reasonably expect easier access to async from our OS than this mechanism offers.

On that topic of which.. how's the future of operating systems coming along?

Re:What's So Bad About Posix I/O? by mfukar on Tuesday September 12, 2017 @04:05AM (#15225598)
Those problems are already solved by async I/O in platforms other than Linux.
Re:What's So Bad About Posix I/O? by exDM69 on Tuesday September 12, 2017 @05:03AM (#15225837)
You can't do that with normal read/write and select/poll/epoll, but you can either use aio (posix) or io_submit (linux-specific).

In my opinion, a big issue with these is that asynchronous i/o requests can not be used with select/poll/epoll, but rely on other notification methods instead. AIO can use unix signals (ugh) or thread notification (see sigevent(7)) to signal completion. io_submit uses io_getevents to read events about completed I/O requests.

From a userspace programmer's point of view, it would make much more sense if io_setup() would return a file descriptor that could be used with select/poll, and io_events would be read() from the fd.

Currently it's impossible (?) to have filesystem i/o in the same select/poll loop with your network i/o because of this issue. This is why libuv falls back to using threads and synchronous i/o to provide "async" i/o.

Re:What's So Bad About Posix I/O? by derefr on Tuesday September 12, 2017 @05:51AM (#15226004)
> Currently it's impossible (?) to have filesystem i/o in the same select/poll loop with your network i/o because of this issue.

Hacky workaround: don't do filesystem i/o in the first place. Have the kernel serve an iSCSI target, then consume it over the loopback interface entirely in userspace. Your disk now has network semantics! (But you have to bring your own filesystem driver.)

If you don't mind some extra abstraction overhead, you can skip past iSCSI and instead build a userspace NFS client lib into your app, consuming a loopback NFS share. s/NFS/9P/ if your disk server has in-kernel 9P.

(Is there any use to these approaches? Yes: they're actually nearly-optimal ways to persist state from a unikernel running on a hypervisor, because all the disks are remote one way or another anyway. Erlang on Xen uses the 9P approach, for example.)

Re:What's So Bad About Posix I/O? by sitkack on Tuesday September 12, 2017 @09:01AM (#15226898)
This aligns all semantics and removes file io as special case? Unikernels appear to be a good way to evolve past Unix.
Re:What's So Bad About Posix I/O? by MichaelMoser123 on Tuesday September 12, 2017 @05:26AM (#15225919)
you can do io_submit from one thread and then have some dedicated threads do io_getevent + event signalling (comes at a price though).

Still all this event goodness is not good enough for things like infiniband and the brave world of zero copy networking.

Re:What's So Bad About Posix I/O? by exDM69 on Tuesday September 12, 2017 @06:05AM (#15226062)
Yeah, sure that kinda works but it won't play nice with having an event loop on network events. A typical high performance server has multiple worker threads waiting on events on a select/epoll and if you add in another thread (or several) waiting on io_getevent you end up in a rather contrived solution.

You could use a pipe or eventfd or some other fd-based mechanism to wake up a worker thread on a filesystem event, but then you get two context switches (one to wake up io_getevent thread and another to wake up a worker). This carries a lot of indirect costs from jumping back and forth to the kernel.

I am unaware of a solution that would make filesystem i/o and network i/o play nice in one event loop without adding some overhead.

Re:What's So Bad About Posix I/O? by fulafel on Tuesday September 12, 2017 @01:06AM (#15224942)
Threads are less of a problem with file i/o, because usually a process doesn't need to have 10000 outstanding disk io requests.

(Windows async disk i/o is thread-backed too behind the scenes, though)

Re:What's So Bad About Posix I/O? by useerup on Tuesday September 12, 2017 @03:46AM (#15225522)
Windows async I/O ("overlapped" in Windows parlance) is backed by a thread pool (completion ports).

Windows does not spin up or allocate a thread just to wait for an IO operation to complete. Rather, when an IO operation completes, a thread is allocated from the thread pool (hence the name completion ports) on which the callback happens.

So there is no excessive allocation of threads. Everything is event-driven and kernel managed until the operation completes.

Re:What's So Bad About Posix I/O? by emn13 on Tuesday September 12, 2017 @04:00AM (#15225583)
Simultaneously, people overestimate the costs of threads, and underestimate the efficiencies they provide. At extremely high loads, they become an issue, but it's quite rare. And at normal loads, threading is (IME) often simply more efficient than typical async solutions in practice, probably since a thread gets synchronized access to its internal state and consistent ordering of execution (almost) for free, whereas async code needs to (usually) reimplement that in user mode.

People have taken the notion that threads are slow in some circumstances and made the conclusion that threads are slow, period. But that's simply not true.

Re:What's So Bad About Posix I/O? by dom0 on Tuesday September 12, 2017 @04:59AM (#15225828)
The rate of computation is obviously very similar for threads and async, but the rate of multiplexing is not. Switching between processes or threads takes more time than switching between fibers/coroutines. So the general observation that for massively multiplexed workloads fibers/coroutines are lower overhead is generally correct, but the more interesting question is of course "what qualifies as a massively multiplexed workload?" ... I'd argue most kinds of web application servers don't.
Re:What's So Bad About Posix I/O? by emn13 on Tuesday September 12, 2017 @08:14AM (#15226620)
Yeah, and the devil is really in the details there; not all context switches are created equal. If you're dealing with less than (rough ballpark) 1000 requests per core per second, there's just no way context switching is going to be anywhere near a bottleneck. Depending on all those details (app/OS/processor/lunar cycle), you may be able to deal with 10 to 100 times as many before context switching is an issue.

Those kind of servers are simply quite rare (IME). Nothing wrong with interesting problems in niche spaces, but it's not something you should be worrying about by default.

(No idea what "big" servers provide public stats, but e.g. https://nickcraver.com/blog/2016/02/17/stack-overflow-the-ar... ) lists a random day for stackoverflow having 209,420,973 http reqests, i.e. a little less than 3000 per second. I doubt context switching is going to matter for them (in the hypothetical world all this was served by one HTTP server, which of course it isn't).

Re:What's So Bad About Posix I/O? by dhd415 on Tuesday September 12, 2017 @11:42AM (#15228209)
I largely agree with the above and I would say that 1000 reqs/sec is probably a decent threshold for considering when async IO is going to matter for performance. That said, the details of your particular workload may benefit from async IO at significantly lower levels. As an example, one message routing application on which I worked with a typical workload of ~100 reqs/sec increased its performance by about 5x when switched from a blocking thread per request model to async IO. The application typically maintained a larger number (500-1000) of open but usually idle network connections. With that particular workload and on that particular platform, the overhead of thread context switching became a significant factor at much fewer than 1000 reqs/sec. One hint that this was the case was relatively high percentage (30%+) of CPU time spent in kernel mode. Switching to async IO dropped kernel time to about 5% on this particular application.
Re:What's So Bad About Posix I/O? by emn13 on Wednesday September 13, 2017 @07:36AM (#15237269)
Yeah, that's a neat case in point (and illustrates nicely that there are cases where async is super-valueable!).
Re:What's So Bad About Posix I/O? by fulafel on Tuesday September 12, 2017 @11:27AM (#15228059)
You can do ~ 1 million thread context switches per second, per core. That's a lot of disk operations in flight before the context switch overhead becomes a large component in your performance equation. Multiply that by 10-20 cores for a server CPU, too. If you still haven't pegged your storage hardware IOPS, I'd say you have a "happy problem" :)
Re:What's So Bad About Posix I/O? by adrianratnapala on Wednesday September 13, 2017 @10:44AM (#15238748)
I never imagined that the cost of threads was predominantly a performance cost (though obviously that exists too in some parameter regimes).

The real cost of threads is that threaded code is far more difficult to get right than non-threaded code. The closest thing I know of to an excuse for using threads is that we are already using threads, so all the complixity is already there.

After all, once every line of code is already a potential race condtion, it hardly matters if you turn a few more of them into real ones.

Re:What's So Bad About Posix I/O? by gpderetta on Tuesday September 12, 2017 @05:51AM (#15226003)
the problem with threads is that unless you spawn an ungodly amount of them, you might still not be able to issue enough pending blocking disk IO operations to saturate the disk bandwidth.
Re:What's So Bad About Posix I/O? by joosters on Tuesday September 12, 2017 @08:48AM (#15226823)
AFAIK, there's no reason why an OS can't make filesystem I/O non-blocking with the standard read/write/select (or poll or whatever) system calls.

The only tricky part (API-side) is that write() is defined to confirm that some data got written, or not. If you let write() become non-blocking, and deferred the I/O, perhaps by returning immediately with EAGAIN or some such response, the write is is an unknown state to the rest of the application. What data can then be expected from other read() calls on that file from the same process? The old data? The new? A mix? You'd have to drop the POSIX consistency guarantee. For most programs, this is never likely to be an issue, as they don't tend to be re-reading bits of a file that they are also writing to, so it's a shame there's no option to let the write() be non-blocking if requested.

Issue 2 is failures: If the write, when it eventually happens, fails, you've got to have some way of passing that information back to the process. The solution for this seems easy enough; just let the FD become writeable again and the program will probably re-attempt the same write, at which time you can report the previous error.

Finally, making open() calls non-blocking would be the real API changer. If you defer all of the file opening work and give the application a file descriptor before doing any I/O, then you can hit all kinds of errors (permissions problems, file not found, and so on). How do you pass them back to the program? You can make any future read() or write() calls fail but these syscalls would now have to return error codes that they aren't specified as actually being able to return (read can't return things like EEXIST, EACCESS and so on). So the API is inadequate for these situations. You can see how they could be extended to cover these cases though.

Re:What's So Bad About Posix I/O? by jzwinck on Tuesday September 12, 2017 @09:30AM (#15227090)
File write could work the same as socket send. If the data cannot definitely be written now, write nothing and allow the application to try again, probably after waiting for readiness via poll or select.
Re:What's So Bad About Posix I/O? by hoytech on Tuesday September 12, 2017 @10:06AM (#15227342)
See gpderetta's comment elsewhere in this thread: the page-cache is different than socket mbufs in some pretty significant ways.
Re:What's So Bad About Posix I/O? by api on Tuesday September 12, 2017 @01:00AM (#15224924)
I thought you could, at least on Linux.
Re:What's So Bad About Posix I/O? by sgift on Tuesday September 12, 2017 @02:37AM (#15225255)
You can on (more or less) any modern OS, but it's not part of POSIX, it's platform specific.
Re:What's So Bad About Posix I/O? by xfer on Tuesday September 12, 2017 @03:19AM (#15225423)
It is part of posix, it's called posix AIO, but working with it is a massive pain.