+ /* 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));
+ }
+ }