0

I have been working on signal handling on Linux lately, and have read all the concepts related to signal handling. One question that's tinkering my head is that why the signal in the set of sigtimedwait() doesn't get delivered while the process is unblocked. My code is as follows :-

#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
void sighandler1(int sig)
{
        printf("SIGINT caught\n");
}
void sighandler2(int sig)
{
        printf("SIGTSTP caught\n");
}
void sighandler3(int sig)
{
        printf("SIGALRM caught\n");
}

int main()
{

  sigset_t s1,s2;

  struct sigaction act1,act2,act3;

  int ret;

  sigemptyset(&s1);// The bit-mask s1 is cleared
  sigaddset(&s1,SIGINT);//Add SIGINT to the bit-mask s1

  sigemptyset(&s2);// The bit-mask s2 is cleared
  sigaddset(&s2,SIGALRM);//Add SIGALRM to the bit-mask s2

  sigprocmask(SIG_BLOCK,&s2,NULL);//Signal(s) in s2 blocked

  act1.sa_handler = sighandler1; //function pointer pointing to the signal handler
  act1.sa_flags = 0;        

  sigaction(SIGINT,&act1,NULL);  // installing the action
                                 // for SIGINT

  act2.sa_handler = sighandler2; //function pointer pointing to another signal handler
  act2.sa_flags = 0;         // no flags


  sigaction(SIGTSTP,&act2,NULL);  // installing the action
                                 // for SIGTSTP
  act3.sa_handler = sighandler3; //function pointer pointing to another signal handler
  act3.sa_flags = 0;         // no flags


  sigaction(SIGALRM,&act3,NULL);  // installing the action for SIGALRM

  sigprocmask(SIG_SETMASK,&s1,NULL); //Signals in s1 blocked and other signals unblocked
  printf("sigprocmask() called with SIG_SETMASK on s1,which contains SIGINT\n");
  printf("Blocked on sigtimedwait() with s1\n");
  if(sigtimedwait(&s1,NULL,NULL) < 0)
        {
                if(errno ==  EINTR)
                printf("Some other signal caught\n");
        }
  printf("This is a process. You can pass signal to it\n");

  while(1);

}

To be more clear with the question, I have called sigtimedwait in the above code with "s1" as the "set "parameter . This set contains only the signal SIGINT. As per the man page, sigtimedwait() blocks the process , until one of the signals in its set is delivered. I am all okay with that statement. But Why is the SIGINT handler not called when I pass SIGINT to unblock the process? On the other hand, when I pass SIGALRM or SIGTSTP, which are not there in the set, EINTR is returned as expected, and also the signal handler gets called.

For anyone, who wants to observe the scenario, can execute the above code and then pass SIGINT to it. They will observe that the process is unblocked without the handler being called . Why is the handler not called? Am I misinterpreting any part of the man page of sigtimedwait()??

Shubham_K
  • 78
  • 5

1 Answers1

0

sigtimedwait seems to return the signal value, instead of the signal handler getting caught:

switch(sigtimedwait(&s1,NULL,NULL))
{
    default:
        printf ("Some other signal???");
        break;
    case SIGINT:
        printf ("We got SIGINT\n");
        break;
    case -1:
        perror ("sigtimedwait");
        break;
}
Stian Skjelstad
  • 2,277
  • 1
  • 9
  • 19
  • Looking at the man-page, this is expected: sigwaitinfo() removes the signal from the set of pending signals and returns the signal number as its function result. If the info argument is not NULL, then the buffer that it points to is used to return a structure of type siginfo_t (see sigaction(2)) containing information about the signal. – Stian Skjelstad Apr 22 '16 at 09:03
  • Then, what about the following statement mentioned in the very first line of DESCRIPTION in the man-page - *sigwaitinfo() suspends execution of the calling thread until one of the signals in set is delivered.* It does say that the signal has to be delivered. However, I see that the signal in the set does not get delivered, but the signals *not in the set* do get delivered, with the handler getting called. – Shubham_K Apr 22 '16 at 14:23
  • You only block SIGINT in your sigprocmask() call, that is why the other signals can get through (causing sigtimedwait to return -1 and setting errno to EINTR). After the sigtimedwait, SIGINT is still blocked, and can not get received. With the wording delivered, they mean that it is no longer in the kernel-queue. sigtimedwait is the receiver of the signal in this case. – Stian Skjelstad Apr 22 '16 at 21:22
  • Ok, Let me not block SIGINT. So, Even though I comment the following line *sigprocmask(SIG_SETMASK,&s1,NULL);* , the signal SIGINT still doesn't get delivered when the process is unblocked. Though it gets delivered later when the process is no more blocked on *sigtimedwait()* . How's this happening then? – Shubham_K Apr 23 '16 at 10:03
  • What do you mean by the statement - *they mean that it is no longer in the kernel-queue. sigtimedwait is the receiver of the signal in this case.* Does it mean that sigtimedwait() is only responsible for catching the signal and not passing it through to the handler?? Something like that? – Shubham_K Apr 23 '16 at 10:09
  • Correct, sigtimedwait does not forward it to the handler – Stian Skjelstad Apr 23 '16 at 12:35