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.
Related
This question already has answers here:
How to avoid using printf in a signal handler?
(8 answers)
Closed 2 years ago.
I have a code that looks like this:
//global variables
void signal_handler() {
//deallocation of global variables
free(foo);
close(foo_2);
exit(0);
}
int main () {
signal(SIGINT, signal_handler);
//irrelevant code
}
As you can see, I changed the CTRL+C interruption to execute the signal_handler function once instead of killing the process right away. I read somewhere that some functions like might be free are not async-safe and would NOT execute in the signal_handler but I'm not sure about that.
Can I execute functions like free, close, exit or even pthread_join in a signal handler?
No. Only functions listed in man 7 signal-safety are safe to call inside a signal handler.
close is listed and should be safe. free is not. For reasons why you would have to look at its source code (it contains locks). exit is not safe because it can call arbitrary cleanup handlers. You have _exit which exits abruptly without the cleanup.
You techincally can compile a program that calls such functions in a signal handler, nothing stops you from doing that. However it will result in undefined behavior if the function you are trying to execute is not async-signal-safe. It's not like unsafe function would just "NOT execute" as you say, they very well could, but that'd still be undefined behavior.
A list of async-signal-safe functions is documented in man 7 signal-safety. The close() function is safe, while free() and phtread_join() are not. The exit() function is also not safe to call from a signal handler, if you wish to exit from such context you will have to do so using _exit() instead.
The only way to safely call a function that is not async-signal-safe when receiving a signal is to "remember" that you have to call it (for example setting a global variable) and then do so after returning from the signal handler.
Short answer is no:
7.1.4 Use of library functions
...
4 The functions in the standard library are not guaranteed to be reentrant and may modify
objects with static or thread storage duration.188)
188) Thus, a signal handler cannot, in general, call standard library functions
C 2011 Online Draft
Real-world example of the consequences - I worked on a system that communicated with an Access database. There was a signal handler that tried to write an error message to the console with fprintf, but somehow during the signal handling process stderr got mapped to the .mdb file that stored the database, overwriting the header and ruining the database beyond repair.
There's honestly not a whole lot you can do in a signal handler other than set a flag to be checked elsewhere.
Can I execute free() or close() in a signal handler?
You definitely should not. See signal(7) and signal-safety(7)
In practice, it might work like you want perhaps more than half of the time. IIRC, the GCC compiler is doing like you want to do, and it usually works.
A better approach is to use some write(2) to a pipe(7) (from inside your signal handler) and from time to time check that pipe (in your main program) with poll(2) or related things.
Or you could set some volatile sigatomic_t flag; (perhaps it should be also _Atomic) in your signal handler, and check that flag elsewhere (in the main program, outside of signal handlers).
Qt is explaining that better than I could do in a few minutes.
On Linux, see also signalfd(2) and eventfd(2).
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.
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.
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;
}
Any ideas on this? Is there some kind of a signal queue, or does it get dropped?
While we are at this question, is it true that signal handlers should do as minimal work as possible?
I read somewhere that a signal handler should use a pipe and just write one byte to it, indicating what the program should do. Then somewhere else the program periodically checks the pipe, and dispatches based on byte in it. (I might have misunderstood it)
Thanks, Boda Cydo.
To answer the second part of your question, "is it true that signal handlers should do as minimal work as possible?" the answer is yes, because there is a very minimal set of functions that are "async signal safe" and therefore able to be called from signal handlers. Async signal safety is kind of an enhanced form of re-entrancy. If foo() is async signal safe, that means that it's safe to call foo() within a signal handler, even if foo() was already executing when the signal was raised.
You can get the full list of async signal safe functions by looking that the section 7 man page for signal (man 7 signal). Calling any function other than one of these from within a signal handler, directly or indirectly, invokes undefined behavior.
The "write a byte to a pipe" approach is a great way to deal with signals without being restricted to async signal safe functions, especially if your program is already oriented around a select loop.
To answer the first part of your question, the default is as follows: If it's the same signal as the one currently being handled, the new signal is blocked (held in a queue) and delivered when the handler returns. If some other signal arrives, the handler for the new signal is called. c.f. the glibc manual.