A signal,

1. Basic concepts

Signal is a simulation of the interrupt mechanism at the software level. In principle, a signal received by a process is the same as an interrupt request received by a processor. Signals are asynchronous; a process does not have to do anything to wait for a signal to arrive. In fact, the process does not know exactly when the signal will arrive.

For example, the keystroke interrupt key (^C), which occurs unpredictably during program execution.

Signals are the only asynchronous communication mechanism in the interprocess communication mechanism and can be considered as asynchronous notification, notifying the receiving process of what has happened.

Hardware exceptions can also signal, such as division by zero or invalid memory references (as in test). These conditions are usually detected by the kernel hardware and then notified to the kernel. The kernel decides what signal to generate.

Additional occurrences of the same signal are not usually queued. If the signal is blocked five times, the signal handler is usually called only once when we unblock the signal.

Only one signal can be processed at a time, and that signal is pending when the signal handler sends a signal to itself.

The smaller the signal value, the higher the priority. When a process receives more than one signal to be processed, it always processes the signal with a higher priority first.

The stack of signal handlers can be either interrupted or independent, which can be set by system call.

The signal mechanism has been extended by POSIX in real time to be more powerful, delivering additional information in addition to basic notification.

2. Handling methods

Ignore: Do nothing after receiving a signal. Capture: Use custom signal handlers to perform specific actions. Default: After receiving a signal, the system processes the signal according to the default behavior. This is how most apps handle it.

Signal types under Linux

Using kill -l displays a list of signals supported by Linux.

In the list, signals numbered from 1 to 31 are supported by traditional UNIX and are unreliable signals (non-real-time signals). Signals numbered from 32 to 63 are later extended and are called reliable signals (real-time signals). The difference between unreliable and reliable signals is that the former does not support queuing and may cause signal loss, while the latter does not.

Below we discuss signals whose numbers are less than SIGRTMIN (the numbers below correspond in turn to signals whose values are 1-31).

1) SIGHUP

This signal is sent when the user terminal connection (normal or abnormal) has ended, usually when the terminal’s control process has ended, to inform individual jobs in the same session that they are no longer associated with the control terminal.

When you log in to Linux, the system assigns a terminal (Session) to the user. All programs running on this terminal, including foreground and background process groups, generally belong to this Session. When the user logs out of Linux, the foreground process group and the background processes that have output to the terminal will receive the SIGHUP signal. The default action of this signal is to terminate the process, so the foreground process group and processes with terminal output in the background are aborted. However, it is possible to catch this signal, for example wget can catch the SIGHUP signal and ignore it so that wGET can continue downloading even after logging out of Linux.

In addition, this signal is used to tell a daemon that is disconnected from the terminal to re-read the configuration file.

2) SIGINT

An interrupt signal emitted when the user types an INTR character (usually Ctrl-C) to tell the foreground process group to terminate the process.

3) SIGQUIT

Similar to SIGINT, but controlled by the QUIT character (usually Ctrl-). A core file is generated when a process exits due to SIGQUIT, which is similar to a program error signal in this sense.

4) SIGILL

Illegal instructions were executed. This is usually due to an error in the executable itself or an attempt to execute a data segment. This signal can also be generated when the stack overflows.

5) SIGTRAP

Generated by a breakpoint instruction or other trap instruction. Used by the debugger.

6) SIGABRT

The signal generated by calling abort.

7) SIGBUS

Invalid addresses, including memory address alignment errors. Such as accessing a four-word integer whose address is not a multiple of 4. It differs from SIGSEGV in that the latter is triggered by illegal access to a valid storage address (such as access to a non-own storage space or read-only storage space).

8) SIGFPE

Emitted when a fatal arithmetic error occurs. This includes not only floating-point errors, but also overflow and all other arithmetic errors such as divisor zero.

9) SIGKILL

Used to terminate the program immediately. This signal cannot be blocked, processed, or ignored. If the administrator finds that a process cannot be terminated, you can attempt to send this signal.

10) SIGUSR1

Leave it to the user

11) SIGSEGV

An attempt to access unallocated memory or to write data to a memory address that does not have write permission.

Signal 11 indicates that there may be illegal memory access in the program under certain conditions.

12) SIGUSR2

Leave it to the user

13) SIGPIPE

Pipe burst. This signal is usually generated in interprocess communication, such as when two processes communicate using FIFO(pipe). If the reading pipe is not opened or terminates unexpectedly, the writing process receives the SIGPIPE signal. In addition, for the two processes that use the Socket to communicate, the writing process terminates while writing the Socket.

14) SIGALRM

Clock timing signal that calculates the actual time or clock time. this signal is used by the alarm function.

15) SIGTERM

Terminate signals, which, unlike SIGKILL, can be blocked and processed. The shell command kill produces this signal by default. We only try SIGKILL if the process cannot be terminated.

17) SIGCHLD

The parent receives this signal when the child terminates.

If the parent process does not process the signal and does not wait for the child process, the child process is called a zombie if it terminates but still holds entries in the kernel process table. This situation should be avoided (the parent either ignores SIGCHILD, catches it, waits for its derived child, or terminates first, in which case the init process automatically takes over).

18) SIGCONT

To make a process continue when it has stopped. This signal cannot be blocked. A handler can be used to make a program do specific work when the stopped state changes to continue. For example, redisplay the prompt

19) SIGSTOP

Stopped the execution of the process. Notice the difference between this and terminate and interrupt: the process is not finished; it is just paused. This signal cannot be blocked, processed, or ignored.

20) SIGTSTP

Stops the process, but the signal can be processed and ignored. This signal is emitted when the user types SUSP characters (usually Ctrl-Z)

21) SIGTTIN

When a background job reads data from a user terminal, all processes in the job receive a SIGTTIN signal. These processes are stopped by default.

22) SIGTTOU

Similar to SIGTTIN, but received when writing a terminal (or modifying terminal mode).

23) SIGURG

Generated when “urgent” data or out-of-band data reaches the socket.

24) SIGXCPU

CPU time resource limit exceeded. This limit can be read/changed by getrLimit/setrLimit.

25) SIGXFSZ

When a process attempts to expand a file to exceed the file size resource limit.

26) SIGVTALRM

A virtual clock signal, similar to SIGALRM but counting the CPU time used by the process.

27) SIGPROF

Similar to SIGALRM/SIGVTALRM, but including the CPU time used by the process and the system call time.

28) SIGWINCH

Emitted when the window size changes.

29) SIGIO

The file descriptor is ready to begin input/output operations.

30) SIGPWR

Power failure

31) SIGSYS

Invalid system call.

3. Signal behavior description

The default behavior and description of the main signals are listed below:

The name of the digital standard The default behavior instructions
SIGILL 4 ANSI Stop + coredump Illegal instructions were executed. This is usually due to an error in the executable itself or an attempt to execute a data segment. This signal can also be generated when the stack overflows
SIGABRT 6 ANSI Stop + coredump The signal generated by calling abort
SIGBUS 7 4.2 BSD Stop + coredump Invalid addresses, including memory address alignment errors. Such as accessing a four-word integer whose address is not a multiple of 4. It differs from SIGSEGV in that the latter is triggered by illegal access to a valid storage address (such as access to a non-own storage space or read-only storage space)
SIGFPE 8 ANSI Stop + coredump Emitted when a fatal arithmetic error occurs. This includes not only floating-point errors, but also overflow and all other arithmetic errors such as divisor zero
SIGSEGV 11 ANSI Stop + coredump An attempt to access unallocated memory or to write data to a memory address that does not have write permission. Access to null Pointers, wild Pointers almost all produce this signal, is the most common signal
SIGSTKFLT 16 N/A Termination of Stack errors
SIGPIPE 13 POSIX Termination of Pipe burst. This signal is usually generated in interprocess communication, such as when two processes communicate using FIFO(pipe). If the reading pipe is not opened or terminates unexpectedly, the writing process receives the SIGPIPE signal. In addition, for the two processes that use the Socket to communicate, the writing process terminates while writing the Socket
SIGTRAP 5 POSIX Stop + coredump Generated by a breakpoint instruction or other trap instruction. Used by the debugger
SIGHUP 1 POSIX Termination of Issued when a user terminal connection (normal or abnormal) terminates, usually when the terminal’s control process terminates, to notify individual jobs in the same session that are no longer associated with the control terminal
SIGINT 2 ANSI Termination of An interrupt signal emitted when the user types an INTR character (usually Ctrl-C) to tell the foreground process group to terminate the process
SIGQUIT 3 POSIX Stop + coredump Similar to SIGINT, but controlled by the QUIT character (usually Ctrl-). A core file is generated when a process exits due to SIGQUIT, which is similar to a program error signal in this sense
SIGKILL 9 POSIX Termination of Used to terminate the program immediately. This signal cannot be blocked, captured, or ignored. If the administrator finds that a process cannot be terminated, you can attempt to send this signal
SIGCHLD 17 POSIX ignore The parent receives this signal when the child terminates. If the parent process does not process the signal and does not wait for the child process, the child process is called a zombie if it terminates but still holds entries in the kernel process table. This situation should be avoided (the parent either ignores SIGCHILD, catches it, waits for its derived child, or terminates first, in which case the child’s termination is automatically taken over by the init process).
SIGCONT 18 POSIX Continue/ignore To make a process continue when it has stopped. This signal cannot be blocked. A handler can be used to make a program do specific work when the stopped state changes to continue. For example, redisplay the prompt.. Continue when the process is suspended, otherwise ignore
SIGSTOP 19 POSIX suspended Suspends the execution of the process. Notice the difference between this and terminate and interrupt: the process is not finished; it is just paused. This signal cannot be blocked, captured, or ignored
SIGALRM 14 POSIX Termination of Clock timing signal that calculates the actual time or clock time. this signal is used by the alarm function

4. Signal classification

Among the signals listed above, the program may not catch, block, or ignore:

SIGKILL,SIGSTOP 
Copy the code

The following signals cannot be restored to the default action:

SIGILL,SIGTRAP 
Copy the code

The default message that causes the process to abort is:

SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGIOT,SIGQUIT,SIGSEGV,SIGTRAP,SIGXCPU,SIGXFSZ 
Copy the code

The default signals that cause a process to exit are:

SIGALRM,SIGHUP,SIGINT,SIGKILL,SIGPIPE,SIGPOLL,SIGPROF,SIGSYS,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM 
Copy the code

The default signals that cause a process to stop are:

SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU 
Copy the code

Signals ignored by the default process are:

SIGCHLD,SIGPWR,SIGURG,SIGWINCH
Copy the code

In addition, SIGIO is quit in SVR4 and ignored in 4.3bSD;

SIGCONT continues when the process is suspended, otherwise ignored, and cannot be blocked

When terminating a program, you should not use SIGKILL if you have to, because SIGKILL does not process the child process, only itself.

5. Signal driven IO-SIGIO-29

Now we will focus on the use of SIGIO-29.

Refer to the picture above:

  • Time 1 through the sigAction system call to establish signal SIGIO signal processing function, the function can immediately return, note, the corresponding driver must support method. Fastnc
  • At time 2, if the data is not ready, the process will continue to execute, and the kernel will continue to wait for data. In other words, the application process is not blocked while waiting for data.
  • When the kernel is ready to copy the data to the application process, the SIGIO signal is submitted to the application program through function kill_fasync (). The signal handler of the second application program will be called. In this function, we can assign the program from the kernel to the process through system calls such as read
  • Time 4 During data assignment, the process is blocked
  • At time 5 data replication is complete, a success indicator is returned, and the application can continue processing the data

The CPU utilization of signal-driven I/O is high because, in the figure, the application can continue to perform other operations while waiting for data 2.

Six, program implementation

Signal ();

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
Copy the code

Function:

Sighandler_t (sighandler_t)(sighandler_t)(sighandler_t)(sighandler_t)(sighandler_tCopy the code

Parameters:

intSignum signal valuesighandler_tHandler Indicates the signal processing functionCopy the code

2. Kernel functions

void kill_fasync(struct fasync_struct **fp, int sig, int band)
Copy the code

Function:

A signal sig is sent to the process to inform it whether the process is readable or writable. POLLIN: readable POLLOUT: writableCopy the code

General character device. Fasync method, generally is a fixed notation, we can temporarily not care about his principle, can use, specific notation is as follows:

static ssize_t hello_write (struct file *filep, const char __user *buf, size_t size, loff_t *pos)
{
	interror; ..................... kill_fasync(&hello_fasync,SIGIO,POLLIN);return size;
}

static struct file_operations hello_ops ={..................... .fasync = hello_fasync_func, };Copy the code

2. The source program

Driver: hello.c

/* * public number: Linux *2021.6.21 *version: 1.0.0 */
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/poll.h> 
#include<asm/signal.h>

static int major = 237;
static int minor = 0;
static dev_t devno;
static struct cdev cdev;
struct device *class_dev = NULL;
struct class *cls;

struct fasync_struct *hello_fasync;

static int hello_open (struct inode *inode, struct file *filep)
{
	printk("hello_open()\n");
	return 0;
}
static int hello_release (struct inode *inode, struct file *filep)
{
	printk("hello_release()\n");

	return 0;
}

#define KMAX_LEN 32
char kbuf[KMAX_LEN+1] = "kernel";


//read(fd,buff,40);

static ssize_t hello_read (struct file *filep, char __user *buf, size_t size, loff_t *pos)
{
	int error;

	
	if(size > strlen(kbuf))
	{
		size = strlen(kbuf);
	}

	if(copy_to_user(buf,kbuf, size))
	{
		error = -EFAULT;
		return error;
	}

	return size;
}
//write(fd,buff,40);
static ssize_t hello_write (struct file *filep, const char __user *buf, size_t size, loff_t *pos)
{
	int error;

	if(size > KMAX_LEN)
	{
		size = KMAX_LEN;
	}
	memset(kbuf,0.sizeof(kbuf));
	if(copy_from_user(kbuf, buf, size))
	{
		error = -EFAULT;
		return error;
	}
	printk("%s\n",kbuf);
	kill_fasync(&hello_fasync,SIGIO,POLLIN);
	return size;
}

int hello_fasync_func(int fd,struct file* filep,int on)
{
	printk("led_fasync \n");
	return fasync_helper(fd,filep,on,&hello_fasync);
}

static struct file_operations hello_ops = 
{
	.open = hello_open,
	.release = hello_release,
	.read = hello_read,
	.write = hello_write,
	.fasync = hello_fasync_func,
};
static int hello_init(void)
{
	int result;
	int error;
	
	printk("hello_init \n");
	result = register_chrdev( major, "hello", &hello_ops);
	if(result < 0)
	{
		printk("register_chrdev fail \n");
		return result;
	}
	cls = class_create(THIS_MODULE, "hellocls");
	if (IS_ERR(cls)) {
		printk(KERN_ERR "class_create() failed for cls\n");
		result = PTR_ERR(cls);
		goto out_err_1;
	}
	devno = MKDEV(major, minor);
	
	class_dev = device_create(cls, NULL, devno, NULL."hellodev");
	if (IS_ERR(class_dev)) {
		result = PTR_ERR(class_dev);
		goto out_err_2;
	}
	
	return 0;

out_err_2:
	class_destroy(cls);
out_err_1:
	unregister_chrdev(major,"hello");
	return 	result;
}
static void hello_exit(void)
{
	printk("hello_exit \n");
	device_destroy(cls, devno);
	class_destroy(cls);
	unregister_chrdev(major,"hello");
	return;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
//proc/devices
Copy the code

write.c

/* * Sip Linux *2021.6.21 *version: 1.0.0 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
main()
{
	int fd;
	int len;
	char buf[64] = {0};
	char buf2[64+1] ="peng";
	
	
	fd = open("/dev/hellodev",O_RDWR);
	if(fd<0)
	{
		perror("open fail \n");
		return;
	}

	
	printf("before write\n");
	len = write(fd,buf2,strlen(buf2));
	printf("after write\n");

	printf("len = %d\n",len);
	
	 
	close(fd);
}

Copy the code

test.c

/* * public number: Linux *2021.6.21 *version: 1.0.0 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<signal.h>

char buff[64] = {0};
int fd;

void func(int signo)
{
	printf("signo= %d\n",signo);
	read(fd,buff,sizeof(buff));
	printf("buff=%s\n",buff);
	return ;
}

main()
{
	int flage;

	fd = open("/dev/hellodev",O_RDWR);
	if(fd<0)
	{
		perror("open fail \n");
		return;
	}
	fcntl(fd,F_SETOWN,getpid());
	flage=fcntl(fd,F_GETFL);
	fcntl(fd,F_SETFL,flage|FASYNC);
    signal(SIGIO,func);
	while(1); 
	close(fd);
}
Copy the code

3. Execution result

compile

make
gcc test.c -o run
gcc write.c -o run
Copy the code

Perform:

insmod hello.ko
Copy the code

Start a terminal and run

./run
Copy the code

Start another terminal and run

./w
Copy the code

The result is as follows:

As you can see, after writing the data, the signal handler is called and prints out the value of the signal, 29, while reading the data from the driver.

This example is based on the character device to achieve, detailed principle, please refer to the blogger other articles.

Linux Driver Series

Complete code and execution environment, please pay attention to, a jun number, background reply: Ubuntu B station also have synchronous video,

Blog.csdn.net/daocaokafei…