Problem on capturing system Shutdown

I am having exactly the same problem with Application Cleanup during Linux Shutdown but the thread is old and closed. The only difference is that I use sigaction() instead of signal(), which is recommended, as far as I know.

This is my code:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handler(int signal)
{
    FILE *out=fopen("test.txt","at");
    if (out)
    {
        fprintf(out,"got %d\n",signal);
        fclose(out);
    }
}

int main()
{
    struct sigaction sigIntHandler;

    sigIntHandler.sa_handler = handler;
    sigemptyset(&sigIntHandler.sa_mask);
    sigIntHandler.sa_flags = 0;

    sigaction(SIGINT, &sigIntHandler, NULL);
    sigaction(SIGTERM, &sigIntHandler, NULL);
    sigaction(SIGHUP, &sigIntHandler, NULL);
    sigaction(SIGQUIT, &sigIntHandler, NULL);
    while(1)
        sleep(30);
}


And this is some usage that shows that it is working:

$ rm -rf test.txt
$ ./signal_handling_test &
[1] 3599
$ kill -s SIGTERM 3599
$ cat test.txt
got 15

If I normally shutdown or log out then the process is killed without the clean up taking place.

I am running under Ubuntu 13.04.

Read this:

signal(7) - Linux manual page

Pay particular attention to the section "Async-signal-safe functions". Bluntly, you can't call async-signal-unsafe functions from a signal handler and expect proper results.

If you want to see what's happening, you can run your program under strace and see for yourself.

1 Like

Thanks a lot for your answer. I cannot understand anything from the phrase
"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:
...
list of functions
...
"
POSIZ.1-2004 requires an implementation? What does that mean? After I implement POSIX.1-2004 then I can safely call only the following functions that almost none of them have to do with writing to files?

Also, is there any way to exactly simulate shutdown for my process only so as not to shutdown my system all the time for testing purposes?

EDIT: Also, how come and the signal handler works each time if I send the SIGTERM? What different does the system do? I thought it sends SIGTERM through kill and waits a small timeout for the processes to end.

It means, the list of signal-safe functions are safe to use inside a signal handler. The POSIX stuff means that this is what's expected of a UNIX system.

How would you simulate shutdown without being shutdown? Killing all processes but not turning off the computer?

1 Like

I just downloaded the source code of ettercap-graphical (a well know application) and it doesn't use async-safe functions in the code (fprintf is being used, user interface is being normally shut down, the log file is flushed and closed). So how "strict" is it to make async-safe functions?

I also have this simple question: Why not use async-unsafe functions after all? The worse thing that could happen would be the application to crash or to be in a loop easily terminated with SIGKILL. The application was going to forcefully terminate after all. At least give it a chance to do a proper cleanup.

As for simulating shutdown: Now I am simulating shutdown with simply sending SIGTERM to my process. As I said before, this is not the only thing that really happens, because when I send SIGTERM it runs the handler without any problem. So, the system does something else that I am unaware of (I highly doubt that it really spends time on checking whether the function that is to be called is async-safe or not). So, I simply asked whether there is a better way to simulate the shutdown for only one process, because simply sending SIGTERM is not the best way. I don't believe I am being irrational.

I think you just answered your own question.

You can give it more than a chance -- you can actually do so. Async-safe system calls include open(), close(), read(), and write() among many other things. All you need.

fopen, printf() and its relatives in particular are not signal safe because they allocate memory. You might get away with it by accident but it's system-dependent, compiler-dependent, library-dependent, and luck-dependent. Your code may work all the time on your system and crash all the time on someone else's.

To write code that'll work both here and there, use signal-safe things. That's what they're for.

So you claim that if I make a sync-safe function using the above sync-safe functions, then the handler will be executed? And if this is true then how does the system determine:

a) Where in the memory the handler sits for each application
b) If the handler is sync-safe or sync-unsafe

Also, this is still a question:

What different does the system do instead of sending SIGTERM, waiting for the process to exit, and, after timing out, sending SIGKILL? Because it does something different, it not only sends SIGTERM, because if I send it, it just works.

Not necessarily, depending on how the program is killed. There are signals that cannot be interrupted. Further experimentation is required.

What I would do is create and close file when the program starts. When the signal handler is called, unlink() it. If the program cleans up properly, the file will disappear, if not, it will remain.

It doesn't "determine" unsafe things. It doesn't "punish" unsafe code. It's the software interrupt itself that is unsafe, really...

It halts your main program, whatever it's doing, finished or not; then does a graceless jump to a temporary, limited stack space. It leaves whatever was happening, dangling. main could be inside printf or malloc already when you try and call them in your interrupt handler. That would be bad.

So to get around this, you have to talk directly to the kernel with system calls, instead of using your handy stdio libraries and such. This avoids tearing out your floor from under you by accident.

I'd wonder if your disks are still mounted read-write by the time your program is killed. If they're not, you'll never see any changes even if your interrupt handler works.

So if it doesn't determine whether my function is sync-safe or not, the function should run without many problems most of the time (as you see, the file is accessed nowhere inside the program, a simple sleep is being done)

The only thing that I want my real handler to do is to save one variable into one file that is closed during the whole execution of the program. That is the only place where the file is opened for writing and closed.

The variable is being updated once per second (adding one to itself), so the chance of it being accessed the wrong moment is very slight, and even if it does, I don't really care.

If I understand correctly you are advising me on how to make a function sync-safe, and thanks a lot for that, but that was not my initial question. My initial question was why the handler is not executed while it should. Function being async-unsafe has nothing to do as far as I can understand from your last reply.

And one last thing: If my disk is not writable when I receive the signal, how the heck am I going to do my cleanup? How are other linux applications do stuff like this?

It may be getting proper cleanup, I'm not sure. Daemons definitely do, I'm not so sure of random user processes that happen to be sitting around.

My suggestion would be to try the suggestion I made earlier, unlinking the file...