sigwait duplicou e transformou sinais no MacOS
Estou vendo sinalização inconsistente entre dois threads com o posix pthread / api de sinalização.
Aqui está meu programa de teste
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
void *thr_fn(void *arg)
{
int err, signo;
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask,SIGUSR1);
sigaddset(&mask,SIGUSR2);
sigaddset(&mask,SIGABRT);
printf("Thread Checker\n");
while(1) {
err = sigwait(&mask, &signo);
if (err != 0)
{
printf("sigwait failed %d\n",err);
exit(1);
}
switch(signo)
{
case SIGUSR1:
printf("SIGUSR1\n");
break;
case SIGUSR2:
printf("SIGUSR2\n");
break;
case SIGABRT:
printf("SIGABRT\n");
break;
default:
printf("Signal %d\n",signo);
break;
}
}
}
int main(void)
{
int err;
pthread_t tid;
sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask,SIGUSR1);
sigaddset(&mask,SIGUSR2);
sigaddset(&mask,SIGABRT);
pthread_sigmask(SIG_BLOCK,&mask,NULL);
err = pthread_create(&tid, NULL, thr_fn, 0);
if (err != 0)
{
printf("can't create thread %d",err);
exit(1);
}
sleep(1);
for(int x=0;x<5;x++)
{
printf("set %d\n",x);
usleep(100000);
// raise(SIGUSR1);
pthread_kill(tid, SIGUSR1);
pthread_kill(tid, SIGUSR2);
pthread_kill(tid, SIGABRT);
usleep(500000);
printf("\n");
}
printf("Done\n");
exit(0);
}
O que espero ver são 5 grupos de sinais identificados semelhantes aos abaixo:
set 1
SIGUSR1
SIGUSR2
SIGABRT
Espero ver 1 representante para cada sinal, mas suponho que não seja razoável esperar que os sinais estejam em ordem.
$ cc -pthread main.c $ ./a.out
Thread Checker
set 0
SIGUSR1
SIGABRT
SIGUSR2
set 1
SIGUSR2
SIGABRT
SIGUSR2
set 2
SIGUSR1
SIGABRT
SIGUSR2
set 3
SIGUSR1
SIGABRT
SIGUSR2
set 4
SIGUSR1
SIGABRT
SIGUSR2
Done
Program ended with exit code: 0
Note that set 1 has 2 SIGUSR2's in it. Each time I run the program I frequently a different number of signals. Using the commented out raise(SIGUSR1) in place of pthread_kill(tid,SIGUSR1) does not help.
So the questions is what is happening with SIGWAIT? Why is it possible to for signals to change type, or get duplicated in the signal queue. Why is this not consistent behavior? We see this work 100% in Linux but it also behaves badly in WSL.
Respostas
I added:
void dummy(int sig) {
dprintf(1, "Dummy %d\n", sig);
}
and:
signal(SIGUSR1, dummy);
signal(SIGUSR2, dummy);
signal(SIGABRT, dummy);
near the top of main; and it works as expected, and dummy is never invoked. In man sigwait:
The signals specified by set should be blocked, but not ignored, at the time of the call to sigwait().
update: if you change this to fork into thr_fn instead of pthread_create, it works without establishing the dummy params; which leads to a hypothoguess: macos diddles the SIG_DFL when a thread is created. This isn't inconsistent with the mess that pthreads+signals are. If you are planning to use both of these paradigms, you might want to hit pause....
My best guess is that you're running the program under debugger on macOS when you observe the odd behavior. Try running it directly from terminal without debugger.