Signal handler scheduling on single-threaded RTS
Edward Z. Yang
ezyang at MIT.EDU
Wed Nov 10 19:37:57 EST 2010
I've been poking the bad behavior Brian described here:
http://blog.ezyang.com/2010/08/interrupting-ghc/comment-page-1/#comment-1334
and in the process noticed something kind of interesting about
thread scheduling in non-multithreaded mode (i.e. without -threaded).
When the single-threaded RTS receives a signal, it writes it to
pending_handler_buf, and hopes that eventually startSignalHandlers creates
the threads to handle the signal. This doesn't happen instantaneously,
which is /really/ obvious if you're looping on an FFI call (like a program
might use readline). Here's an example (with some extra debug statements
from me):
installing Haskell signal handler
cap 0: thread 1 stopped (suspended while making a foreign call)
> ^Cstoring pending signal
cap 0: running thread 1 (ThreadRunGHC)
cap 0: thread 1 stopped (suspended while making a foreign call)
cap 0: running thread 1 (ThreadRunGHC)
Just ""
cap 0: thread 1 stopped (suspended while making a foreign call)
>
cap 0: running thread 1 (ThreadRunGHC)
cap 0: thread 1 stopped (yielding)
cap 0: thread 1 appended to run queue
starting signal handlers
scheduling a thread to handle signal (signo=2)
cap 0: created thread 2
cap 0: thread 2 appended to run queue
cap 0: running thread 1 (ThreadRunGHC)
cap 0: thread 1 stopped (suspended while making a foreign call)
cap 0: running thread 1 (ThreadRunGHC)
As you can see, the signal is stored immediately, but thread 1 gets
another crack at running the FFI call before it yields and we start
signal handlers.
Then, it turns out, thread 1 /never/ yields to anyone else, unless I
add this following patch:
hunk ./rts/posix/Signals.c 432
&base_GHCziConcziSignal_runHandlers_closure,
rts_mkPtr(cap, info)),
rts_mkInt(cap, info->si_signo))));
+ contextSwitchCapability(&MainCapability);
}
unblockUserSignals();
In which case the program finally realizes that there's a signal and handles
it about seven <ENTER> presses later.
I wonder if we should make it so that contextSwitchCapability(..) works more
instantly; possibly by checking for it before we start a safe FFI call and
yielding before we go into the FFI.
Cheers,
Edward
P.S. -threaded execution is broken in a different way: the ^C doesn't get handled
until the FFI call returns to Haskell. But that's another issue entirely, and one
in which readline is partially to blame. :-)
More information about the Glasgow-haskell-users
mailing list