[OT] poll() vs. AIO (was: [PATCH] ash: clear NONBLOCK flag from stdin when in foreground)

Cathey, Jim jcathey at ciena.com
Thu Aug 18 23:53:21 UTC 2011


>No. The paradigm in "wait until some event happens, then react on it".
>The most important feature of select/poll is that they
>*wait for something to happen*, and can wait for a set of events,
>not just one event.

That is true, so far as it goes, but it's the nature of 'something'
that is one of the near-insoluble problems of select/poll.  The
go-ahead is decoupled from what you want to do, and can be out of
sync.  (Which is what started this whole discussion.)  That lie
is the unforgivable sin of polling, and when it's coupled with the
fact that with poll/select you only have one timeout, which you have
to manipulate depending on what is going on _everywhere_ else in
the program, you start to wonder why you're using that kind of a poor
tool to begin with.  My pursuance of event-driven AIO is just sugar
on top of NOT using polling in general, and poll/select in specific.
I am biased, but I believe I have good reason to be.

The heart of the issue is whether or not you can write a program
that truly has only ONE blocking point within it, or not.  If you
can it is guaranteed to be responsive.  Few systems indeed can do
this, but many can be fobbed off using LWP's or the like.  If you
have them, which admittedly DNIX (like most every other Un*x in
that era) did not.  (In single-CPU systems, which most DNIX boxes
were, LWP's are just a way to reorganize the problem and offer no
inherent performance or maintainability advantage over an AIO
approach, and might actually be a performance liability.)

>AIO is slightly more efficient, but it's slightly more complex
>to code and understand too.

Yes, but once that step is taken the program becomes,
and generally remains, robust.

>This is nice in theory, but as soon as one of "..." parts
>requires blocking, you need to split it into two (or two dozen)
>subparts and include them separately into this gigantic switch.

Possibly.  Some sugar that the system I was referring to had
was completion handles that were part of the events, you just
indirect-called via them to subpackage handling.  The main
loop didn't need 100% of the application logic within it
at all.  So long as all blocking I/O was done via AIO the
app remained responsive.  That was easy to code-review for.

Another bit of sugar DNIX had, which NO other system I am
aware of has, was that completion queues were themselves
usable via AIO by virtue of the fact that completion queues
were just regular file descriptors, and AIO was orthogonal
on ALL fd's.  We did not use this facility, but it meant
that complex autonomous event-handling packages could be
hosted inside a complex event-handling program, WITHOUT
having to merge the code into a single event loop.  Ad
infinitum, though I'm sure performance would suffer rather
quickly.  We found it sufficient to share a single completion
queue, using a common event-handling convention.

>This becomes unwieldy very quickly. BTW, main loops based on
>select/poll are no different: they have absolutely the same problem.

They do; if the app is structured to do this only in one place it's
nearly the same thing structure-wise.  The presence of poll semantics
seems to encourage NOT doing this in only one place, in which case
the potential problems multiply with the quantity of poll/select calls.

>AIO or select loop, async programming is inherently more difficult.

Yes.  You wouldn't use it for a stdin/stdout pipeline type of tool
of course.  Interactive programs, multi-channel servers (same thing
really), yes it's worth the initial effort.

-- Jim






More information about the busybox mailing list