Refactor to use dispatch_io for tasks, and wait for EOF

Hopefully resolves #139, #135, #161.

/cc @joshaber @keithduncan
This won't happen when the input signal is disposed—only when the returned signal is (which happens in the dispatch_io cleanup block). The input signal is handled in the `completed` block above.