Tuesday, July 22, 2014

The truth behind Linux signals

Today I'll be talking about signals in Linux.
Along to this discussion i'll be giving  two code examples so you would get a better grasp on the topic. So let's start:

Signals is another way of communicating a between either the kernel and a process or among the processes (IPC mechanism), they are usually called software interrupts since they occur asynchronous.

There are 32 types of signals (as mentioned in NSIG, see file: signals.h), each signal is triggered when specific scenario occurs.for each signal there is a default registered  signal handler, which would be invoked in such specific scenario.

If we would like to register and use our proprietary signal handler instead of OS's signal handler, we can make some good use of the system call signal().

The list of signals can be easily view in the header file: signals.h
moreover we can send a signal to a specific process via the system call kill, mentioning the pid and the signal number.

I'm quite sure for those of you programmers out there, during your coding journey you have probably received few Segmentation faults along the way. such as the following message:

"line 45: 27702 Segmentation fault      (core dumped) "

As you may know this popular message is generated in response to a segmentation fault which occurred while de-referencing an invalid memory.
There could be many reasons for it, such as:
A process tried to access a part of kernel memory while running in user mode, or a process tried to modify a variable which
is located on read-only memory (text segment or mapped memory marked as read only) - a simple example will be given later.
so eventually the operating systems invokes a signal SIGSEGV.

The SIGSEGV is a single example of signal among the 32 which exist.

The signal SIGINT is quite useful too in Linux, for terminating the foreground process.

Another well known is SIGFPE is invoked when an illegal arithmetic operation have been done, such as dividing by zero.

Here is a quite straightforward program which I wrote,
which demonstrates signals in action:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <stdio.h>
#include <signal.h> /* For using SIGINT/SIGSEV/SIGFPE defininations and the function signal */
#include <stdlib.h>
#include <stdint.h>

int my_global_sighandler(int signum)
{
 switch (signum) 
 {
 case SIGINT:
   printf("\nAttenion: An interrupt signal was invoked!\n");
   break;
 case SIGSEGV:
  printf("\nAttention: a segmentation fault occured\n");
  break;
 case SIGFPE:
  printf("\nAttention: an Arithemtic error occured \n");
  break;
 }

 printf("\nProcess (PID=%d) has recieved a signal of type  \"%s\" (message from my signal handler)\n",getpid(),strsignal(signum));
 exit(EXIT_FAILURE);
}

int main(int argc, const char *argv[])
{
 char *s = "Introductions to signals";
 sigset_t int_mask;
 int  a = 5;
 double res;
 uint8_t user_pick;
 
 /* Registering few Signals to signal handler: my_global_sighandler */
 signal(SIGINT,my_global_sighandler);
 signal(SIGFPE,my_global_sighandler);
 signal(SIGSEGV,my_global_sighandler);

 printf("\n****Coding for pleasure - Today's talk is Linux's Signals****\n");
 printf("There are 32 signals, but here I'll demostrate three common signals, so lets start:\n");
 printf("\nWhich signal you would like to generate?:\n");
 printf("1) SIGINT - Interrupt \n2) SIGFPE - Floating point exception \n3) SIGSEGV - Segmentation fault\n");
 scanf("%d",&user_pick);
 printf("\nGenerating signal ...\n");

 switch (user_pick) 
 {
 case 1:
  printf("\nPress Ctrl+c for invoking SIGINT signal\n");
   while (1);
   break;
 case 2:
  printf("\nGenerating an Illegale arithmetic calculation for invoking SIGFPE signal\n");
  res = user_pick / 0;
  break;
 case 3:
  printf("\n");
    *s='H';
  break;
 default:
  printf("Wrong number, should pick 1-3\n");
  break;
 }
}  

We can see the pointer s is assigned a string which is located on the read only memory segment. so any change to the value pointed by s, would invoke a segmentation fault.
For getting a better grasp about this error you can easily see for yourself by printing the address the of the string and then see in /proc/<process pid>/maps in which memory segment range the string falls into.

More to say about signals, signals also can be blocked too. In case you have put some thought and came to conclusion your process should be  sleeping/waiting and block any signals heading your way, so you won't be interruptible. you can do this easily via calling function sigprocmask, soon I'll be elaborating on the subject more.

A great reference about signals handlers can be seen here:
http://osr600doc.sco.com/en/SDK_sysprog/_Signal_Handlers.html

No comments:

Post a Comment

About