信号驱动I/O详解

Posted 正在起飞的蜗牛

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了信号驱动I/O详解相关的知识,希望对你有一定的参考价值。

1、Linux中的信号

1.1、查看信号

[centos6-jk128:latest ~]$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

(1)使用"kill -l"查看linux中的全部信号,信号又分为可靠信号和不可靠信号,每个信号更详细的介绍自行查询;
(2)信号驱动I/O中使用的SIGIO信号;

1.2、信号处理方式

(1)忽略:接收到信号后不做任何反应;
(2)捕获:用自定义的信号处理函数来执行相应信号;不是所有信号都可以捕获的,关闭进程的信号就不能捕获;
(3)默认:按系统默认的信号处理方式响应信号,不去显示的指定信号处理方式,就是按默认的方式;

1.3、信号注册

	sighandler_t signal(int signum, sighandler_t handler)

(1)signum:要捕获的信号;
(2)handler:当进程接收到信号时绑定的处理函数;

2、信号驱动I/O

2.1、信号驱动I/O的原理

(1)应用层打开文件并设置好文件的相关标志位;
(2)绑定SIGIO信号处理函数,在信号处理函数中读/写文件;
(3)当驱动中有可读数据时,向相应进程发送SIGIO信号;
(4)进程接收到SIGIO信号后,运行绑定的信号处理函数;
总结:应用层打开文件并绑定信号处理函数,进程并不会阻塞,只有在接收到SIGIO信号时才去执行信号处理函数,属于异步通知;

2.2、应用层实现信号驱动I/O

void func(int signo)

	读文件的操作;


fd = open("/dev/hellodev",O_RDWR);

fcntl(fd,F_SETOWN,getpid());

flage=fcntl(fd,F_GETFL);
fcntl(fd,F_SETFL,flage|FASYNC);

   signal(SIGIO,func);

(1)应用层打开文件得到文件描述符,设置文件的属主进程,属主进程的进程ID号被保存代struct file filep->fowner中,将来内核才知道应该给
哪个进程发SIGIO信号;
(2)设置文件的FASYNC标志,通过fcntl的F_SETFL命令实现,也就是调用文件的file_operations结构体的fasync方法;
(3)绑定进程的SIGIO信号的响应函数;
总结:执行完上面的步骤,当文件在新数据到达时向进程发送一个SIGIO信号,进程就去读文件;

2.3、驱动层使用信号驱动I/O

//这是fasync_helper()函数和kill_fasync()函数需要用到的,照着写就行
struct fasync_struct *hello_fasync;

static struct file_operations hello_ops = 

	.open = hello_open,
	.release = hello_release,
	.read = hello_read,
	.write = hello_write,
	.fasync = hello_fasync_func,
;

int hello_fasync_func (int fd, struct file *filep, int on)

	printk("hello_fasync_func()\\n");
	return fasync_helper(fd, filep, on, &hello_fasync);


static ssize_t hello_write (struct file *filep, const char __user *buf, size_t size, loff_t *pos)

	······
	kill_fasync(&hello_fasync, SIGIO, POLLIN); //给注册的进程发送SIGIO信号
	······
return size;

(1)F_SETOWN被调用时对file->f_owner赋值,此外什么也不做;
(2)在执行F_SETFL启动FASYNC时,调用驱动程序的fasync方法,上面的代码中就是执行hello_fasync_func()函数;
(3)当数据到达时,也就是有其他的进程调用驱动的write函数写数据时,向注册为异步通知的进程发送SIGIO信号;
(4)hello_fasync:这是fasync_helper()函数和kill_fasync()函数需要用到的信息,照着格式写就行;
(5)POLLIN:表示文件数据可读;

以上是关于信号驱动I/O详解的主要内容,如果未能解决你的问题,请参考以下文章

五种IO模型详解

vSocket模型详解及select应用详解

五种网络IO模型-阻塞I/O非阻塞I/OI/O多路复用信号驱动I/O异步I/O

:Linux设备驱动中的异步通知与同步I/O

信号驱动和异步驱动的区别

I/O复用 select和poll