Which signal was delivered to process deadlocked in signal handler
I would try "frame 15" to move to the signal delivery frame, followed by "print $_siginfo.si_signo". See https://sourceware.org/gdb/onlinedocs/gdb/Signals.html
This works on Linux at least, which I presume from your backtrace that you are using. I'm not sure about other platforms.
Does anybody have an Example of A Non-Async Safe Signal Handler Deadlock
You are not seeing any deadlock or other failure for two reasons. First, and most important, your program is sitting in a spin loop waiting for signals to be delivered.
// loop and wait for signals
while (1) {}
This means there is never anything "interesting" for a signal handler to interrupt. If you changed it to something like this:
while (1) {
size_t n = rand();
char *p = malloc(n);
free(p);
}
then you'd have a chance of your signal handler that calls malloc
interrupting the normal flow of execution inside malloc
, which is one way that async signal handlers could cause a deadlock.
The other reason is, on your system, signal(SIGINT, handler)
is installing a handler whose execution cannot be interrupted by another SIGINT
. The C standard doesn't say whether signal
does this or not, but most modern Unixes do it that way. You can get a signal handler whose execution can be interrupted by dropping down to the lower-level sigaction
: replace your signal
call with
struct sigaction sa;
sa.sa_handler = inthandler;
sa.sa_flags = SA_NODEFER | SA_RESTART;
sigemptyset(&sa.sa_mask);
sigaction(SIGINT, &sa, 0);
This will also enable the possibility of a signal arriving within the guts of malloc
.
Signals are one of the most confusing and difficult aspects of the low-level Unix API. I encourage you to acquire a copy of W. Richard Stevens' book Advanced Programming in the Unix Environment and read the chapters on signal handling. It's an expensive book, but you should be able to request it at your local public library.
behaviour of unix process when a signal arrives and the process is already in signal handler?
By default signals don't block each other. A signal only blocks itself during its own delivery. So, in general, an handling code can be interrupted by another signal delivery.
You can control this behavior by setting the process signal mask relatively to each signal delivery. This means that you can block (or serialize) signal delivery. For instance you can declare that you accept to be interrupted with signal S1 while handling signal S2, but not the converse...
Remember that signal delivery introduces some concurrency into your code, so controlling the blocking is needed.
signal handling in linux and interrupted function calls?
This is not deadlock. A deadlock is a situation where P1 waits P2 to finish and P2 waits P1 to finish...
Your problem is a eventually a matter of concurrent access and the solution is to use locks. A lock lets a program/thread to accomplish some task atomically. The strategy is to use a lock L
shared by the two process/threads in such a way: GET(L); do some task; RELEASE(L);
What is wrong in your code is that signal delivery interrupts your sleep
calls. And when such a call is interrupted it does not restart at the end of the handling. The manuel says:
If the sleep() function returns due to the delivery of a signal,
the value returned will be the unslept amount (the requested time
minus the time actually slept) in seconds.
So you can modify your loops like this:
if (pid > 0) {
while(1) {
int v = 500;
while ((v=sleep(v))!=0); // restart while delay not passed
kill(pid,SIGUSR1);
}
}
else {
while(1) {
int v=5;
while ((v=sleep(v))!=0); // restart while delay not passed
kill(ppid,SIGUSR2);
}
}
I can also suggest not to use the old signal
interface but sigaction
which is more safe and reliable (you will never have to reset the signal
handling in the signal handler for example).
How to get backtrace of external source which generated the signal?
As suggested by others, use GDB, set a breakpoint at the signal handler, and display the backtrace using the bt command.
If your program does not take parameters, its easy:
> gdb myprogram
> br mySignalHandler
> run
When it hits the breakpoint, type bt to get the traceback:
> bt
If you program needs command line parameters, using the --args option:
> gdb --args myprogram param1 param2 etc
> br mySignalHandler
> run
And it will stop when it enters your mySignalHandler routine. Type bt to get your backtrace.
This is also very useful for when your code segfaults, but in that case there is no need to set a breakpoint. Segfaulting code stops automatically and then you can type bt to find out where it died.
Related Topics
Qfiledialog: How to Filter Only Executables (Under Linux)
How Does One Override an Existing Zsh Keyboard Completion
How to Get "Instant" Output of "Tail -F" as Input
U-Boot: Cannot Boot Linux Kernel Despite Kernel Being Less Than Maximum Bootm_Len
PHPmyadmin Mcrypt Extension Is Missing
Shell Script to Shutdown/Restart Linux System
X11 Configurenotify() Always Returning X,Y = (0,0)
Bash Script with User Defined Functions in Autocomplete
How to Link a Linux's Thread Tid and a Pthread_T "Thread Id"
How to Capture Unix 'Top' Command Output to a CSV File
Arguments Were Passed Wrong in Pthread
Page Fault in Interrupt Context
How to Specify a Local Bond Interface to Multicast Socket in Haskell
How to Reset Tty After Exec-Ed Program Crashes
Determining The Independent Cpu's (Specified with Affinity Id's) for Building Atlas