0

How does one actually use kqueue() for doing simple async r/w's?

It's inception seems to be as a replacement for epoll(), and select(), and thus the problem it is trying to solve is scaling to listening on large number of file descriptors for changes.

However, if I want to do something like: read data from descriptor X, let me know when the data is ready - how does the API support that? Unless there is a complimentary API for kicking-off non-blocking r/w requests, I don't see a way other than managing a thread pool myself, which defeats the purpose.

Is this simply the wrong tool for the job? Stick with aio?

Aside: I'm not savvy with how modern BSD-based OS internals work - but is kqueue() built on aio or visa-versa? I would imagine it would depend on whether the OS io subsystem system is fundamentally interrupt-driven or polling.

2 Answers2

1

None of the APIs you mention, aside from aio itself, has anything to do with asynchronous IO, as such.

None of select(), poll(), epoll(), or kqueue() are helpful for reading from file systems (or "vnodes"). File descriptors for file system items are always "ready", even if the file system is network-mounted and there is network latency such that a read would actually block for a significant time. Your only choice there to avoid blocking is aio or, on a platform with GCD, dispatch IO.

The use of kqueue() and the like is for other kinds of file descriptors such as sockets, pipes, etc. where the kernel maintains buffers and there's some "event" (like the arrival of a packet or a write to a pipe) that changes when data is available. Of course, kqueue() can also monitor a variety of other input sources, like Mach ports, processes, etc.

(You can use kqueue() for reads of vnodes, but then it only tells you when the file position is not at the end of the file. So, you might use it to be informed when a file has been extended or truncated. It doesn't mean that a read would not block.)

I don't think either kqueue() or aio is built on the other. Why would you think they were?

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • Thanks for the answer. Ya when I said "descriptors" I meant it in the general sense, though obviously it was built targeting sockets/pipes. I'm not sure why I though they wold be built off each other - not that I think about it, it wouldn't make any sense. It's likely they are both built off some kernel-level structure whereby threads can register to be interested in some event, and informed when it happens. Difference would be `kqueue()` packages a bunch of these together, while `aio` would take exclusive ownership of a descriptor and kick off a r/w request first. Yes? –  Feb 06 '16 at 15:54
  • Surely kqueue supports asynchronous IO through the EVFILT_AIO filter. You set up a queue, then when you make an asynchronous IO request, you pass the descriptor of the queue in the request, and when it completes, an event is sent to the queue. That seems like exactly what the OP wants. Am i missing something? – Tom Anderson Jun 07 '17 at 10:28
  • 1
    @TomAnderson, on macOS at least, the `kqueue` man page says this for `EVFILT_AIO`: "This filter is currently unsupported." – Ken Thomases Jun 07 '17 at 15:17
  • 1
    Argh! I spent some time reading the FreeBSD documentation, but didn't even think to check the OS X docs. I suppose xnu must have a completely different implementation of everything to do with events and threading internally, what with all the Mach stuff. – Tom Anderson Jun 08 '17 at 16:35
  • @KenThomases Well I've been looking into why `NonBlockingFileIO` of Swift-nio uses a thread pool and blocking reads -- now I know! Thank you. I've asked around and couldn't figure it out (the library is about asyncIO and using kernel events for efficient reading). Anyway I'm using a pipe in the code i'm working on so I guess i'll still end up implementing one of these async methods afterall – Antwan van Houdt Oct 13 '21 at 02:55
0

I used kqueues to adapt a Linux proxy server (based on epoll) to BSD. I set up separate GCD async queues, each using a kqueue to listen on a set of sockets. GCD manages the threads for you.

Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • Thanks for the reply. When I mention managing a thread pool myself, I don't do so because it's too difficult - just that it's potentially unnecessary if a true interrupt-base mechanism & API existed. I don't see the point in using an API just feigns non-blocking by issuing a blocking call on a separate thread - no real reason to not just write that yourself. –  Feb 06 '16 at 02:36
  • kqueue/kevent is a blocking mechanism. That's why it has a wait parameter. I assume it's intended to be used from a background thread/threads. It doesn't "feign non-blocking" at all. – Duncan C Feb 08 '16 at 14:00