The OS which tries to "block" signals while their handlers are executing. I
think the `raise` inside the handler confuses your OS into thinking the handler
has not yet returned. So, changing your `handler` to this works on Unix to
unblock SIGINT, the Ctrl-C signal:
import posix
proc handler() {.noconv.} =
var nmask, omask: Sigset
discard sigemptyset(nmask)
discard sigemptyset(omask)
discard sigaddset(nmask, SIGINT)
if sigprocmask(SIG_UNBLOCK, nmask, omask) == -1:
raiseOSError(osLastError())
raise newException(EKeyboardInterrupt, "Keyboard Interrupt")
Run
You probably also should re-call `setControlCHook(handler)` in your `else`
clause after your echo. IIRC, the `signal` call Nim uses will (often but not
portably!) just revert back to the default action which for `SIGINT` is to die
(although, the way things sound like they are working for you, that reversion
may never happen).
If you need something more portable then you might do better to manage the
state from inside the signal handler rather than mixing signals & exceptions.
E.g.:
import times, os, strutils
let t = epochTime()
var caught = false
proc handler() {.noconv.} =
if caught:
echo "Caught a second time"
quit()
caught = true
echo "Program has run for ", formatFloat(epochTime() - t, precision = 0),
" seconds."
setControlCHook(handler)
for n in 1..<int64.high:
sleep 500
echo n
Run
You could just add some `if caught: setControlCHook(handler); clearInput()`
wherever you wanted to clear the input on that first Ctrl-C.
It might be possible to put the re-install of the signal handler in `handler`
itself rather than externally in both cases, though I also would bet this is
not portable/reliable/fully defined. POSIX tried to clean up all this `signal`
stuff with `sigaction` and friends (which that `sigprocmask` is a part of), but
Nim tries to only use ANSI C things and work both on Unix & Windows. So, the
best answer to your question probably depends upon whether you seek
cross-platform portability of Control-C handling or if Unix alone is good
enough.