Issue with Signal Handling, Interrupt Handling

Issue with signal handling, interrupt handling

Signal is executed in user mode, but with a different user context, then return to kernel, which return to user_mode with ret_from_syscall.
The behaviour of system call when signal handler are installed with SA_RESTART depends on the system call.

A description of which system call are restarted is available in recent version of the signal overview manpage :

man 7 signal

If the SA_RESTART flag is not used, system call is not restarted.

Signal handling in C - interrupt in interrupt

Quoting the sigaction(2) manpage:

Signal routines normally execute with the signal that caused their
invocation blocked, but other signals may yet occur. A global signal mask
defines the set of signals currently blocked from delivery to a process.
The signal mask for a process is initialized from that of its parent
(normally empty). It may be changed with a sigprocmask(2) call, or when
a signal is delivered to the process.

You can control whether the signal is automatically blocked in its signal handler with the SA_NODEFER flag.

Proper signal handling and interrupts

Actually, if a signal occurs, your current operation isn't necessarily going to finish before the signal handler is called. However, upon completion of the signal handler, your code resumes from exactly where it was when the signal interrupted. And since all your signal handler does is set a flag variable, there's no effect on the code that currently in middle of whatever else it's doing.

Answers:

  1. Why bother? Your code does resume after, and any properly designed signal handler isn't going to destabilize the code.
  2. Documentation seems to indicate that the handling of the second signal will be deferred until the first handler completes. See this question for details.

signal handler and multithreading

INTRODUCTION

First of all each thread has its own mask that specifies which signals it is listening to. When a thread is created it inherits the mask of the thread that is creating it (let me call it the parent thread) that is active when pthread_create is called.

Generally it is better that if a thread is listening to a signal then the others should not, unless you want to have many threads that do the same stuff (for example when processing a connection request in a server to process many requests simultaneously). In this way you always know which thread is processing the signal. Otherwise you do not have any idea which thread is receiving the signal and which part of the program is executing: it becomes impossible to debug (an example is your own question).

To change the mask of the child thread that is being created from the parent thread you create a new mask, you set it active, create a new thread with pthread_create and then in the parent thread set the previous mask active again (see the code at the end of the answer).

EDIT: According to this post it is better to use sigaction() instead of signal. In modern systems signal() is implemented with sigaction() so there should not be any difference. However if its old implementation is used, problems might arise.

ANSWER

So signal only interrupt thread instead of the whole process if there
are multi-threading?

NO: Signals are just signals, they do not do anything. Actions associated to signals have the power to do stuff, including stopping the program or terminating the thread. Each signal has a default action associated and the default action for SIGINT is to interrupt the process.

With you handler you are overwriting the default action. So it will not stop the program anymore but it will do what you have specified in the thread function.

In the first case you have only one thread, the main one, which is an infinite loop, it always catches the signal as long as he is alive so that's why the behavior. If you resend the signal, the signal is momentarily blocked until the signal handler ends the execution. Nevertheless if many signals are sent while the handler is executing, you can loose some signals.
In fact as explained here, blocked signals are set to pending, but not queued. The term pending means that the operating system remembers that there is a signal waiting to be delivered at the next opportunity by setting a flag, and not queued means that it does this by setting a flag somewhere, but not by keeping an exact record of how many signals have arrived.
So if the signals is sent once, 5 times or more (try to press CTRL+C more times with your program: I have tried) while the signal handler is executing it produces the exactly same behaviour.

In your second case you have 3 threads: the main one, t1, and t2: all of them are enabled to see the signal SIGINT and all of them have associated the same signal handler. If you press 3 times one after the other all three of them will execute the handler: that is why you don't see any delay. If you press very very fast though and more than 3 times (the number of threads listening to that signal) I think you will see something similar to the first behaviour.

I will end my answer with the code I posted in a question where I was setting masks so that some signals were caught only by the main thread:

int main()
{
int err;
sigset_t omask, mask;
pthread_t thread_motionSensor;
pthread_t thread_tempReading;
pthread_t thread_platformPost;

printf("Created threads IDs\n");

...
if (signal(SIGINT, sig_handler)==SIG_ERR)
printf("Error on recording SIGINT HANDLER\n");

/*Create a new mask to block all signals for the following thread*/
sigfillset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, &omask);
printf("Trying to create threads\n");
if ((err = pthread_create (&thread_motionSensor, NULL, task1, NULL))!=0)
{
printf("Thread 1 not created: error %d\n", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 1 created. Trying to create Thread 2\n");
if((err = pthread_create (&thread_tempReading, NULL, task2, NULL))!=0)
{
printf("Thread 2 not created: error %d\n", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 2 created. Trying to create Thread 3\n");
if ((err = pthread_create (&thread_platformPost, NULL, task3, NULL))!=0)
{
printf("Thread 3 not created: error %d %d\n", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 3 created\n");
/*The main thread must block the SIGALRM but catch SIGINT
SIGQUIT, SIGTERM, SIgkILL*/
/*empty the omask set from all signals */
sigemptyset(&omask);
/*add the signals to the omask*/
sigaddset(&omask, SIGINT);
sigaddset(&omask, SIGQUIT);
sigaddset(&omask, SIGKILL);
sigaddset(&omask, SIGTERM);
/*unblock all signals in omask*/
pthread_sigmask(SIG_UNBLOCK, &omask, NULL);
printf("Main thread waiting for signal\n");
/*pause will stop the main thread until any signal not blocked by omask will be received*/
pause();
printf("Exit signal received: cancelling threads\n");

pthread_cancel(thread_motionSensor);
pthread_cancel(thread_tempReading);
pthread_cancel(thread_platformPost);
pthread_join(thread_motionSensor, NULL);
pthread_join(thread_tempReading, NULL);
pthread_join(thread_platformPost, NULL);
printf("Exiting from main thread and process\n");
exit(0);
}


Related Topics



Leave a reply



Submit