Linux中的信号:由内核发送给应用程序
处理方式:
忽略:
接收到信号后不做任何反应
捕获:
用自定义的信号处理函数来执行特定的动作(注册响应函数)
默认:
接收到信号后按系统默认的行为处理该信号,如Ctrl+C。
捕获函数signal()
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
给signum这个信号注册一个处理函数。
信号驱动IO工作过程
- 应用程序调用 sigaction或者signal(系统调用);内核在调用之后立刻返回一个结果,但是内核本身会阻塞等待数据;应用程序正常进行。两者是异步的。
- 内核层收集(准备好)数据,给用户层递交一个SIGIO信号; 用户层触发信号处理程序,去执行处理函数,在处理函数中 使用系统调 用去内核读取数据。
- 用户层通过系统调用去内核中拷贝数据,该过程中用户层是阻塞的;直到拷贝结束内核通知任务完成。
- 简单来说就是用户层给内核一个任务,你去接受数据,等有数据了内核通知我,我再去去取数据。
Fasync方法
内核能够接受用户层的信号注册函数需要支持Fasync方法,于file_operations里定义。
struct file_operations {
......
int (*fasync) (int, struct file *, int);
......
}
实际使用实例
fasync_helper(int fd, struct file * filp, int on, struct fasync_struct * * fapp);
struct fasync_struct {
spinlock_t fa_lock;
int magic;
int fa_fd;
struct fasync_struct *fa_next; /* singly linked list */
struct file *fa_file;
struct rcu_head fa_rcu;
};
fasync_helper:该函数负责启动fasync队列等,说白了就是初始化的必须;
fasync_struct:它的作用就是储存内容的列表,在初始化和发出信号时候使用;函数会自动申请内存并赋值给hello_fasync,所以不需要对hello_fasync进行定义。
实例使用
main:
void func(int signo)
{
printf("signo= %d\n",signo);
read(fd,buff,sizeof(buff));
printf("buff=%s\n",buff);
return ;
}
main:
int flage;
fcntl(fd,F_SETOWN,getpid());
flage=fcntl(fd,F_GETFL);
fcntl(fd,F_SETFL,flage|FASYNC);
signal(SIGIO,func);
1、一般默认情况下同步是不开的,需要通过fcntl设置fd的性质;
2、给信号SIGIO注册处理函数。
驱动:
static struct file_operations hello_ops =
{
.open = hello_open,
.release = hello_release,
.read = hello_read,
.write = hello_write,
.fasync = hello_fsync_func;
};
int hello_fsync_func (int fd, struct file *filep, int on)
{
printk("hello_fsync_func()\n");
return fasync_helper(fd, filep, int, on, &hello_fasync);
}
发生信号(由内核发出地)
kill_fasync(struct fasync_struct * * fp, int sig, int band);
内核数据准备好后给用户层发信号。
int sig:内核发送信号的是啥;int band:分为POLLIN/POLLOUT,表示可读可写。
使用实例
驱动:
static ssize_t hello_write (struct file *filep, const char __user *buf, size_t size, loff_t *pos)
{
int error;
if(size > KMAX_LEN)
{
size = KMAX_LEN;
}
memset(kbuf,0,sizeof(kbuf));
if(copy_from_user(kbuf, buf, size))
{
error = -EFAULT;
return error;
}
printk("%s\n",kbuf);
// 当内核中有数据就可以给应用程序发送信号
kill_fasync(&hello_fasync, SIGIO, POLLIN);
return size;
}
kill_fasync负责给应用程序发送信号。