I written the below code to handle signals in separate thread to forcefully cleanup some resources and exit the complete process.
Here is the brief note about the below code.
Signals can be received by any thread in a process. So i am setting the global variable.
I have 2 questions.
1) This implementation is fine? or i have to block the signals for the main thread and handle only by the spawned thread ?
2) How to block a signal to the main process and handle it in a thread?
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <stdatomic.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
/*
* Set this variable if any signal is received
*/
volatile sig_atomic_t sig_set_flag = 0;
pthread_mutex_t cleanup_mutex;
/*
* Resource cleanup function.
*/
int cleaup_resources() {
pthread_mutex_lock(&cleanup_mutex);
/*
* Send notification to all the clients.
* Delete all the temp files
*/
printf("Notified to clients.Exiting process\n");
pthread_mutex_unlock(&cleanup_mutex);
return 0;
}
/*
* Signal handler thread
*/
void sig_term_handler(int sig_num) {
sig_set_flag = sig_num;
}
/*
* Signal handler thread routine
*/
void *signal_handler_thread(void * args) {
while(1) {
if(sig_set_flag != 0) {
printf("%s : Signal flag is set for sig_no %d\n",__func__,sig_set_flag);
cleaup_resources();
break;
}
usleep(5);
}
exit(0);
}
int main()
{
int loop_count,status;
pthread_t tid;
pid_t pid;
struct sigaction sig;
sig.sa_handler = &sig_term_handler;
sig.sa_flags = 0;
sigaction(SIGTERM, &sig, NULL);
/*
* Spawn a thread to monitor signals.
* If signal received, Exit the process.
*/
pthread_create(&tid, NULL, signal_handler_thread, NULL);
while(1) {
printf("Some time consuming task in progress... PID = %d\n",getpid());
pid = fork();
if(pid == 0) {
sleep(100);
return 0;
} else {
waitpid(pid, &status, 0);
loop_count++;
if( loop_count>=10)
break;
}
}
cleaup_resources();
exit(0);
}
Note:I know signals will interrupt the some system calls and EINTR will be set. Unfortunately some system calls (ie) waitpid() will not be interrupted. So i spawned a thread to handle this scenario.
1) Your implementation seems to be correct. signal()
and sigaction()
register a handler function for the whole process, so it doesn't matter you call them in the main thread or in the spawned thread.
2) To block a signal in the main thread, and handle it in a thread, you have to design, not a handler function, but a handler thread, using sigwait()
or sigwaitinfo()
. So the thread will wait for the signals and the program execution won't be interrupted.
In this case, you have to block process-wide signals in all the threads, including the main thread. If it is not blocked, the signal will have the default behavior on the program.
You have to use pthread_sigmask()
to block one or more signals. An example of code to block SIGTERM:
sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGTERM);
pthread_sigmask(SIG_BLOCK,&set,NULL);
When a thread is created, it inherits of the blocked signals of the creator thread.
I modified your code to show you how to use sigwaitinfo()
and pthread_sigmask()
:
#include <stdio.h>
#include <signal.h>
#include <pthread.h>
#include <stdatomic.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>
pthread_mutex_t cleanup_mutex;
/*
* Resource cleanup function.
*/
int cleaup_resources() {
pthread_mutex_lock(&cleanup_mutex);
/*
* Send notification to all the clients.
* Delete all the temp files
*/
printf("Notified to clients.Exiting process\n");
pthread_mutex_unlock(&cleanup_mutex);
return 0;
}
/*
* Signal handler thread routine
*/
void *signal_handler_thread(void * args) {
sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGINT);
siginfo_t info;
while(1) {
sigwaitinfo(&set,&info);
if(info.si_signo == SIGINT){
printf("\nSIGINT received\n");
cleaup_resources();
exit(0);
}
}
}
int main()
{
int loop_count,status;
pthread_t tid;
pid_t pid;
sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGINT);
pthread_sigmask(SIG_BLOCK,&set,NULL);
// The new thread will inherit the blocked
// signals from the thread that create it:
pthread_create(&tid, NULL, signal_handler_thread, NULL);
while(1) {
printf("Some time consuming task in progress... PID = %d\n",getpid());
pid = fork();
if(pid == 0) {
sleep(100);
return 0;
} else {
waitpid(pid, &status, 0);
loop_count++;
if( loop_count>=10)
break;
}
}
cleaup_resources();
exit(0);
}
Also, be careful of the fork()
, from the tests I have done, the child process will inherit of the blocked signals.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.