Why we call Signal Handler twice? - c

I am a novice to signal handling using c language. I am analyzing below signal handling code which extracted from specific resource.
Here is that code .
#include <stdio.h>
#include <signal.h>
void intproc();
void quitproc();
main()
{
int i;
signal(SIGINT,intproc);
signal(SIGQUIT,quitproc);
printf("Ctrl+c is disabled. Use ctrl+\\ to quit\n");
for (i=0;;i++) {
printf("In an infinite loop...\n");
sleep(200);
}
}
void intproc()
{
signal(SIGINT,intproc);
printf("You have pressed ctrl+c.\n");
}
void quitproc()
{ signal(SIGQUIT,intproc);
printf("You have pressed ctrl+\\. Now the program quits.\n");
exit(0);
}
what I want to know is why we call again Signal handler "(SIGINT,intproc)" inside intproc() function ?
I tried to run this code without that signal handler within that function ,and its also working .

This is very old code. In the old days (perhaps SunOS3, 1990-s) a signal handler was automatically uninstalled when executed. See signal(2) (difference between SysV and BSD behavior) and avoid using signal.
Carefully read signal(7) then use sigaction(2). Don't use signal(2). Care about async signal safe functions (the only ones you can call from a signal handler; you should not use printf inside a signal handler!). Consider simply setting some volatile sig_atomic_t global (or static) variable inside your signal handler (and test it outside).
Read Advanced Linux Programming which explains these things in detail.

After the function intproc has completed, the program carries on, but the signal action is restored to the default. When it receives a second SIGINT signal, the program takes the default action, which is to terminate the program.
If you want to retain the signal handler, you would need to re-establish it by calling signal again.
This is the reason you should always prefer the more robust sigaction over the signal function.

Related

Handle signals in ncurses

I am writing a program in C using ncurses.I am trying to handle the CRTL C signal. In my code, this signal is being caught and dealt with but the program is not termination correctly. Could it be the way I am exiting from ncurses?
//handle SIGINT signal
void handle_signal(int signal){
if(signal == SIGINT){
clear();
mvprintw(3,3,"A SIGNAL WAS ENCOUNTERED");
refresh();
sleep(1/2);
exit(0);
} //close if statement
}//close handle_signal() function
Without further research: I'd be VERY surprised if curses functions were actually signal safe. It's generally best practice to keep your signal handlers minmal, ideally just setting a flag. So, you should solve your problem like this:
static volatile sig_atomic_t interrupted = 0;
in your signal handler:
if (signal == SIGINT)
{
interrupted = 1;
}
somewhere in your main loop:
if (interrupted)
{
clear();
mvprintw(3,3,"A SIGNAL WAS ENCOUNTERED");
refresh();
sleep(1);
endwin();
exit(0);
}
Note your code didn't call endwin() anywhere, this is required for restoring the terminal to normal.
As noted in the initscr manual page, ncurses installs a handler for SIGINT
The handler attempts to cleanup the screen on exit. Although it
usually works as expected, there are limitations:
If you setup your handler before initscr (or newterm), it will not be called. If you setup the handler after, you'd have to take into account the various limitations of what functions you can safely call in a signal handler.
ncurses' handling of SIGINT takes into account the fact that some of the functions it would normally use are not safe, and it uses a different strategy when it has receive a signal (which is perhaps not 100% reliable, but an improvement).
Your signal handler does not take any of that into account, and for example ncurses could call malloc to handle some extra output-buffering needed, and "not work", since malloc is not a safe function to use.
Further reading:
Apparent malloc from signal handler (and followup)
I need a list of Async-Signal-Safe Functions from glibc
signal - overview of signals

Save data about signal in file?

I am trying to save certain information about the signal in a file, e.g. time it was caught, etc, in the signal handler.
void sig_handler(int signo){
curr_signal = time(NULL);
receivedtime[z] = curr_signal;
signumber = signo;
diff = curr_signal - receivedtime[z-1];
z++;
write(f, &diff, sizeof(diff));
}
I have updated my program to write inside the file (f). My problem is that nothing is being written inside the file.The file is being created.
Be careful about the calls from inside your signal handler.
From man 7 signal:
Async-signal-safe functions
A signal handler function must be very careful, since processing else‐
where may be interrupted at some arbitrary point in the execution of
the program. POSIX has the concept of "safe function". If a signal
interrupts the execution of an unsafe function, and handler either
calls an unsafe function [...],
then the behavior of the program is undefined.
And follows a list of the functions that are async-signal-safe.
Your signal handler calls:
time(): ok, it is async-signal-safe
fprintf(): nope, it is not.
The existing answer tells you why it doesn't work: you call signal-unsafe functions in your signal handler. I want to add what to do instead: it's best practice to do as little as possible inside the handler and instead inform your "normal" code about the signal. This can be done using a volatile sig_atomic_t variable. Just update your data structures and set a volatile sig_atomic_t to 1. In your main code, check that variable periodically, and if it is set, do the desired output and set it back to 0.

LInux signals concepts

How signal handler takes the signal number without passing arguments to signalhandler() function in main()?
For example in the below source code inside main() passing 2nd argument of signal system call as signalhandler without any argument in signal handler but while coming to signalhandler definition it is collecting an argument with name sig_num ...
How actually it is possible?
According ANSI C if we don't pass any arguments then function definition will should not collect any argument.
Please help me regarding this.
#include<stdio.h>
#include<signal.h>
void signalhandler(int sig_num)
{
printf("caught signal number: %d\n", sig_num);
}
int main(void)
{
while(1)
{
printf("hello world\n");
sleep(1);
signal(SIGINT, signalhandler);
}
}
Your function signalhandler is not called when you give it as an argument of signal(2). The prototype is :
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
So you can see that the second argument is a function pointer. Your function signalhandler will be called later (when a signal is delivered) and the code that will call it will give it an int argument.
Take a look at some other function pointer examples to understand better this callback mechanism.
The signal API registers the provided function pointer to be called upon receipt of the specified signal. It is possible to register the same function pointer against multiple signals, so the function when called will be provided the signal value that was received.
In Linux (and all operating systems that I am aware of) signal delivery is asynchronous to the process's execution, and the notification is immediate. The OS behaves as if it preempts the program and injects the signal handler function call on top of whatever the program is currently doing. The OS is aware which signal was delivered, and passes it as the parameter to the function call.
Note: It is possible to use raise to generate a synchronous signal to the program. But, it will typically use the OS service to deliver it to the process rather than directly invoke the signal handler.
If you use a debugger and set a breakpoint within your signal handler, and deliver the appropriate signal, you might see that the backtrace will show that the signal handler is being injected by the OS.
For example, consider the program:
void signalhandler (int sig)
{
write(2, "signal!\n", 8);
}
void foo (void)
{
for (;;) {}
}
int main (void)
{
signal(SIGINT, signalhandler);
foo();
}
When running the program in gdb, you can deliver the signal with the signal command. The resulting backtrace would look like:
(gdb) signal SIGINT
Continuing with signal SIGINT.
Breakpoint 1, signalhandler (sig=2) at s.c:5
5 write(2, "signal!\n", 8);
(gdb) bt
#0 signalhandler (sig=2) at s.c:5
#1 <signal handler called>
#2 foo () at s.c:10
#3 0x08048498 in main () at s.c:16
Note: It is important to realize that the signal handler function call should not be treated like a regular function call. Since the OS injects the call, it has limitations that are discussed below.
The signal call can be injected at some arbitrary place in your code execution. For this reason, POSIX mandates certain functions to be safe to be called from signal handlers. Functions that are not designed to be re-entrant run the risk of being in an inconsistent state if it is interrupted by a injected call to the signal handler function, which then in turn calls the interrupted function.
As an example of a problem that could happen, suppose you are writing code that is manipulating a data structure, such as removing a node from a linked list. However, if the pointers of the elements have not been completely fixed up when the signal is delivered, then the signal handler may see a corrupted linked list. This situation can happen more often than you might assume, especially if you call a function that requires heap allocation.
Thus, it is often safest to make the signal handler dead simple. For example, the signal handler may simply set a flag, and your application code would then need code to detect whether or not the flag was set.
I will explain in simple terms.
Signal are way of delivering messages to a program. For example when the program is running in a terminal window and you press Ctrl+C then the terminal window sends SIGINT to the program.
Now, for each process, the kernel maintains a table which maps from each signal to what is to be called when the signal is received. By default, on SIGINT, the behavior is set to terminate. But, a program can change the default behavior for some signals by a call to the function signal.
Eg. signal(SIGINT, funcHandler) changes the behavior on receiving SIGINT from termination to calling funcHandler. But it never calls funcHandler. funcHandler will be called when the program receives a SIGINT.
Now, when the program receives SIGINT then the kernel looks up the table to decide which function to call(say handler), then the kernel sets up handler's stack with the received signal as the argument and then returns to the program. As effect funcHandler is called with signal_number as the argument in the program's context.

OSX "Illegal instruction 4" with nested function

The goal here was to catch SIGINT to close the server socket on a little socket server. I've tried to use a nested functions to keep the code clean. But...
When I do Ctrl-C (SIGINT, right?), I get Illegal instruction: 4. After reading this post, I've tried adding -mmacosx-version-min=10.8 to the compile flags since I'm on 10.8. Same error when doing Ctrl-C.
Two questions here: Why do I get `Illegal instruction 4"? How can I close the server socket without using a global variable?
My software:
Mac OSX 10.8.4
GCC 4.2.1
Here's how I'm compiling:
gcc -fnested-functions main.c
Here's the code:
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
void register_sigint_handler(int *serverSocket)
{
void sigint_handler(int signal) {
printf("Shutting down...\n");
printf("Server socket was %d\n", *serverSocket);
close(*serverSocket);
exit(0);
}
signal(SIGINT, &sigint_handler);
}
int main(void) {
int serverSocket = 0, guestSocket = 0;
register_sigint_handler(&serverSocket);
serverSocket = socket(PF_INET, SOCK_STREAM, 0);
while (1) {}
close(serverSocket);
return 0;
}
While I can't tell you specifically what happens, the gcc docs have a generalization:
If you try to call the nested function through its address after the
containing function exits, all hell breaks loose.
Passing the function pointer to signal() will do exactly that, call your local function after the containing function has exited. So you shouldn't pass a nested function pointer to signal()
You should probably just use a normal function for the handler, which sets a flag.
static volatile int do_exit;
void sigint_handler(int sig)
{
do_exit = 1;
}
In a server one usually have main loop of some sort, around e.g. select or poll, your main loop, the empty while loop can now become
while (!do_exit) {
pause();
}
(Note that sockets are automatically closed by the operating system when the process exits;)
"Don't do that, then."
GCC's nested-functions-in-C extension does not provide true closures. When you take the address of sigint_handler, a "trampoline" (a small piece of self-modifying code) is written to the stack; as soon as register_sigint_handler exits, the trampoline is destroyed; a subsequent attempt to invoke the trampoline (by the kernel, in order to dispatch the signal) causes undefined behavior.
Signal handlers are process-global by definition. Therefore, it is incorrect in principle to attempt to avoid using global variables in signal handlers. Imagine what you'd do to make this code cope with two server sockets: you can only have one SIGINT handler registered, so somehow it has to close both sockets.
All open file descriptors are automatically closed when your process terminates. Therefore, it is not necessary to close them by hand first. Furthermore, it is a breach of convention to exit successfully on ^C. If this program were being driven by a supervisory process, that process would want to know (via waitpid's status code) that it exited because of a SIGINT. Putting those two things together, you should not have this signal handler at all.
(That stops being true if you need to do something to your active sockets on exit. For instance, if you wanted to write something to every active client connection on exit, you'd want a signal handler. But at that point you want to have the signal handler alert the main event loop, and do the work there.)
(Consider using libevent for this sort of thing rather than doing all the low-level goo yourself.)

Can exit() fail to terminate process?

I have a registered a signal handler in my program. Upon receiving an undesired signal (SIGABRT), i call 'exit(-1)' in signal handler to exit the process. But as noticed on few ocassions, it calls exit() but fails to terminate the process.
The issue was randomly generated and I strongly suspect on execution of exit().
Can there be any reasons or cases in which the exit() can fail to terminate the process.
Thanks.
Are you calling exit() from the signal handler?
In man 7 signal, section Async-signal-safe functions you can see all the functions that are guaranteed to work when called from an signal handler:
A signal handler function must be very careful, since processing elsewhere may be interrupted at
some arbitrary point in the execution of the program. POSIX has the concept of "safe function". If
a signal interrupts the execution of an unsafe function, and handler calls an unsafe function, then
the behavior of the program is undefined.
POSIX.1-2004 (also known as POSIX.1-2001 Technical Corrigendum 2) requires an implementation to
guarantee that the following functions can be safely called inside a signal handler:
There you can see functions _Exit(), _exit() and abort(), but notably not exit(). So you should not call it from a signal handler.
The nasty thing is that even if you call an unsafe function from a signal handler (printf() any?) it will just work most of the time... but not always.
Yes, there are some circumstances, such as:
The exit() function shall first call all functions registered by atexit(), in the reverse order of their registration, except that a function is called after any previously registered functions that had already been called at the time it was registered. Each function is called as many times as it was registered. If, during the call to any such function, a call to the longjmp() function is made that would terminate the call to the registered function, the behavior is undefined.
If a function registered by a call to atexit() fails to return, the remaining registered functions shall not be called and the rest of the exit() processing shall not be completed. If exit() is called more than once, the behavior is undefined.
See the POSIX page on exit.
For more information, attach a debugger when you reach the situation and take a look at the call stack.
I had analogous problem to the one described by Madar. I needed to perform an action for every signal and quit properly. I wondered through a couple of answers to similar issues and came up with the following explanation/solution.
Explanation:
One issue is that exit() should not be used in signal handlers because it is not one of the async-signal-safe functions (see man signal-safety). This is to say that it may but is not guaranteed to work in signal handlers. As a result you would need to call _exit()/_Exit() (which are async-signal-safe). These however terminate the process instantly, without calling the atexit callbacks and static destructors. My understanding is that for some signals a bit more cleaning can be done than what those functions provide.
Solution: The solution I came up with is to register your signal handler for all signals and do any extra steps. Then you can reset to the default handler and call raise(signal_number), which is async-signal-safe, to re-send the singal and so execute the default handler.
Here is a working example that runs default handler only on SIGINT. I think this is too simple to experience the "failing" exit() if you used it in the handler. I tested similar code with an alternative stack to also handle SIGSEGV.
Note If you want this to work properly in multi-threaded context (e.g. multiple threads causing SIGSEGV at the same time) you need to take some care about synchronization. Threads share the same handler but have separate signal masking.
#include <csignal>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <unistd.h>
// The actual signal handler
extern "C" void handleSignal(int sig, siginfo_t *siginfo, void *) {
// Cannot use printf() - not async-signal-safe
// For simplicity I use a single call to write here
// though it is not guaranteed to write the whole message
// You need to wrap it in a loop
// Die only on Ctrl+C
if(sig == SIGINT) {
const char *msg = "Die\n";
write(STDERR_FILENO, msg, ::strlen(msg));
// Reset to use the default handler to do proper clean-up
// If you want to call the default handler for every singal
// You can avoid the call below by adding SA_RESETHAND to sa_flags
signal(sig, SIG_DFL);
raise(sig);
return;
}
// Here we want to handle the signal ourselves
// We have all the info available
const char *msg = "Continue\n";
write(STDERR_FILENO, msg, ::strlen(msg));
}
int main() {
// You might want to setup your own alternative stack
// eg. to handle SIGSEGV correctly
// sigaltstack() + SA_ONSTACK flag in sa_flag
// Prepare a signal action for handling any signal
struct sigaction signal_action;
signal_action.sa_sigaction = ::handleSignal;
signal_action.sa_flags = SA_SIGINFO;
::sigfillset(&signal_action.sa_mask);
// A vector of all signals that lead to process termination by default
// (see man -s 7 signal)
const int TERM_SIGNALS[] = {
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV,
SIGPIPE, SIGALRM, SIGTERM, SIGUSR1, SIGUSR2, SIGBUS, SIGPOLL,
SIGPROF, SIGSYS, SIGTRAP, SIGVTALRM, SIGXCPU, SIGXFSZ};
// Register the signal event handler for every terminating signal
for (auto sig : TERM_SIGNALS) {
::sigaction(sig, &signal_action, 0);
}
while(true);
return 0;
}

Resources