一,应用程序主动的去查询或 read
。
1.查询方式:很占资源。
2.中断机制:虽然有休眠,但在没有按键按下时 read()
3.poll 机制:指定超时时间。以上都是“应用程序”主动去读或查询。
二,异步通知:
有按键按下了,驱动程序来提醒(触发)“应用程序”去
进程之间发信号:
kill -9 pid
kill 是信号发送者,
pid 具体进程是信号接收者。
信号值是“9”
“信号”与“中断”差不多。注册中断处理函数时是用信号也是有一个“信号”和“处理函数”。
参数是“信号的值”,和要挂接的“信号处理函数”。
程序"signal"一收到这个“Kill”信号时,就会调用里面的“信号处理函数”“my_signal_fun”。
-USR1 与 -10 是一样的。
kill -9 pid:9 这个信号处理函数就是让这个进程退出来。
1,先注册“信号处理函数”。
2,发送信号。
①,谁来发信号。
②,发给谁。
③,怎么发。
三,异步通知功能的驱动程序:
目标:按下按键时,驱动程序会主动通知应用程序
找一个字符驱动查看 kill_fasync 函数的用法。接上面 4 个步骤查看用法,下面找到一个:
1,首先看这个字符设备中定义的一个“fasync_struct”结构的变量:rtc_async_queue。 2,看这个变量的定义,初始化和使用,整个 rtc.c 中有三处出现“rtc_async_queue”:
3,要清楚使用方法就要清楚“rtc_fasync()”在哪里定义:
在这个“rtc.c”中可以找到这个函数的定义,它是一个“file_operatons”结构中的成员。
以上弄清楚“kill_fasync”函数的用法之后,可以依照:
在“中断服务程序”中发:即当有按键按下时就发送一个信号给应用程序。
首先声明一个“fasync_struct”结构变量。
有按键按下了就发一个信号给应用程序。
其中要定义一个结构,取名为“button_async”.
以上便可以发送信号出去了。
发给谁肯定是这个结构中定义的。这个结构“button_async”要做些初始化。
有如下例子,这里的结构体是“rtc_async_queue”,看看这个“fasync_helper”函数是否在初
始化这个结构体。
rtc_fasync函数就是file_operations里的成员函数,需要我们自己实现
所以可以依照这个例子做。在“file_operations 结构中加一个成员。
然后加上这个初始化“button_async”结构的函数“fasync_help”:
这个函数“fifth_drv_fasync”什么情况下调用:
信号是驱动程序发的,在中断服务程序“buttons_irq”通过“kill_fasync (&button_async, SIGIO,
POLL_IN);” 来 发 。 发 给 谁 是 包 含 在 “ button_async ” 这 个 结 构 体 中 。 这 个 结 构 体 在
“fifth_drv_fasync”中由“fasync_helper”来初始化。这个函数“fifth_drv_fasync”什么时候被
调用,是应用程序调用“.fasync”
这么一个“.fasync”系统调用时,就会调用到:fifth_drv_fasync
所以显然是应用程序要调用“.fasync”来设置那个“发给谁”。
为了使设备支持异步通知机制,驱动程序中涉及以下 3 项工作:
- 支持 F_SETOWN 命令,能在这个控制命令处理中设置 filp->f_owner 为对应进程 ID。
不过此项工作已由内核完成,设备驱动无须处理。
- 支持 F_SETFL 命令的处理,每当 FASYNC 标志改变时,驱动程序中的 fasync()函数将得以
执行。
驱动中应该实现 fasync()函数。
- 在设备资源可获得时,调用 kill_fasync()函数激发相应的信号
应用程序:
fcntl(fd, F_SETOWN, getpid()); // 告诉内核,发给谁
应用程序会调用“fcntl()”这个函数,把进程的 PID 号告诉给驱动程序。
应用程序还要通过“F_GETFL”读出“flags”,在 flags 上置上“FASYNC”位。
Oflags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, Oflags | FASYNC); // 改变 fasync 标记,最终会调用到驱动的 faync >
fasync_helper:初始化/释放 fasync_struct
如上面“fcntl(fd, F_SETFL, Oflags | FASYNC);”接口被调用时,下在函数中的“fasync_helper
()”就会被调用:
应用程序会调用“F_SETOWN”即“fcntl(fd, F_SETOWN, pid)”这样一个函数,来进程的 pid 告
诉驱动程序。
然后应用程序还要通过“F_GETFL”读出标志位,即 flags,先读出来再在这个 flags 上面修
改,加上一个“FASYNC”。异步通知的 flags.每当 FAYNC 标志“flags”改变时,驱动程序里
面的
这个函数会被调用。
这个函数也只是用一个“fasync_helper”,这是内核帮做的一个函数。是辅助作用。将结构体
变量“button_async”初始化,我们定义了但没去初始化它,这个内核辅助函数就去初始化它。
这个结构体“button_async”初始化后,中断服务程序“buttons_irq”就能调用:
当应用程序调用这个接口“fcntl(fd, SETFL, oflags | FASYNC)”时,函数“fasync_helper”
就会被调用。
驱动程序对“F_SETOWN”的处理是由内核完成的。
这是驱动测试程序。它不会主动去读按键值“read(fd, &key_val, 1); ”。这个“my_signal_fun”信号函数是在驱动服务程序“buttons_irq”里,发现有按键按下时,给应用程序发“kill_fasync
(&button_async, SIGIO, POLL_IN);”信号,这个信号会触发应用程序来调用它的信号处理函数“my_signal_fun”。