Thursday, January 5, 2012

Using kill

Versión en español

While working, I have heard persons saying that the terminate the process / services using kill -9, because that way "the process always ends" (true history). This way of terminating process has a problem, you can lose information.

Let's explain it. First, the kill command , this command sends signals to the processes (see wikipedia). This type of interprocess communication is very simple and asynchronous (usually). If you already checked the man pages (man 7 signal) or the wikipedia link, you will see that there are different signals, for example:: SIGINT, SIGTERM, SIGKILL, etc; and there are some signals that can't be handled, for example: SIGKILL. ¿What does it mean that it can't be handled? According mi experience, you can't program a handler for those signals, in other words the process never see it coming, the os just apply the signal..

For a better understanding, let's use our best friend C (I hope you have the C compiler installed)

First, create a file called test.c

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

volatile int FINISH = 0;

void handler(int sig)
{
    if (sig == SIGINT) {
        fprintf(stderr, "Interrupted: Closing files\n");
        FINISH = 1;
    } else if (sig == SIGTERM) {
        fprintf(stderr, "Terminating: Closing files\n");
        FINISH = 1;
    } else {
        fprintf(stderr, "I don't know what to do with this signal\n");
    }
}

int main(void)
{
    FILE *f = NULL;
    struct sigaction sa;
    sigemptyset(&sa.sa_mask);
    sa.sa_handler = handler;
    if (sigaction(SIGINT, &sa, NULL) == -1) {
        perror("sigaction with SIGINT");
    }
    if (sigaction(SIGTERM, &sa, NULL) == -1) {
        perror("sigaction with SIGTERM");
    }
    if ((f = fopen("test_file.txt", "w")) == NULL) {
        perror("Couldn't open test_file.txt for writing");
        exit(1);
    }
    while (!FINISH) {
        fprintf(f, "hello");
        fprintf(f, " ");
        sleep(5);
        fprintf(f, "world\n");
    }
    fclose(f);
    exit(0);
}

Some remarks, the handler function handles the signals defined with sigaction. I didn't try to handle  SIGKILL a.k.a 9, because you can't handle it, if you try it, the os will ignore you. The code is in a while loop writing hello world in a file. When we send the interrupt or termination signal, the program will finish gracefully, closing the file, etc. Instead if we send the SIGKILL, it's very likely that the file ends empty or corrupt. Try it.

Compile
$ cc -Wall -o test test.c

Execute
$ ./test

In another terminal, execute some of this three commands
pkill -SIGINT test
pkill -SIGTERM test
pkill -SIGKILL test

Between executions, check the test_file.txt file and compare the results. If you exec kill with SIGKILL the results should not be as expected. Now you know why, you shouldn't terminate processes, like a database system with SIGKILL. You could end with lost or corrupt data (a lot of fun ^_^).

As a remainder, first try to terminate the process being nice (SIGTERM), and if after a time it doesn't end, then you call your hitman friend (the os) to do the dirty job (SIGKILL).

That's all folks.

Alejandro

No comments:

Post a Comment