Is it possible to ignore all signals? - c

I have a server application which I want to protect from being stopped by any signal which I can ignore. Is there a way to ignore all possible signals at once, without setting them one by one?

Yes:
#include <signal.h>
sigset_t mask;
sigfillset(&mask);
sigprocmask(SIG_SETMASK, &mask, NULL);
This does not exactly ignore the signals, but blocks them; which in practice is the same effect.
I guess there's no need to mention that SIGKILL and SIGSTOP cannot be blocked nor ignored in any way.
For more detailed semantics, like mask inheritance rules and the like, check the man page

Blocking signals is NOT the same as ignoring them.
When you block signals as suggested by C2H5OH, it gets added to a pending signal queue and will be delivered to the process as soon as you unblock it.
Unblocking can be done using
#include <signal.h>
sigset_t mask;
sigemptyset(&mask);
sigprocmask(SIG_SETMASK, &mask, NULL);
To answer your question on how to ignore signals, it has to be handled by a Signal Handler which is a user-defined function which executes whenever a signal is delivered to the process
static void foo (int bar)
{
/*some code here. In your case, nothing*/
}
then register this function by using
signal(SIGINT,foo); //or whatever signal you want to ignore
If you want to ignore all signals
int i;
for(i = 1; i <=31 ; i++)
{
signal(i,foo);
}
This code will take all the signals delivered to the process and ignore them instead of blocking them.
NOTE:
According to man pages , it is not the recommended way, instead sigaction is suggested. Do check out man sigaction

Solutions based on sigprocmask() and pthread_sigmask() have not worked for me.
Here's what I found to work:
#include <signal.h>
#include <unistd.h>
#include <assert.h>
int main() {
struct sigaction act;
act.sa_handler = SIG_IGN;
for(int i = 1 ; i < 65 ; i++) {
printf("i = %d\n", i);
// 9 and 19 cannot be caught or ignored
// 32 and 33 do not exist
if((i != SIGKILL) && (i != SIGSTOP) && (i != 32) && (i != 33)) {
assert(sigaction(i, &act, NULL) == 0);
}
}
sleep(10000);
return 0;
}

Related

Sigaction returning -1 on declaration in a child process

In pong, the code returns the error print. I know I don't understand enough about signals so I definitely don't know what's going wrong here.
From what I understand, Sigaction returns -1 when:
The signal is invalid or can't be caught or ignored
SA_SIGINFO bit flag is set without support from the implementation
Since SIGUSR1 is a user-defined signal, I don't see why it can't be caught or ignored. Also, I haven't touched SA_SIGINFO, so unless it defaulted to and invalid setting, I can't see why that'd be an issue.
My project outline says that I need to "Set up a signal handler to call the handler function" within the pong() function, not main. However, Main should send the signal before it ends. The signal function should only print "pong ending" and exit to break the infinite loop inside pong.
Edit 3: The main method isn't sending the signal to pong() and the code is left hanging.
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
int ping();
int pong();
void handle_SIGUSR1(int signum);
int fdA[2];
int fdB[2];
int ppid;
int ping ()
{
close(fdA[0]);
close(fdB[1]);
int i = 0, check = 0;
printf("ping - %d\n", i);
write(fdA[1], &i, sizeof(int));
while (i < 18)
{
read(fdB[0], &i, sizeof(int));
i++;
printf("ping - %d\n", i);
write(fdA[1], &i, sizeof(int));
}
close(fdA[1]);
close(fdB[0]);
exit(0);
return 0;
}
int pong()
{
ppid = getpid();
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_handler = handle_SIGUSR1;
sa.sa_flags = 0;
if (sigaction(SIGUSR1, &sa, NULL) == -1)
{
printf("error -> sigaction err\n");
}
int j = 0;
while (1)
{
read(fdA[0], &j, sizeof(int));
j++;
printf("pong - %d\n", j);
write(fdB[1], &j, sizeof(int));
}
}
void handle_SIGUSR1(int signum)
{
printf("Pong ending...\n");
exit(0);
}
int main ()
{
if (pipe(fdA) == -1 || pipe(fdB) == -1)
return 1; // pipe initialization error
int pid = fork();
if (pid == 0)
{
ping();
}
else
{
ppid = getpid();
pong();
}
kill(ppid, SIGUSR1);
}
Transferring the gist of my comments into an answer.
Study the POSIX specification of sigaction() carefully.
One part of your problem may be that you've not set the signal mask, sa.sa_mask, so it is random garbage, and presumably, the random garbage is not acceptable. Writing sigemptyset(&sa.sa_mask); before the call might fix the problem — it would fix the problem if my analysis is correct. Basically, you should make sure you've initialized the structure properly/thoroughly. Even if this is not the cause of the trouble, you should still always set the mask. It isn't a good idea to block a random set of signals; you should know what you're blocking, so either sigemptyset() or sigfillset() should be used to set the mask — or you can ensure the struct sigaction structure is zeroed when you create it.
(Similarly, you should ensure the that the sa_flags member is appropriately set too — part of the previous point about setting the structure properly. This was noted by Nate Eldridge in this answer. You should only set one of sa_handler and sa_sigaction, depending on whether you set SA_SIGINFO in the sa_flags.)
However, you have another more major problem. Take a good look at the if statement:
if (sigaction(SIGUSR1, &sa, NULL) == -1);
What's the semicolon doing? Don't put semicolons there; it means that the code block after it is executed unconditionally.
Note that errors should be written to stderr, and you could consider using perror(), or using errno and strerror() to report the error message (and possibly the error number). But the semicolon is the main problem. You should still make sure the structure passed to sigaction() is fully initialized.
Your sa.sa_flags is uninitialized so it very likely contains flags that make no sense, causing sigaction to fail. It doesn't "default" to anything except garbage. If you don't want the behavior of any of the flags, set sa.sa_flags to 0.

How to cancel waitpid if child has no status change?

Disclaimer: Absolute newbie in C, i was mostly using Java before.
In many C beginner tutorials, waitpid is used in process management examples to wait for its child processes to finish (or have a status change using options like WUNTRACED). However, i couldn't find any information about how to continue if no such status change occurs, either by direct user input or programmatic (e.g. timeout). So what is a good way to undo waitpid? Something like SIGCONT for stopped processes, but instead for processes delayed by waitpid.
Alternatively if the idea makes no sense, it would be interesting to know why.
How about if I suggest using alarm()? alarm() delivers SIGALRM after the countdown passes (See alarm() man page for more details). But from the signals man page, SIGALRM default disposition is to terminate the process. So, you need to register a signal handler for handling the SIGALRM. Code follows like this...
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
void sigalrm(int signo)
{
return; // Do nothing !
}
int main()
{
struct sigaction act, oldact;
act.sa_handler = sigalrm; // Set the signal handler
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
#ifdef SA_INTERRUPT // If interrupt defined set it to prevent the auto restart of sys-call
act.sa_flags |= SA_INTERRUPT;
#endif
sigaction(SIGALRM, &act, &oldact);
pid_t fk_return = fork();
if (fk_return == 0) { // Child never returns
for( ; ; );
}
unsigned int wait_sec = 5;
alarm(wait_sec); // Request for SIGALRM
time_t start = time(NULL);
waitpid(-1, NULL, 0);
int tmp_errno = errno; // save the errno state, it may be modified in between function calls.
time_t end = time(NULL);
alarm(0); // Clear a pending alarm
sigaction(SIGALRM, &oldact, NULL);
if (tmp_errno == EINTR) {
printf("Child Timeout, waited for %d sec\n", end - start);
kill(fk_return, SIGINT);
exit(1);
}
else if (tmp_errno != 0) // Some other fatal error
exit(1);
/* Proceed further */
return 0;
}
OUTPUT
Child Timeout, waited for 5 sec
Note: You don't need to worry about SIGCHLD because its default disposition is to ignore.
EDIT
For the completeness, it is guaranteed that SIGALRM is not delivered to the child. This is from the man page of alarm()
Alarms created by alarm() are preserved across execve(2) and are not inherited by children created via fork(2).
EDIT 2
I don't know why it didn't strike me at first. A simple approach would be to block SIGCHLD and call sigtimedwait() which supports timeout option. The code goes like this...
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
sigset_t sigmask;
sigemptyset(&sigmask);
sigaddset(&sigmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &sigmask, NULL);
pid_t fk_return = fork();
if (fk_return == 0) { // Child never returns
for( ; ; );
}
if (sigtimedwait(&sigmask, NULL, &((struct timespec){5, 0})) < 0) {
if (errno == EAGAIN) {
printf("Timeout\n");
kill(fk_return, SIGINT);
exit(1);
}
}
waitpid(fk_return, NULL, 0); // Child should have terminated by now.
/* Proceed further */
return 0;
}
OUTPUT
Timeout
The third argument to waitpid takes a set of flags. You want to include the WNOHANG flag, which tells waitpid to return immediately if no child process has exited.
After adding this option, you would sit in a loop a sleep for some period of time and try again if nothing has exited. Repeat until either a child has returned or until your timeout has passed.
Waiting for process to die on a typical Unix system is an absolute PITA. The portable way would be to use various signals to interrupt wait function: SIGALARM for timeout, SIGTERM/SIGINT and others for "user input" event. This relies on a global state and thus might be impossible to do.
The non-portable way would be to use pidfd_open with poll/epoll on Linux, kqueue with a EVFILT_PROC filter on BSDs.
Note that on Linux this allows waiting for a process to terminate, you will still have to retrieve status via waitid with P_PIDFD.
If you still want to mix in "user events", add signalfd to the list of descriptors on Linux or EVFILT_SIGNAL filter of kqueue on BSDs.
Another possible solution is to spawn a "process reaper" thread which is responsible for reaping of all processes and setting some event in a process object of your choice: futex word, eventfd etc. Waiting on such objects can be done with a timeout. This requires everyone to agree to use the same interface for process spawning which might or might not be reasonable. Afaik Java implementations use this strategy.

What are the pitfalls of using `pause()` in signal handler?

I want to suspend the thread and resume it. There are few methods listed here. But I thought of using pause() library function from unistd.h.
What are the pitfalls of using pausing in signal handler?
One I noticed is, when I send 0 to pause thread and send 0 again then my signal is queued. I need to send 1 twice to resume the thread.
I guess there may be many more cases like this. How to handle such conditions if I want to use pause() or sleep() in signal handler.
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <stdbool.h>
static bool thread_ready = false;
static void cb_sig(int signal)
{
if (signal == SIGUSR1)
pause();
else if (signal == SIGUSR2)
;
}
static void *thread_job(void *ignore)
{
int i = 0;
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = cb_sig;
if (sigaction(SIGUSR1, &act, NULL) == -1)
printf("unable to handle siguser1\n");
if (sigaction(SIGUSR2, &act, NULL) == -1)
printf("unable to handle siguser2\n");
thread_ready = true;
while (1) {
printf("thread counter: %d\n", i++);
sleep(1);
}
return NULL;
}
int main()
{
bool running;
int user_input;
pthread_t thread;
if (pthread_create(&thread, NULL, thread_job, NULL))
return -1;
while (!thread_ready);
for (running = true; running; ) {
printf("0: pause thread, 1: resume thread, -1: exit\n");
scanf("%d", &user_input);
switch(user_input) {
case -1:
running = false;
break;
case 0:
pthread_kill(thread, SIGUSR1);
break;
case 1:
pthread_kill(thread, SIGUSR2);
break;
}
}
pthread_kill(thread, SIGKILL);
return 0;
}
A signal handler should not sleep(), and probably should not pause(), even though technically, both of these functions are async-signal-safe. Signal handlers should run quickly and minimize or (preferrably) completely avoid blocking.
As for specific pitfalls, you already noted one: by default, a signal is automatically blocked while its handler is running. It is possible to install the handler in a way that avoids that, but here that wouldn't help you: if you kept sending signals that get handled by your particular handler, then you would always have at least one thread blocked in that handler. If you kept sending them to the same thread then that thread would never unblock.
More generally, there are any number of poor interactions that might happen between signal masks, signaling, and signal handlers blocking on signal receipt.
Moreover, pause() is rather non-specific unless you combine it with setting a rather restrictive signal mask (in which case sigsuspend() is probably a better choice). But if you set a restrictive signal mask then you potentially interfere with other uses of signaling.
Do not "handle" such issues other than by avoiding use of pause() and sleep() in your signal handlers.

How to restore original signal handling properties in C

Tried my best to figure this out on my own, but I really do not want to continue tampering with things that I do not fully understand. So for a programming assignment I have to do in C, I need to terminate a program upon the user entering CTRL+D key stroke via a terminal. I tried to isolate that functionality in a smaller test function, but now my CTRL+D behaves as my CTRL+C and CTRL+C does not have any effect, even outside of the program when it finishes executing. This is the program that caused this change:
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include <stdlib.h>
void ctrlD(int sig){
printf("\n");
signal(SIGINT, SIG_DFL);
exit(0);
}
int main(){
signal(SIGINT, ctrlD);
while(1) {
printf("Hello\n");
sleep(5);
}
}
The line signal(SIGINT, SIG_DFL); was added afterward upon realizing my CTRL+C no longer worked. I thought it would return the keystrokes to their original functionalities, but to no avail. What do I do to get back the original functionalities while also making this program work with CTRL+D?
***EDIT: This question seems to have gone off the rails a bit. I get now that Ctrl+D is not a signal. Nonetheless, I no longer have the functionality of Ctrl+C anymore when attempting to use it in my MAC OS terminal, and instead Ctrl+D seems to have that exact functionality. HOW exactly can I return each to have the functionality that they had before I went on this haphazard journey?
If your intention is to restore signal's default behavior after executing handler then, pass SA_RESETHAND flag to sa_flags while registering signal action. For example.
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_flags = SA_RESETHAND;
act.sa_handler = some_handler;
sigaction(SIGINT, &act, NULL);
From sigaction() man
SA_RESETHAND
Restore the signal action to the default upon entry to the signal handler. This flag is meaningful only when
establishing a signal handler.
If you write a program to explore signals, it is much better to write it carefully, using proper POSIX interfaces (sigaction() instead of signal()), and avoiding undefined behaviour (using non-async-signal safe functions in a signal handler).
Consider, for example, the following program:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
static volatile sig_atomic_t sigint_count = 0;
static void catch_sigint(int signum)
{
if (signum == SIGINT)
sigint_count++;
}
static int install_sigint(void)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = catch_sigint;
act.sa_flags = 0;
if (sigaction(SIGINT, &act, NULL) == -1)
return errno;
return 0;
}
static int install_default(const int signum)
{
struct sigaction act;
memset(&act, 0, sizeof act);
sigemptyset(&act.sa_mask);
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
if (sigaction(signum, &act, NULL) == -1)
return errno;
return 0;
}
int main(void)
{
struct timespec duration;
int result;
if (install_sigint()) {
fprintf(stderr, "Cannot install SIGINT handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
duration.tv_sec = 5;
duration.tv_nsec = 0; /* 1/1000000000ths of a second. Nine zeroes. */
printf("Sleeping for %d seconds.\n", (int)duration.tv_sec);
fflush(stdout);
while (1) {
result = nanosleep(&duration, &duration);
if (!result)
break;
if (errno != EINTR) {
fprintf(stderr, "nanosleep() failed: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
/* nanosleep was interrupted by a delivery of a signal. */
if (sigint_count >= 3) {
/* Ctrl+C pressed three or more times. */
if (install_default(SIGINT) == -1) {
fprintf(stderr, "Cannot revert SIGINT to the default handler: %s.\n", strerror(errno));
return EXIT_FAILURE;
}
printf("SIGINT has been reverted to the default handler.\n");
fflush(stderr);
}
}
if (sigint_count > 0)
printf("You pressed Ctrl+C %d time%s.\n", (int)sigint_count, (sigint_count > 1) ? "s" : "");
else
printf("You did not press Ctrl+C at all.\n");
return EXIT_SUCCESS;
}
The #define tells your C library (glibc in particular) that you want POSIX.1-2008 (and later) features from it.
The INT signal handler only increments a volatile sig_atomic_t counter. Note that this type may have a very small range it can represent; 0 to 127, inclusive, should be safe.
The main program waits using the POSIX nanosleep() function. On some systems, sleep() may be implemented via the SIGALRM function, so it is better avoided when using signals otherwise; nanosleep() does not interfere with signals like that at all. Plus, nanosleep() can return the amount of time remaining, if it is interrupted by a signal delivery.
In the main loop, nanosleep() will return 0, if it has slept the entire interval (but note that it may not update the remaining time to 0 in this case). If it is interrupted by the delivery of a signal, it will return -1 with errno == EINTR, and the remaining time updated. (The first pointer is to the duration of the sleep, and the second is to where the remaining time should be stored. You can use the same structure for both.)
Normally, the main loop does only one iteration. It can do more than one iteration, if it is interrupted by the delivery of a signal.
When the main loop detects that sigint_count is at least three, i.e. it has received at least three INT signals, it resets the signal handler back to default.
(Note that both the memset() and the sigemptyset() are important when clearing the struct sigaction structure. The memset() ensures that future code is backwards compatible with older code, by ensuring even padding fields are cleared. And sigemptyset() is the safe way to clear the signal mask (set of signals blocked while the handler runs).)
(In theory, memset() is not async-signal-safe, while both sigemptyset() and sigaction() are. This is why I reset the signal handler in the main program, and not in the signal handler.)
If you want to print from a signal handler, you need to use low-level I/O, because <stdio.h> functions are not async-signal safe. For example, you can use the following function to print strings to standard output:
static int wrerr(const char *p)
{
const int saved_errno = errno;
int retval = 0;
if (p) {
const char *q = p;
ssize_t n;
while (*q)
q++;
while (p < q) {
n = write(STDERR_FILENO, p, (size_t)(q - p));
if (n > 0)
p += n;
else
if (n != -1) {
retval = EIO;
break;
} else
if (errno != EINTR) {
retval = errno;
break;
}
}
}
errno = saved_errno;
return retval;
}
The above wrerr() function is async-signal safe (because it only uses async-signal safe functions itself), and it even keeps errno unchanged. (Many guides forget to mention that it is quite important for a signal handler to keep errno unchanged. Otherwise, when a function is interrupted by a signal handler, and that signal handler modifies errno, the original function will return -1 to indicate an error, but then errno is no longer EINTR!)
You can just use wrerr("INT signal!\n") if you want. The return value from wrerr() is zero if the write was successful, and an errno error code otherwise. It ignores interrupts itself.
Do note that you should not mix stderr output via fprintf() or other <stdio.h> functions with the above (except perhaps for printing error messages when the program aborts). Mixing them is not undefined behaviour, it just may yield surprising results, like wrerr() output appearing in the midst of a fprintf(stderr,...) output.
Its because of exit(0) statement in the handler, when SIGINT is raised, handler strlD gets called and you might thinking why signal(SIGINT,SIG_DFL) didn't work ? Actually it works. But your main process a.out get terminated successfully there itself by calling exit(0). remove exit(0) if you want to restore the behavior of SIGINT.
#include <unistd.h>
#include <stdio.h>
#include <termios.h>
#include <signal.h>
#include <stdlib.h>
void ctrlD(int sig){
//printf("CTRL+C pressed\n");/* just to observe I added one printf
statement, Ideally there shouldn't be any printf here */
signal(SIGINT, SIG_DFL);/*restoring back to original action */
}
int main(){
signal(SIGINT, ctrlD);/*1st time when CTRL+C pressed, handler ctrlD gets called */
while(1) {
printf("Hello\n");
sleep(5);
}
return 0;
}
Also its advisable to use sigaction() instead of signal() as told here What is the difference between sigaction and signal? . Read man 2 sigaction and man 2 exit to check what exit(0) means.
Also this How to avoid using printf in a signal handler?
Edit :
void ctrlD(int sig){
/* printf("CTRL+C pressed \n"); */
signal(SIGINT, SIG_DFL); /* only one time CTRL+C works
after that SIG_DFL will terminate whole process */
}
int main(){
signal(SIGINT, ctrlD); /* if you press CTRL+C then it will go to handler
and terminate */
int ch;
while( ((ch = getchar())!=EOF) ) { /* wait or read char until CTrl+D is not pressed */
printf("Hello : %d \n",ch);/* ASCII equivalent of char */
}
return 0;
}
Thank you everyone who contributed to this question. The resources provided/linked were tremendously helpful in learning more about signals (and that EOF isn't a signal), among the other wealth of information provided.
After some more research, I found out that somehow, either through some accidental bash command gone awry, or perhaps the program posted in my original question itself, I had altered the key mappings for my terminal's stty settings. If anyone finds themselves in this oddly specific situation in the future, I hope this can be of help, as it is what fixed my problem:
Enter the command $ stty -a to see all of your terminals settings, specifically the "cchars" section.
I then saw the reversal, and fixed it like so:
$ stty intr ^C
$ stty eof ^D
Then you can run $ stty -a once again to see that the changes have properly taken effect. Once again, thanks everyone.

can't get alarm() to work more than twice

static void AlarmHandler(int sig) ;
int i=0;
jmp_buf mark;
int main(int argc, char * argv[]){
setjmp(mark);
signal(SIGALRM, AlarmHandler);
alarm(2);
while(1);
return 0;
}
static void AlarmHandler(int sig) {
signal(SIGALRM, SIG_IGN);
printf("I am in AlarmHandler: %d \n",i);
i++;
longjmp(mark, 0);
}
When I run this code the program goes through the AlarmHandler only once and then it just stays trapped inside the while loop. Can someone explain why?
Your program might work as you expected on some POSIXy operating systems -- in fact, it does work as you expected on the computer I'm typing this on. However, it relies on a bunch of unspecified behavior relating to signals, and I think you've tripped over one of them: I think that on your computer, a signal is "blocked" — it can't be delivered again — while its handler is executing, and also, jumping out of the handler with longjmp does not unblock the signal. So you go around the loop once and then the second SIGALRM is never delivered because it's blocked. There are several other, related problems.
You can nail down all of the unspecified behavior and make the program reliable on all POSIXy operating systems, but you have to use different functions to set things up: sigsetjmp and sigaction. You should also get rid of the busy-waiting by using sigsuspend instead. A corrected program would look something like this:
#define _XOPEN_SOURCE 700
#include <signal.h>
#include <setjmp.h>
#include <stdio.h>
#include <unistd.h>
static jmp_buf mark;
static void
handle_SIGALRM(int sig)
{
static int signal_count;
signal_count++;
printf("SIGALRM #%u\n", signal_count);
siglongjmp(mark, signal_count);
}
int
main(void)
{
sigset_t mask, omask;
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
if (sigprocmask(SIG_BLOCK, &mask, &omask)) {
perror("sigprocmask");
return 1;
}
struct sigaction sa;
sigfillset(&sa.sa_mask);
sa.sa_flags = 0; // DO interrupt blocking system calls
sa.sa_handler = handle_SIGALRM;
if (sigaction(SIGALRM, &sa, 0)) {
perror("sigaction");
return 1;
}
if (sigsetjmp(mark, 1) >= 4)
return 0;
alarm(1);
sigsuspend(&omask);
perror("shouldn't ever get here");
return 1;
}
I should probably say a few words about signal safety: In this program, it is safe to call printf and siglongjmp from the signal handler, because I have arranged for the SIGALRM only to be deliverable while the main thread of execution is blocked on sigsuspend. (That's what the call to sigprocmask up top does.) If you had anything to do in your main thread of execution besides sleep waiting for the signal to arrive, you would have to be much more careful about what you did in the signal handler, and I would advocate for using pselect and/or the self-pipe trick instead of jumping out of the handler, if at all possible.

Resources