- /* In clone_threads, if A and B both interrupt C at approximately
- * the same time, it does not matter: the second signal will be
- * masked until the handler has returned from the first one. In
- * pthreads though, we can't put the knowledge of what function to
- * call into the siginfo, so we have to store it in the
- * destination thread, and do it in such a way that A won't
- * clobber B's interrupt. Hence, this stupid linked list.
- *
- * This does depend on SIG_INTERRUPT_THREAD being queued (as POSIX
- * RT signals are): we need to keep interrupt_fun data for exactly
- * as many signals as are going to be received by the destination
- * thread.
- */
- lispobj c=alloc_cons(function,NIL);
- sigset_t newset,oldset;
- sigemptyset(&newset);
- /* interrupt_thread_handler locks this spinlock with blockables
- * blocked (it does so for the sake of
- * arrange_return_to_lisp_function), so we must also block them or
- * else SIG_STOP_FOR_GC and all_threads_lock will find a way to
- * deadlock. */
- sigaddset_blockable(&newset);
- thread_sigmask(SIG_BLOCK, &newset, &oldset);
- if (th == arch_os_get_current_thread())
- lose("cannot interrupt current thread");
- get_spinlock(&th->interrupt_fun_lock,
- (long)arch_os_get_current_thread());
- ((struct cons *)native_pointer(c))->cdr=th->interrupt_fun;
- th->interrupt_fun=c;
- release_spinlock(&th->interrupt_fun_lock);
- thread_sigmask(SIG_SETMASK,&oldset,0);
- /* Called from lisp with the thread object as a parameter. Thus,
- * the object cannot be garbage collected and consequently reaped
- * and joined. Because it's not joined, kill should work (even if
- * the thread has died/exited). */
- {
- int status=kill_thread_safely(th->os_thread,SIG_INTERRUPT_THREAD);
- if (status==0) {
- return 0;
- } else if (status==ESRCH) {
- /* This thread has exited. */
- th->interrupt_fun=NIL;
- errno=ESRCH;
- return -1;
- } else {
- lose("cannot send SIG_INTERRUPT_THREAD to thread=%lu: %d, %s",
- th->os_thread,status,strerror(status));
- }