Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

signal handling in linux for c

Tags:

c

linux

signals

I am trying to understand how signals work in Linux from the sample program that I found online, but it has some parts which I don't really understand.

This is my sample program:

#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

void catcher(int sig) {
    printf("catcher() has gained control\n");
}

int main(int argc, char *argv[]) {
    struct sigaction sigact;
    sigset_t sigset;

    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigact.sa_handler = catcher;
    sigaction(SIGUSR1, &sigact, NULL);

    printf("before first kill()\n");
    kill(getpid(), SIGUSR1);

    sigemptyset(&sigset);
    sigaddset(&sigset, SIGUSR1);
    sigprocmask(SIG_SETMASK, &sigset, NULL);

    printf("before second kill()\n");
    kill(getpid(), SIGUSR1);
    printf("after second kill()\n");

    return 0;
}

Here is the sample output from my program:

before first kill()
catcher() has gained control
before second kill()
after second kill()

Can I know why the first line in the output is before first kill()? Why doesn't catcher() has gained control appear first?

From what I know, sa_handler consists of two types of signal, signal default and signal ignore.

How do we know which signal it will generate? Why would it trigger the function to print the catcher() has gained control if the signal ignore being generate?

Besides, what is the sa_mask function in this program? In my understanding, sa_mask will block the specified signal.

like image 256
doe Avatar asked Nov 09 '22 06:11

doe


1 Answers

Can I know why the first line in the output is before first kill()? Why doesn't catcher() has gained control appear first?

You installed a signal handler that catches SIGUSR1. Until SIGUSR1 is delivered to the process, normal program execution flow keeps happening. So, here:

printf("before first kill()\n");
kill(getpid(), SIGUSR1);

You only generate the signal after printing before first kill(). Why don't you expect this to appear before catcher() has gained control? In other words, when you call printf("before first kill()\n");, no signals have been raised yet, so you can only expect program execution to remain normal.

This line:

kill(getpid(), SIGUSR1);

Generates SIGUSR1. The operating system delivers the signal to the process at a convenient time. Because you installed a handler for SIGUSR1, your signal handler (catcher()) is invoked. You raise the signal after printing the first line, so it is expectable that the next line of output will come from the signal handler.

Note that printf(3) is not async-signal safe, so technically you can't call it from inside a signal handler, but it is usually ok for these toy examples.

From what I know, sa_handler consists of two types of signal, signal default and signal ignore.

There's more to it than that. The sa_handler field of struct sigaction can have the values SIG_DFL, which corresponds to the default signal action (the default action is listed in man signal), and SIG_IGN, which means the signal is ignored (nothing happens when it is raised). But sa_handler can also be a pointer to a function that you want to be invoked every time the signal is delivered. This is what the code you showed is doing - it is saying: Hey, when SIGUSR1 is delivered, please call catcher().

How do we know which signal it will generate? Why would it trigger the function to print the catcher() has gained control if the signal ignore being generate?

You indicated a signal (SIGUSR1) when you called sigaction(2) to setup the handler. So, catcher() will be called when SIGUSR1 is delivered.

Besides, what is the sa_mask function in this program? In my understanding, sa_mask will block the specified signal.

It's a signal mask that is atomically installed when the signal handler is entered, and uninstalled when the signal handler returns. By default, even if you pass it an empty mask, the signal being caught is always blocked upon entering the handler (unless the SA_NODEFER flag is set in the sa_flags field of struct sigaction). However, you might want to block other signals while the handler is executing - the way you do that is by indicating these signals in sa_mask.

like image 66
Filipe Gonçalves Avatar answered Nov 14 '22 23:11

Filipe Gonçalves