Linux驱动开发学习笔记【10】:Linux异步通知

目录

一、信号

二、同步IO、异步IO、阻塞IO、非阻塞IO之间的联系与区别

三、实现过程

1、应用程序

2、驱动程序


一、信号

先来回顾一下“中断”,中断是处理器提供的一种异步机制,我们配置好中断以后就可以让处理器去处理其他的事情了,当中断发生以后会触发我们事先设置好的中断服务函数,在中断服务函数中做具体的处理。采用中断以后处理器就不需要时刻的去查看按键有没有被按下,因为按键按下以后会自动触发中断。

同样的, Linux应用程序可以通过阻塞或者非阻塞这两种方式来访问驱动设备

  1. 阻塞方式访问的话应用程序会处于休眠态,等待驱动设备可以使用
  2. 非阻塞方式的话会通过 poll函数来不断的轮询,查看驱动设备文件是否可以使用

信号类似于我们硬件上使用的“中断”,只不过信号是软件层次上的。算是在软件层次上对中断的一种模拟,驱动可以通过主动向应用程序发送信号的方式来报告自己可以访问了, 应用程序获取到信号以后就可以从驱动设备中读取或者写入数据了。整个过程就相当于应用程序收到了驱动发送过来了的一个中断,然后应用程序去响应这个中断,在整个处理过程中应用程序并没有去查询驱动设备是否可以访问,一切都是由驱动设备自己告诉给应用程序的。

异步通知的核心就是信号,在 arch/xtensa/include/uapi/asm/signal.h文件中定义了Linux所支持的所有信号,这些信号如下所示:

#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

二、同步IO、异步IO、阻塞IO、非阻塞IO之间的联系与区别

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

三、实现过程

完整的驱动程序源码:https://github.com/denghengli/linux_driver/tree/master/17_fasync

1、应用程序

在应用程序中要使用异步通知,需要添加内容:

(1)注册新号处理函数

(2)将本应用程序的进程号告诉内核

(3)开启异步通知

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、驱动程序

(1)当设备可以访问的时候,驱动程序需要通过 kill_fasync 函数向应用程序发出信号,相当于产生“中断”

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

fp:要操作的 fasync_struct。

sig 要发送的信号。

band 可读时设置为 POLL_IN,可写时设置为 POLL_OUT。

返回值:无。

(2)编写fasync函数,当应用程序通过 fcntl(fd, F_SETFL, flags | FASYNC) 改变fasync标记的时候,驱动程序 file_operations操作集中的 fasync 函数就会执行,需要在该函数中初始化 fasync 控制结构体

/* 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,
};

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值