On Sun, May 12, 2019 at 6:38 AM John Cowan <xxxxxx@ccil.org> wrote:

Thread A executes a system call.
An async signal occurs that has a signal handler.
The kernel returns to user mode and executes the Posix-level signal handler in thread B
The Posix signal handler enqueues a Scheme signal handler for later execution (in thread C?)
When the signal handler exits, thread A is resumed with errno = EINTR.
The Scheme runtime re-executes the system call on behalf of thread A.
Asynchronously, thread C runs the Scheme signal handler, at which point any non-local exit is irrelevant to thread A.

In this scenario, system call executed by Thread A is not interrupted by an async signal so it won't return with EINTR.
If thread B is also executing a system call, then thread B will see an error return with errno = EINTR.

And you should queue or buffer the signals per-thread;  This is roughly what Gauche does:

   do {
      int r = syscall()
      if ((r < 0) && errno == EINTR) {
      } else {
   } while (1)

(In fact, it is a bit more involved because of EPIPE handling
https://github.com/shirok/Gauche/blob/b518a0b5a96b4d34a4abff0d835934a848edb90f/src/gauche/system.h#L48 )