Consider this example I set up to illustrate this.
#define _POSIX_C_SOURCE 199506L
#include <unistd.h>
#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
void hand(int sig);
void *thrfn(void *arg);
int main(void)
{
struct sigaction act;
struct itimerval timer;
sigset_t mask;
pthread_t thr;
act.sa_handler = hand;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, NULL);
/* error checking omitted */
timer.it_interval.tv_sec = 1;
timer.it_interval.tv_usec = 500000;
timer.it_value = timer.it_interval;
/* ultimately I want to build a loop; hence repeating */
setitimer(ITIMER_REAL, &timer, NULL);
sigemptyset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, NULL);
/* why doesn't this prevent SIGALRM from interrupting main? */
pthread_create(&thr, NULL, thrfn, NULL);
puts("Main thread done.");
getchar();
return 0;
}
void hand(int sig)
{
(void)sig;
write(STDOUT_FILENO, "Handler handled.\n", 17);
}
void *thrfn(void *arg)
{
sigset_t mask;
(void)arg;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
pthread_sigmask(SIG_SETMASK, &mask, NULL);
/* why doesn't this make pause() return in this thread? */
pause();
puts("Off thread's pause returned.");
pthread_exit(NULL);
}
Here's the output of this, compiled with gcc:
Main thread done.
Handler handled.
With about one and a half seconds between the messages.
How come my second thread's pause
never returns?
I guess the error is in the usage of pthread_sigmask
. Using SIG_BLOCK
and SIG_UNBLOCK
instead of SIG_SETMASK
the program behave you were expecting.
#define _POSIX_C_SOURCE 199506L
#include <unistd.h>
#include <stdio.h>
#include <sys/time.h>
#include <errno.h>
#include <signal.h>
#include <pthread.h>
void hand(int sig);
void *thrfn(void *arg);
int main(void)
{
struct sigaction act;
struct itimerval timer;
sigset_t mask;
pthread_t thr;
act.sa_handler = hand;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, NULL);
/* error checking omitted */
timer.it_interval.tv_sec = 1;
timer.it_interval.tv_usec = 500000;
timer.it_value = timer.it_interval;
/* ultimately I want to build a loop; hence repeating */
setitimer(ITIMER_REAL, &timer, NULL);
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
pthread_sigmask(SIG_BLOCK, &mask, NULL);
/* This prevent SIGALARM interrupring the main */
pthread_create(&thr, NULL, thrfn, NULL);
puts("Main thread done.");
getchar();
return 0;
}
void hand(int sig)
{
(void)sig;
write(STDOUT_FILENO, "Handler handled.\n", 17);
}
void *thrfn(void *arg)
{
sigset_t mask;
(void)arg;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
/* This make the pause() return on SIGALARM */
pause();
puts("Off thread's pause returned.");
pthread_exit(NULL);
}
This program gives the following output:
$ ./test
Main thread done.
Handler handled.
Off thread's pause returned.
It's likely you'll find your answers here and here.
In particular with:
sigemptyset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, NULL);
you are unbloking all signals in the main thread. While, with:
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
pthread_sigmask(SIG_SETMASK, &mask, NULL);
you are blocking only SIGALARM
on the child thread. That is probably the contrary of what you would like to do.
Keep in mind that using SIG_SETMASK
you specify the set of blocked signals.