Search code examples
csignalssetitimer

c setitimer not sending signal when outside its call scope


i have the following case

void foo() {
   printf("hi\n");  
   while(1);

}


int main(void)
{
  struct sigaction temp;
  temp.sa_handler = &foo;
  sigfillset(&temp.sa_mask);
  sigdelset(&temp.sa_mask, SIGVTALRM);
  sigdelset(&temp.sa_mask, SIGINT );
  sigaction(SIGVTALRM, &temp, NULL);
  struct itimerval tv;
  tv.it_value.tv_sec = 2;  /* first time interval, seconds part */
  tv.it_value.tv_usec = 0; /* first time interval, microseconds part */
  tv.it_interval.tv_sec = 2;  /* following time intervals, seconds part */
  tv.it_interval.tv_usec = 0; /* following time intervals, microseconds part */

  if (setitimer(ITIMER_VIRTUAL, &tv, NULL)){
    perror(NULL);
  }
  while(1);
  return 0;
}

all I want is that every 2 seconds foo will be called (foo actually does some other stuff other than while(1), just assume foo run takes more than 2 seconds), after 2 seconds foo is indeed called but then no other call is made untill foo returns. I tried playing with the signal masks (hence the sigfillset) but also when simply calling signal(SIGVTALRM, foo) no changes are made in the result. I also tried having the itimerval and the sigactions variables declared outside main and it didn't quite affect anything.

is the thing I'm trying to do even possible?

thanks!


Solution

  • reference: <http://www.gnu.org/software/libc/manual/html_node/Signals-in-Handler.html>
    
     24.4.4 Signals Arriving While a Handler Runs
    

    What happens if another signal arrives while your signal handler function is running?

    When the handler for a particular signal is invoked, that signal is automatically blocked until the handler returns. That means that if two signals of the same kind arrive close together, the second one will be held until the first has been handled. (The handler can explicitly unblock the signal using sigprocmask, if you want to allow more signals of this type to arrive; see Process Signal Mask.)

    However, your handler can still be interrupted by delivery of another kind of signal. To avoid this, you can use the sa_mask member of the action structure passed to sigaction to explicitly specify which signals should be blocked while the signal handler runs. These signals are in addition to the signal for which the handler was invoked, and any other signals that are normally blocked by the process. See Blocking for Handler.

    When the handler returns, the set of blocked signals is restored to the value it had before the handler ran. So using sigprocmask inside the handler only affects what signals can arrive during the execution of the handler itself, not what signals can arrive once the handler returns.

    Portability Note: Always use sigaction to establish a handler for a signal that you expect to receive asynchronously, if you want your program to work properly on System V Unix. On this system, the handling of a signal whose handler was established with signal automatically sets the signal’s action back to SIG_DFL, and the handler must re-establish itself each time it runs. This practice, while inconvenient, does work when signals cannot arrive in succession. However, if another signal can arrive right away, it may arrive before the handler can re-establish itself. Then the second signal would receive the default handling, which could terminate the process.

    reference:<http://www.gnu.org/software/libc/manual/html_node/Process-Signal-Mask.html#Process-Signal-Mask>
    

    24.7.3 Process Signal Mask

    The collection of signals that are currently blocked is called the signal mask. Each process has its own signal mask. When you create a new process (see Creating a Process), it inherits its parent’s mask. You can block or unblock signals with total flexibility by modifying the signal mask.

    The prototype for the sigprocmask function is in signal.h.

    Note that you must not use sigprocmask in multi-threaded processes, because each thread has its own signal mask and there is no single process signal mask. According to POSIX, the behavior of sigprocmask in a multi-threaded process is “unspecified”. Instead, use pthread_sigmask.

    Function: int sigprocmask (int how, const sigset_t *restrict set, sigset_t *restrict oldset)

    Preliminary: | MT-Unsafe race:sigprocmask/bsd(SIG_UNBLOCK) | AS-Unsafe lock/hurd | AC-Unsafe lock/hurd | See POSIX Safety Concepts.

    The sigprocmask function is used to examine or change the calling process’s signal mask. The how argument determines how the signal mask is changed, and must be one of the following values:

    SIG_BLOCK
    

    Block the signals in set—add them to the existing mask. In other words, the new mask is the union of the existing mask and set.

    SIG_UNBLOCK
    

    Unblock the signals in set—remove them from the existing mask.

    SIG_SETMASK
    

    Use set for the mask; ignore the previous value of the mask.

    The last argument, oldset, is used to return information about the old process signal mask. If you just want to change the mask without looking at it, pass a null pointer as the oldset argument. Similarly, if you want to know what’s in the mask without changing it, pass a null pointer for set (in this case the how argument is not significant). The oldset argument is often used to remember the previous signal mask in order to restore it later. (Since the signal mask is inherited over fork and exec calls, you can’t predict what its contents are when your program starts running.)

    If invoking sigprocmask causes any pending signals to be unblocked, at least one of those signals is delivered to the process before sigprocmask returns. The order in which pending signals are delivered is not specified, but you can control the order explicitly by making multiple sigprocmask calls to unblock various signals one at a time.

    The sigprocmask function returns 0 if successful, and -1 to indicate an error. The following errno error conditions are defined for this function:

    EINVAL

    The how argument is invalid.

    You can’t block the SIGKILL and SIGSTOP signals, but if the signal set includes these, sigprocmask just ignores them instead of returning an error status.

    Remember, too, that blocking program error signals such as SIGFPE leads to undesirable results for signals generated by an actual program error (as opposed to signals sent with raise or kill). This is because your program may be too broken to be able to continue executing to a point where the signal is unblocked again. See Program Error Signals.