This tutorial is about Signals. We will explain Linux signals with an experiment showing LED toggling upon receiving a signal. We are going to use C Code for this example. In this tutorial you will need to use serial port and a LED connected to beaglebone board. We are using Beaglebone Black Board for this purpose. But any board on which you can blink LED on Linux can be used.
EmbeddedCraft YouTube Channel Reference
We have created video tutorials explaining using serial port and using G P I O in Linux. Refer these links
Accessing GPIO and LED Blinking - LED Blinking Program in C for Beaglebone Black board
Beaglebone Black Board: Serial Port Interfacing
Connecting Beaglebone Black board with Serial Port
Embedded Linux @ EmbeddedCraft YouTube Channel
What are Signals in Linux
Signal is very similar to interrupt. it is a method of sending notification to process. Linux Process can receive signals from multiple sources. For example, SIGBUS signal. child process can also send SIG CHLD signal to parent process.
Figure 1: Signal Handler
What will when signal is received by Linux Process
When signal is received, process will run signal handler. When execution of signal handler is complete, control will return back to process. Signal handler to be registered first.
For some signals, there are predefined activities, which a process will do upon receiving signal. When SIG KILL signal is received then the Process will terminate.
For some signals, core dump is also generated, for example SIG ABRT. In case of SIG ABRT signal, process is terminated and code dump is generated. Signal can also let Process execution suspended or resumed.
How Signals should be used in C program
Signals are defined as integer numbers. Please note these numbers depend on Linux distribution. So, always refer "signum-generic.h" file available.
Figure 2: Signal Number
For example SIGINT is number 2. Signal name are start with SIG, and these characters represent signal description.
Signal name is starting with SIG prefix.
you should include “signal.h” in your project. Do not use “signum-generic.h” directly.
One more point, signals can be standard signal or real time signals. Real time signals can be queued and Real time signals also have priority. We will discuss about Real time signals in another article.
Who can send Signals
Next question may be who can send signals to process. Answer is following …
Figure 3: Signal senders
Other Process – other process can send signal. For this use kill() API is used.
Hardware Exception - In case of hardware failure like failure to access memory, Linux kernel also send signal to process. Example SIGBUS signal is generated to indicate memory access.
Terminal – We can also send signal from terminal. For Example pressing “Control+C” will send
SIGTERM to active process. SIGTERM signal will terminate the process.
Software Events – Software events like timer expiry, child process terminates, will generate a signal.
Signal Mask
Signal can be masked or unmasked. When signal is masked, signal delivery is blocked.
When signal is unmasked, than signal will be delivered immediately. When signal is masked, signal delivery is stopped. There are various system calls that allow a process to add and remove signals from its signal mask set.
Figure 4: Signal Mask
For masking and unmasking of signal, we have to create signal block. Signal block is sigset_t type structure.
Add signals in the block.
sigaddset API is used to add signal in the set.
sigprocmask is used to mask signals present the specified signal block.
LED Toggling and Signal Sending Program
We will have two applications (or process). One will be signal receiver and second will be signal sender.
Figure 5: Signal Sender and Signal Receiver Process
Signal Sender process will send SIGUSR1 signal. Signal Receiver process will receive SIGUSR1 and toggle LED.
Here is the LED connection on Beaglebone Black Board.
Figure 6: LED Connection on Beaglebone Black Board
C Code
Let us review code of Signal Sender Program. We will run signal_sender process as…
./signal_send -s <signal_number> -p <process_id>
Example, if we want to send signal number 10, to a process, whose process id is 1234.
./signal_send -s 10 -p 1234
It is using Kill API to send signal.
Download Source code from Github
Signal Sender Process Code |
Explanation |
int main (int argc, char *argv[]){
int opt=0,signum=0;
pid_t pid;
// parsing command line argument
while ((opt = getopt (argc, argv, "s:p:")) != -1) {
switch(opt){
case 's': signum= atoi(optarg); break;
case 'p': pid= atoi(optarg); break;
default : signum = SIGINT; break;
} // end of switch
} // end of while
// sending signal |
C Code
Let us review code of Signal Sender Program. We will run signal_sender process as… ./signal_send -s <signal_number> -p <process_id>
Example, if we want to send signal number 10, to a process, whose process id is 1234. ./signal_send -s 10 -p 1234
It is using Kill API to send signal.
|
if (kill(pid, signum) == -1)
errExit("kill");
} // end of mai |
Kill system call will send specified signal to specified process.
Signal is SIGUSER1, which is number “10”. |
Signal receiver Process Code
Signal receiver has to register signal handler. For that we have to use sigaction structure. sigempty set API, will unmask all signals. sigaction.sa_sigaction field will get the name of signal handler. And we are going to make the signal set empty, this will unmask all signals. Sigaction API is registering my sig action with my signal. it means when sig user 1 signal is received then the handler function will execute.
Now let us review signal receiver code.
Download Source code from Github
Signal Receiver Process Code |
Explanation |
int main (void) {
struct sigaction sa_my,sa_int; int f=0;
// registering MYSIGNAL
sa_my.sa_flags = SA_SIGINFO;
// signal handler will be called with three arguments
sa_my.sa_sigaction = handler;
sigemptyset(&sa_my.sa_mask); 1
// clearing all signal
// registering signal handler for SIGUSR1
sigaction( SIGUSR1, &sa_my, NULL); 2
// registering SIGINT
sa_int.sa_flags = SA_SIGINFO;
sa_int.sa_sigaction = handler;
sigemptyset(&sa_int.sa_mask);
// registering signal handler
sigaction(SIGINT, &sa_int, NULL) 3 |
We are registering signal handler “hander” for two signal. One is SIGUSR1 and second is SIGINT. Sigaction system call is used to register signal handler with signal. We are calling this two times. 2 to register SIGUSR1 and 3 to register SIGINT.
1 And we are clearing mask field for Sigaction structure. It means we are not masking any signal for this process.
|
// set direction out for GPIO 60
printf("\nSignal Receiver: set direction !!!");
f=open("/sys/class/gpio/gpio60/direction", O_RDWR);
write(f,"out",3); 4
close(f);
f=open("/sys/class/gpio/gpio60/value", O_WRONLY);
while(int_exit ==0 ) 5
// we will be in loop till int_exit is zero
{
pause(); // block until a signal is caught
if(int_sig_received==1)
{
if (led_toggle == 0)
write(f,"0",1); // LED off
else
write(f,"1",1); // LED on;
int_sig_received=0;
} } // end of while
Close(f); } // end of main |
This section of code is for LED toggling.
We are using GPIO60, because LED is connected at GPIO1_28 port
4 First we have to set direction of GPIO 60 to output.
5 Int_exit, variable is going to change in signal handler.
Remaining code is straight forward. Here we are doing LED toggling. |
Signal Handler code |
|
static void handler(int sig, siginfo_t *si, void *uc){
if (sig == SIGUSR1) 6
{
int_sig_received=1;
switch (led_toggle){
case 0: led_toggle =1; break;
case 1: led_toggle =0; break;
default: led_toggle =0;
}
} else if (sig == SIGINT){ 7
int_sig_received=1; int_exit=1; }
else
printf("\n Unknown Signal !!! \n");
} // end of handler function |
Signal handler will be called when the signal is received by signal receiver process.
6 Signal number will be in sig variable.
When signal is SIGINT, then we will terminate the process.
7 in case of SIGINT, we are setting sig_received and int_exit flag to 1.
5 this will break loop in our main program. |
Reference
Signal name and Signal Numbes
SIGUSR1 10
SIGUSR2 12
SIGCHLD 17
SIGSTOP 19
Refer “include/bits/signum.h” and “include/bits/signum-generic.h” file.
List of API
Kill – send signal to process. Usage “int kill(pid_t pid, int sig);”
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
struct sigaction {
__sigaction_handler; /* Signal handler. */
__sigset_t sa_mask; /* Additional set of signals to be blocked. */
int sa_flags; /* Special flags. */
void (*sa_restorer) (void); /* Restore handler. */
};