I claim that this is a solved problem, without rseq.
1. Any given thread in an application waits for "events of interest", then performs computations based on those events (= keeps the CPU busy for a while), then goes back to waiting for more events.
2. There are generally two kinds of events: one kind that you can wait for, possibly indefinitely, with ppoll/pselect (those cover signals, file descriptors, and timing), and another kind you can wait for, possibly indefinitely, with pthread_cond_wait (or even pthread_cond_timedwait). pthread_cond_wait cannot be interrupted by signals (by design), and that's a good thing. The first kind is generally used for interacting with the environment through non-blocking syscalls (you can even notice SIGCHLD when a child process exits, and reap it with a WNOHANG waitpid()), while the second kind is used for distributing computation between cores.
3. The two kinds of waits are generally not employed together in any given thread, because while you're blocked on one kind, you cannot wait for the other kind (e.g., while you're blocked in ppoll(), you can't be blocked in pthread_cond_wait()). Put differently, you design your application in the first place such that threads wait like this.
4. The fact that pthread_mutex_lock in particular is not interruptible by signals (by design!) is no problem, because no thread should block on any mutex indefinitely (or more strongly: mutex contention should be low).
5. In a thread that waits for events via ppoll/pselect, use a signal to indicate a need to stop. If the CPU processing done in this kind of thread may take long, break it up into chunks, and check sigpending() every once in a while, during the CPU-intensive computation (or even unblock the signal for the thread every once in a while, to let the signal be delivered -- you can act on that too).
6. In a thread that waits for events via pthread_cond_wait, relax the logical condition "C" that is associated with the condvar to ((C) || stop), where "stop" is a new variable protected by the mutex that is associated with the condvar. If the CPU processing done in this kind of thread may take long, then break it up into chunks, and check "stop" (bracketed by acquiring and releasing the mutex) every once in a while.
7. For interrupting the ppoll/pselect type of thread, send it a signal with pthread_kill (EDIT: or send it a single byte via a pipe that the thread monitors just for this purpose; but then the periodic checking in that thread has to use a nonblocking read or a distinct ppoll, for that pipe). For interrupting the other type of thread, grab the mutex, set "stop", call pthread_cond_signal or pthread_cond_broadcast, then release the mutex.
8. (edited to add:) with both kinds, you can hierarchically reap the stopped threads with pthread_join.