Signals and threads do not play nice in general.
Synchronous signals (SIGSEGFAULT, SIGPIPE, SIGFPE) are always delivered and
signal handler is invoked in the thread that caused them.
Asynchronous ones (all the rest - SIGINT, SIGHUP, SIGCONT, SIGALRM, etc) are
quite different and there are two approaches to handle them .
1. If signal handler is present - it can be invoked in any thread
that has not blocked the delivered signal. This means that only single thread
can deterministically register signal handler (unblock the signal and block it
in all the other threads).
2. Use a dedicated thread to wait & handle all signals (via sigwait()) and block
all signals in other threads. Big advantage here is that after sigwait()
returns you are allowed to use any function not just the async-signal safe ones
as in the case with signal handler (for a list see:
http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html ).

CLISP uses the sigwait() approach. So even though you register a signal handler
the delivery of this signal is blocked in all threads and sigwait() comes to
action.

CLISP handles internally following asynchronous signals:
SIGCLD: to prevent zombies when forking
SIGINT: to act on CTRL-C
SIGALRM & SIGUSR2: to implement CALL-WITH-TIMEOUT
SIGUSR1: to implement THREAD-INTERRUPT
SIGWINCH: to update terminal line length
And all terminating signals (SIGQUIT, SIGABRT, SIGTERM, SIGKILL)
I am not sure it is good idea to allow installation of signals handlers for
the above.

As general solution we may maintain a central registry of signal handlers
and threads in which they have been registered (NIL for "does not care" thread)
and invoke these handlers from dedicated sigwait-ing thread via
THREAD-INTERRUPT (the same way as CALL-WITH-TIMEOUT works now).
If we go in this way there are two questions:
1. should we allow multiple threads to register handler for the same signal?
2. should we allow single thread to register several handlers for the same
signal?

And all the above is POSIX specific of course.