Linux driver development study notes [10]: Linux asynchronous notification

table of Contents

1. Signal

Second, the connection and difference between synchronous IO, asynchronous IO, blocking IO, and non-blocking IO

Three, the realization process

1. Application

2. Driver


1. Signal

Let’s review the "interrupt" first. Interrupt is an asynchronous mechanism provided by the processor. After we configure the interrupt, we can let the processor handle other things. When the interrupt occurs, it will trigger the interrupt service function we set in advance. , Do specific processing in the interrupt service function. After the interrupt is used, the processor does not need to check whether the button is pressed at all times, because the interrupt will be automatically triggered after the button is pressed.

Similarly, Linux applications can access the drive device in two ways: blocking or non-blocking

  1. In blocking mode, the application will be in a dormant state, waiting for the drive device to be available for use
  2. In non-blocking mode, it will continuously poll through the poll function to check whether the drive device file can be used

The signal is similar to the "interrupt" used on our hardware, but the signal is at the software level. It can be regarded as a simulation of interruption at the software level. The driver can report that it is accessible by actively sending a signal to the application program. After the application program obtains the signal, it can read or write data from the drive device . The whole process is equivalent to that the application program receives an interrupt sent by the driver, and then the application program responds to the interrupt. During the entire process, the application program does not query whether the drive device is accessible, everything is told by the drive device itself For the application.

The core of asynchronous notification is the signal. All the signals supported by Linux are defined in the arch/xtensa/include/uapi/asm/signal.h file. These signals are as follows:

#define SIGHUP		 1
#define SIGINT		 2
#define SIGQUIT		 3
#define SIGILL		 4
#define SIGTRAP		 5
#define SIGABRT		 6
#define SIGIOT		 6
#define SIGBUS		 7
#define SIGFPE		 8
#define SIGKILL		 9
#define SIGUSR1		10
#define SIGSEGV		11
#define SIGUSR2		12
#define SIGPIPE		13
#define SIGALRM		14
#define SIGTERM		15
#define SIGSTKFLT	16
#define SIGCHLD		17
#define SIGCONT		18
#define SIGSTOP		19
#define SIGTSTP		20
#define SIGTTIN		21
#define SIGTTOU		22
#define SIGURG		23
#define SIGXCPU		24
#define SIGXFSZ		25
#define SIGVTALRM	26
#define SIGPROF		27
#define SIGWINCH	28
#define SIGIO		29
#define SIGPOLL		SIGIO
/*
#define SIGLOST		29
*/
#define SIGPWR		30
#define SIGSYS		31
#define	SIGUNUSED	31

/* These should not be considered constants from userland.  */
#define SIGRTMIN	32
#define SIGRTMAX	_NSIG

#define SIGSWI		32

Second, the connection and difference between synchronous IO, asynchronous IO, blocking IO, and non-blocking IO

https://www.cnblogs.com/euphie/p/6376508.html

Three, the realization process

Complete driver source code: https://github.com/denghengli/linux_driver/tree/master/17_fasync

1. Application

To use asynchronous notification in your application, you need to add content:

(1) Register new number processing function

(2) Tell the kernel the process number of this application

(3) Turn on asynchronous notification

static void sigio_signal_func(int signum)
{
    ...
}
/*
*argc 应用程序参数个数
*argv 具体的参数内容,字符串形式
*/
int main(int argc, char *argv[]) 
{
    ...
    signal(SIGIO, sigio_signal_func);/*设置sigio的处理函数*/
    /*int fcntl (int __fd, int __cmd, ...);*/
    fcntl(fd, F_SETOWN, getpid());/*设置当前进程接收SIGIO信号*/
    flags = fcntl(fd, F_GETFL);/*获取当前文件标志*/
    fcntl(fd, F_SETFL, flags | FASYNC);/*设置当前文件标志,开启异步通知*/
    ...
    return 0;
}

2. Driver

(1) When the device is accessible, the driver needs to send a signal to the application through the kill_fasync function, which is equivalent to generating an "interrupt"

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

fp : The fasync_struct to be operated.

sig the signal to be sent.

Set to POLL_IN when the band is readable, and set to POLL_OUT when it can be written.

Return value : None.

(2) Write the fasync function. When the application changes the fasync flag through fcntl(fd, F_SETFL, flags | FASYNC) , the fasync function in the file_operations operation set of the driver will be executed, and the fasync control structure needs to be initialized in this function

/* key设备结构体 */
struct key_dev{
    ...
	/*异步结构体 --- 异步通知*/
	struct fasync_struct *fasync_queue;
};

/*定时器回调函数*/
static void timer_func(unsigned long arg)
{
    struct key_dev *dev = (struct key_dev*)arg;
    ...
    if (dev->fasync_queue){	/*有效的按键过程,相应层发送信号实现异步通知*/
            /*SIFIO为发送的信号,POLL_IO表示可读,POLL_OUT表示可写*/
            kill_fasync(&dev->fasync_queue, SIGIO, POLL_IN);
        }
	}
}

static int key_release(struct inode *inode, struct file *filp)
{
	int i = 0;
	struct key_dev *dev = filp->private_data;
    ...
	/*删除fasync结构体*/
	return fasync_helper(-1, filp, 0, &dev->fasync_queue);
}

static int key_fasync(int fd, struct file *filp, int on)
{
	struct key_dev *dev = filp->private_data;

	/*初始化fasync结构体*/
	return fasync_helper(fd, filp, on, &dev->fasync_queue);
}

/* 设备操作函数 */
static struct file_operations key_fops = {
    ...
	.fasync = key_fasync,
};

 

 

Guess you like

Origin blog.csdn.net/m0_37845735/article/details/107307462