linux-user: fails to deliver signals raised during pselect

Host environment

  • Operating system: NixOS
  • OS/kernel version: Linux nix-build 5.10.92 #1-NixOS SMP Sun Jan 16 08:14:24 UTC 2022 x86_64 GNU/Linux
  • Architecture: x86_64
  • QEMU flavor: linux-user
  • QEMU version: qemu-x86_64 version 6.2.50 (v6.2.0-1117-gaeb0ae95)

Description of problem

When run via qemu a program which blocks signals but unmasks them during pselect does not catch these signals when returning from pselect.

Used as reference on expected behavior: The new pselect() system call

Steps to reproduce

A minimal test case below mimics behavior as encountered in the test suite of p11-kit (link) (which attempts to catch SIGTERM in a similar way and results in lingering processes after running the test suite).

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <sys/select.h>

static void handler(int sig)
{
	puts("SIGNAL");
}

int main(int argc, char *argv[])
{
	struct sigaction sa;

	fd_set rfds;
	sigset_t emptyset, blockset;

	sigemptyset (&blockset);
	sigemptyset (&emptyset);
	sigaddset (&blockset, SIGUSR1);

	sa.sa_handler = handler;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	sigaction(SIGUSR1, &sa, NULL);

	sigprocmask (SIG_BLOCK, &blockset, NULL);

	FD_ZERO(&rfds);

	while(1) {
		pselect(0, &rfds, NULL, NULL, NULL, &emptyset);
	}

	return 0;
}

Running this without qemu should print SIGNAL when sent SIGUSR1:

$ ./a.out &
[1] 1683587
$ kill -USR1 %1
$ SIGNAL

When run with qemu-x86_64 however, it does not (also qemu's -strace confirms the signal isn't received whereas a strace of qemu shows it's in fact delivered).

The pselect call itself is interrupted, but the signal goes missing.