invoke_signal_func calls Pike code (via apply_svalue). To run Pike
code, you need to hold the interpreter lock. But that is not all.
You also need to have a Pike stack and a frame pointer, which are
thread local. These are kept in a structure called a
"Pike_interpreter_struct", which in turn is part of something called a
"thread_state". All threads created with thread_create() already has
such a state, stored in a lookup table indexed on the thread id.
However, a thread created by (say) C-code in an external library will
not have such a state created for it.
call_with_interpreter is simply a convenience function used to be able
to call Pike code from an unknown context:
* If the running thread already has an entry in the lookup table, then
it just takes the interpreter lock, if it wasn't already taken, and
calls the function. Then it unlocks the interpreter lock again if
it was unlocked before.
* If the running thread does _not_ have an entry in the lookup table,
then a new thread_state is created, and made the current interpreter
(after taking the lock). The thread_state is also stored in the
lookup table, in case the pike code calls the C library back, which
then again makes a call into Pike and we reenter
call_with_interpreter within the same context. After the Pike code
has been executed, the thread_state is removed from the table and
discarded.