Poke has loops. It also does IO (yeah, right :D). On one hand, this means that Poke programs that never finish are definitely possible (here is one: while (1) {}) and, on the other, a Poke program acting on an enormous amount of data may take a long time to finish, depending on what it does. Maybe hours, maybe even days?
So there are reasons for wanting to interrupt a running Poke program. Since this weekend, this is as easy as pressing Ctrl-C in the command line while a Poke program is running, or sending SIGQUIT to it:
(poke) while (1) { } Ctrl-C (poke)
How does this work? First, Luca got some simple infrastructure for this in Jitter, in the form of an array called JITTER_PENDING_NOTIFICATIONS that contains a counter for every possible signal. Every time poke runs some PVM code, it temporarily installs a handler for SIGQUIT that notes the signal in the pending notifications array.
How is the running program made aware of the presence of the signal? The Poke compiler generates sync instructions in strategic places, such as before the backward jump in loops:
(poke) fun foo = void: { while (1) {} } (poke) .vm dis f foo note "foo" $L1: prolog pushf $L3: push 0x1 bzi $L10 drop pushf popf 1 sync ba $L3 $L10: drop popf 1 push null return exitvm
When the sync instruction is executed, it checks JITTER_PENDING_NOTIFICATIONS, and raises a PVM_E_SIGNAL exception. The default signal handler handles this exception just exiting the program silently.
Happy poking!