Interprocess Communication Based on Linux Programming Part 3: Signals

Overview of Signals

Signals are one of the oldest methods of process communication used in UNIX. It is a simulation of interruption mechanism at the software level and an asynchronous communication mode. Signals can interact directly between user-space processes and kernel processes. Kernel processes can also use them to notify user-space processes of what system events have occurred. It can be sent to a process at any time without knowing the state of the process. If the process is not currently in execution, the signal is saved by the kernel until the process resumes execution and is relayed to it; if a signal is set to be blocked by the process, the transmission of the signal is delayed until its blocking is cancelled.

A complete signal life cycle can be divided into three important stages, which are described by four important events: signal generation, signal registration in the process, signal cancellation in the process, and signal processing function execution.


User processes respond to signals in three ways:

  • Ignore the signal, that is, do not do any signal processing, but there are two signals can not be ignored, namely SIGKILL and SIGSTOP.
  • Capture the signal, define the signal processing function, and execute the corresponding custom processing function when the signal occurs.
  • Perform default operations, and Linux specifies default operations for each signal.
Most of the linux signals are provided by the kernel. The meanings and default operations of common signals are listed below.



2. Signal Processing

There are two main methods of signal processing, one is to use simple signal() function, the other is to use signal set function group. The following two methods are introduced separately.

1. Use signal() function

When signal() function is used to process, only the signal and processing function to be processed need to be pointed out. It is mainly used for processing the first 32 kinds of non-real-time signals, and does not support signal transmission. However, it is also welcomed by many programmers because of its simple use and easy to understand. Linux also supports a more robust and updated signal processing function sigaction(), which is recommended.

Function format:

void (*signal(int signum, void (*handler)(int)))(int)
signum: Specify the signal code

handler: Signal processing functions, which can be SIG_IGN, SIG_DFL, user-defined

2. Use sigaction() function

Function format:

int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)
signum: Signal code that can be used for any specific valid signal other than SIGKILL and SIGSTOP

act: A pointer to an instance of structured sigaction that specifies the processing of a particular signal

Old act: Save the original processing of the corresponding signal

Return value: 0 successful, other return error code

III. Testing

The signal processing implemented by the above two methods is tested. Their functions are the same. A signal processing function is written to capture the SIGINT signal (Ctrl + C) input by the user.

1. Use signal() function

The complete test code is as follows:

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

/* Customized Signal Processing Function */
void my_signal_func(int signum)
{
	if(signum == SIGINT)
	{
		printf("Captured the signal is SIGINT!\n");
	}
	else
	{
		printf("Cptured error!\n");
	}
}

/*
 *	Function: Capture SIGINT signal
 */
int main(void)
{
	printf("Capture SIGINT signal!\n");

	/* Capture the corresponding signal */
	signal(SIGINT, my_signal_func);

	/* wait a signal */
	pause();

	return 0;
}
Compile and run, the results are as follows:


2. Use sigaction() function

The complete code is as follows:

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

#if 0
struct sigaction {
   void     (*sa_handler)(int);
   void     (*sa_sigaction)(int, siginfo_t *, void *);
   sigset_t   sa_mask;
   int        sa_flags;
   void     (*sa_restorer)(void);
};
#endif

/* Signal Processing Function */
static void my_signal_func(int signum)
{
	if(signum == SIGINT)
	{
		printf("Captured the signal SIGINT!\n");
	}
	else
	{
		printf("Captured error!\n");
	}
}

/*
 *	Function: Capture signal SIGINT
 */
int main(void)
{
	int ret;
	struct sigaction my_sigaction;

	printf("Capture the siganl SIGINT!\n");

	/* Setting my_sigaction structure */
	my_sigaction.sa_handler = my_signal_func;
	sigemptyset(&my_sigaction.sa_mask);
	my_sigaction.sa_flags = 0;

	/* Binding the corresponding signal to the signal processing function */
	ret = sigaction(SIGINT, &my_sigaction, 0);

	pause();	// wait for signal
	
	return 0;
}
Compile and run the results as follows:



Keywords: Linux Unix

Added by sbacelic on Tue, 02 Jul 2019 01:29:22 +0300