2

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?

nebuch
  • 6,475
  • 4
  • 20
  • 39
  • 1
    You block signal `SIGALRM` in the thread, so who should interrupt `pause()` call for it ables to return? – Tsyvarev Feb 02 '16 at 07:20

1 Answers1

2

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.

tano
  • 836
  • 1
  • 10
  • 25