Non-blocking signal verification in a loop

I have a thread in an application that has a loop like this:

... while (1) { checkDatabase(); checkChildren(); sleep(3); } ... 

checkDatabase() is self-explanatory; checkChildren() simply calls waitpid(-1, &status, WNOHANG) to process child processes that either waitpid(-1, &status, WNOHANG) or receive a signal.

The application works quite well, but has a default signal processing. The problem is that this parent process has multiple threads (don't worry about child processes at the moment), and I have no experience with synchronous signals, not to mention the POSIX thread application. I used signal() before, but apparently it is not portable, and in any case, it does not do what I need. I have no experience whatsoever with sigaction methods, and I cannot find good documentation on how to fill structures, etc.

I need to make it so that it synchronously captures trailing signals such as SIGINT , SIGTERM and SIGQUIT in the above loop (and I need to completely ignore SIGPIPE so that I can catch the EPIPE error from the IO methods), so it will look like this:

 ... while (1) { checkDatabase(); checkChildren(); checkForSignals(); sleep(3); } ... 

All other threads should have nothing to do with the signal; only the thread that runs this loop needs to know about it. And, obviously, this should be a non-blocking check, so the loop is not blocked during the first iteration. The method, called if a signal is detected, will sort the other threads and destroy the mutexes, and all that.

Can someone please give me heads-up? Thank you very much.

+4
source share
4 answers

(After commenting the question and for completeness, this solution tries to avoid signal handlers.)

You can block signals from rising through sigprocmask () (or, rather, pthread_sigmask () , since you are using threads). From there, signals that were raised but blocked are accessible via sigpending () .

Thus, you can do something like (for brevity, errors are not indicated):

 sigset_t blocked; sigemptyset(&blocked); sigaddset(&blocked, SIGINT); sigaddset(&blocked, SIGTERM); sigaddset(&blocked, SIGQUIT); pthread_sigmask(SIG_BLOCK, &blocked, NULL); // Block SIGINT, SIGTERM and SIGQUIT. signal(SIGPIPE, SIG_IGN); // Ignore SIGPIPE. 

Then, later:

 void checkForSignals(void) { sigset_t pending; sigpending(&pending); if (sigismember(&pending, SIGINT)) { // Handle SIGINT... } if (sigismember(&pending, SIGTERM)) { // Handle SIGTERM... } if (sigismember(&pending, SIGQUIT)) { // Handle SIGQUIT... } } 

Since sigpending() not blocking, this seems to fit your requirements.

+3
source

Create a signal handler for SIGINT , SIGTERM and SIGQUIT using the same function. In this signal function, simply set a flag that can be polled in your loop.

Something like that:

 /* Global variable, will be set to non-zero if SIGINT, SIGTERM or SIGQUIT is caught */ int term_signal_set = 0; void my_signal_handler(int) { term_signal_set = 1; } /* ... */ signal(SIGINT, my_signal_handler); signal(SIGTERM, my_signal_handler); signal(SIGQUIT, my_signal_handler); signal(SIGPIPE, SIG_IGN); /* So functions return EPIPE */ while (1) { /* ... */ if (term_signal_set > 0) break; /* Or do something else */ sleep(3); } 
+2
source

In a multi-threaded application receiving a signal, there is no predetermination that the stream receives the signal. Typical workraounds include setting a global variable in a signal handler and checking it from a dedicated thread.

So, in your case, the signal handler (called from any thread) would simply set something like a global variable for the received signal, and in CheckForSignals() you would check it.

+1
source

sigaction is the way to go. man sigaction should help you. Here is an example from the Internet

 #include <stdio.h> #include <signal.h> #include <string.h> #include <unistd.h> struct sigaction act; void sighandler(int signum, siginfo_t *info, void *ptr) { printf("Received signal %d\n", signum); printf("Signal originates from process %lu\n", (unsigned long)info->si_pid); } int main() { printf("I am %lu\n", (unsigned long)getpid()); memset(&act, 0, sizeof(act)); act.sa_sigaction = sighandler; act.sa_flags = SA_SIGINFO; sigaction(SIGTERM, &act, NULL); // Waiting for CTRL+C... sleep(100); return 0; } 
0
source

Source: https://habr.com/ru/post/1390056/


All Articles