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 asigprocmask(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:
- Why bother? Your code does resume after, and any properly designed signal handler isn't going to destabilize the code.
- 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
Simpler Way to Repeatedly Read Lines and Invoke a Program
Error While Trying to Run Make Command
How to Get Exact List of Collections Form Mongo Database in Shell Script
Perl Script to Capture Stderr and Stdout of Command Executed in Back-Quotes
Creating Filename_$(Date %Y-%M-%D) from Systemd Bash Inline Script
Linux Shell Scripting: How to Remove Final Numbers in a Word List File
How to Generate Multiple Ssh Public Key and Configure Those on Windows Machine from Gitbash
How to Efficiently Get 10% of Random Lines Out of The Large File in Linux
How to Decide How Much Stack I Can Use After a Call to Pthread_Attr_Setstacksize
Required Alignment of .Text Versus .Data
Linux - Get Text from Second Tab
Why Would Vim Create a New File Every Time You Save a File
Copy Failed: Stat /Var/Lib/Docker/Tmp/Docker-Builder700869788/Private: No Such File or Directory