* As observed in alexcrichton/tokio-signal#38, Signal instances can starve based on the order
they are created in, and this ordering appears to be platform/OS
specific
* The crux of the issue is that we woud only *attempt* to broadcast any
pending signals if we successfully read out at least one byte from the
global pipe.
* For reasons unclear to me, the affected Signal instance would get
woken up after the signal handler writes to the global pipe, but it
would immediately hit a WouldBlock error and give up, bypassing the
broadcast attempt (even though the pending flag was correctly set).
- Maybe this has to do with OS specifics with how the bytes are
delivered (or not), or with some complex interaction with tokio and
the pipe registration. It seems fishy since strace logs didn't show
the signal handler pipe write fail either, but I'm all out of ideas
* The fix appears simple: unconditionally attempt to broadcast any
pending signals *any* time a Driver instance is woken up.
* Since we perform an atomic check for each pending signal, we know that
each (coalesced) signal broadcast will happen at most once. If we were
supuriously woken up and no signals were pending, then nothing will be
yielded to any pollers of Signal
* The down side is that since each Signal instance polls a Driver
instance, each poll to Signal will essentially perform N atomic
operations (N = number of signals we support) in an attempt to broadcast
any pending signals.
- However, we can revisit optimizing this better in the future
Fixesalexcrichton/tokio-signal#38
* We introduce a new global structure which keeps track of how many
signal streams have been registered with a given event loop (the event
loop is identified by its OS file descriptor)
* We only attempt to deregister our global evented pipe from any event
loop if and only if we are the last signal that was registered with it
Replace the sequential counting (which might be exhausted) by an address
of an object (in a box, so it doesn't change). This is also a unique, so
it is acceptable ID.
Add the driver task, connecting the signal handler wakeups to the
wakeups of of the streams.
It is a prototype-quality code, a lot of cleanups and similar is needed.
Which is just a wrapper around the futures::sync::mpsc. The sender is in
a global registry.
The part that connects the wakeups to the senders in the registry
doesn't yet exist.
Register the signal handler that wakes up someone through a self-pipe.
That someone doesn't yet exist, though.
Some dependencies (nix, lazy_static) added to speed up the prototyping
process. They are likely to be dropped in some future commits.
Some features (eg. preserving the previous signal handlers) are still
missing.