Which Signal Was Delivered to Process Deadlocked in Signal Handler

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



Leave a reply



Submit