驱动部分
驱动想要给应用层发送信号,需要用到kill_fasync()函数和xxx_fasync()函数
例如:
kill_fasync(&pled->async_queue, SIGRTMIN, POLL_OUT)
//第一个参数为特定的结构体
//第二个参数为信号的类型
//第三个参数为信号值
//作用:驱动通过此函数; 发信号给应用程序,应用程序就调用自己安装的响应函数去处理。
static int kernaldemo_fasync (int fd, struct file *filp, int mode)
{
printk(KERN_EMERG "kernaldemo_fasync\n");
pled = filp->private_data;
return fasync_helper (fd, filp, mode, &pled->async_queue);
}
//fasync_helper作用就是初始化fasync这个东西,包括分配内存和设置属性,
//dev->async_queue可用来区分向谁发
//最后在驱动的release里把fasync_helper初始化的东西free掉。
- 补充1:
在早期的UNIX中信号是不可靠的,不可靠在这里指的是:信号可能丢失,一个信号发生了,但进程却可能一直不知道这一点。现在Linux 在SIGRTMIN实时信号之前的都叫不可靠信号,这里的不可靠主要是不支持信号队列,就是当多个信号发生在进程中的时候(收到信号的速度超过进程处理的速度的时候),这些没来的及处理的信号就会被丢掉,仅仅留下一个信号。可靠信号是多个信号发送到进程的时候(收到信号的速度超过进程处理信号的速度的时候),这些没来的及处理的信号就会排入进程的队列。等进程有机会来处理的时候,依次再处理,信号不丢失。
执行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
- 补充2:
针对SIGRTMIN,一般发送的信号为POLL_IN和POLL_OUT,其他信号可在siginfo.h中的枚举中查到
POLL_IN = 1, /* Data input available. */
# define POLL_IN POLL_IN
POLL_OUT, /* Output buffers available. */
# define POLL_OUT POLL_OUT
POLL_MSG, /* Input message available. */
# define POLL_MSG POLL_MSG
POLL_ERR, /* I/O error. */
# define POLL_ERR POLL_ERR
POLL_PRI, /* High priority input available. */
# define POLL_PRI POLL_PRI
POLL_HUP /* Device disconnected. */
# define POLL_HUP POLL_HUP
应用层部分
应用层部分想要接收到驱动发出的信号,需要用到信号注册函数,信号回调(处理)函数,绑定函数
- 信号注册函数
//第一类
struct sigaction act; //定义信号结构体
memset(&act, 0, sizeof(act)); //清空
sigemptyset(&act.sa_mask); //将参数set信号集初始化并清空。
act.sa_flags = SA_SIGINFO; //设置可用信号结构体携带附加信息
act.sa_sigaction = new_op; //信号处理函数
if(sigaction(SIGRTMIN, &act, NULL) != 0) //信号注册函数
{
perror("sigaction is error");
}
//第二类,不如第一类效果好,一般选用第一类
//SIGIO: 接受的信号
//catch_sigio:信号处理函数
if (SIG_ERR == signal(SIGIO, catch_sigio))
{
perror("signal failed\n");
}
- 绑定函数
fcntl(fd, F_SETSIG, SIGRTMIN); //设置异步通知的信号为SIGRTMIN
fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC);
补充:
函数原型:
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd, struct flock *lock);
描述:
fcntl()针对(文件)描述符提供控制.参数fd是被参数cmd操作(如下面的描述)的描述符.
针对cmd的值,fcntl能够接受第三个参数(arg)
fcntl函数有5种功能:
1.复制一个现有的描述符(cmd=F_DUPFD).
2.获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD).
3.获得/设置文件状态标记(cmd=F_GETFL或F_SETFL).
4.获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN).
5.获得/设置记录锁(cmd=F_GETLK,F_SETLK或F_SETLKW).
cmd 选项:
F_DUPFD 返回一个如下描述的(文件)描述符: (1)最小的大于或等于arg的一个可用的描述符 (2)与原始操作符一样的某对象的引用 (3)如果对象是文件(file)的话,返回一个新的描述符,这个描述符与arg共享相同的偏移量(offset) (4)相同的访问模式(读,写或读/写) (5)相同的文件状态标志(如:两个文件描述符共享相同的状态标志) (6)与新的文件描述符结合在一起的close-on-exec标志被设置成交叉式访问execve(2)的系统调用 F_GETFD 取得与文件描述符fd联合close-on-exec标志,类似FD_CLOEXEC.如果返回值和FD_CLOEXEC进行与运算结果是0的话,文件保持交叉式访问exec(), 否则如果通过exec运行的话,文件将被关闭(arg被忽略) F_SETFD 设置close-on-exec旗标。该旗标以参数arg的FD_CLOEXEC位决定。 F_GETFL 取得fd的文件状态标志,如同下面的描述一样(arg被忽略) F_SETFL 设置给arg描述符状态标志,可以更改的几个标志是:O_APPEND, O_NONBLOCK,O_SYNC和O_ASYNC。 F_GETOWN 取得当前正在接收SIGIO或者SIGURG信号的进程id或进程组id,进程组id返回成负值(arg被忽略) F_SETOWN 设置将接收SIGIO和SIGURG信号的进程id或进程组id,进程组id通过提供负值的arg来说明,否则,arg将被认为是进程id