Tim P. [email protected] wrote:
On Nov 22, 2009, at 7:31 PM, Eric W. wrote:
Tim P. [email protected] wrote:
I’d just write a byte to a pipe (useful with signal handlers, too, see:
http://cr.yp.to/docs/selfpipe.html)
Based on the self-pipe page, here is the solution I came up with.
Please, anyone, give comments and suggestions.
http://gist.github.com/241224
Hi Tim,
I think a length argument is is required for read_nonblock. And
you should probably only be reading from the receiver after the
select.
Also, the creation/check of Thread#[:select_signal_pipe] is
potentially racy. I would probably create it in the parent
like this:
pipe = IO.pipe
thr = Thread.new(pipe) do |pipe|
Thread.current[:select_signal_pipe] = pipe
pipe.last.syswrite(’.’) # wakeup parent once we know the parent can
use it
# …
end
pipe.first.readpartial 1 # blocks until it reads ‘.’
after the readpartial, we know the following is set:
assert(thr[:select_signal_pipe] == pipe)
…
Unlike the self-pipe example, the basic rule of thumb to avoid driving
oneself nuts is that one set of threads/processes only does reads, and
another set only does writes. Reading and writing to one pipe from the
same thread/process anywhere outside of signal handlers gets really
confusing, really quickly :> And even with the self-pipe signal
handlers, all communication is one-way within any given control block.
I’d also be very defensive about spurious select() wakeups (and
Errno::EINTR, too, just in case). Pretty much any syscall that sleeps
like select() including (but not limited to) pthread_cond_wait, poll,
epoll_wait are all potentially susceptible to spurious wakeups, so you
could be exiting a thread when you don’t intend to.