poll和一步通讯
poll的模型核心代码如下所示:
FD_ZERO(fd_set *set)//清除一个文件描述符集;
FD_SET(int fd,fd_set *set)//将文件描述符fd加入文件描述符集中;
FD_CLR(int fd,fd_set *set)//将文件描述符fd从文件描述符集中清除;
FD_ISSET(int fd,fd_set *set)//判断文件描述符fd是否被置位。
例1.7poll接口驱动程序示例
代码见光盘\src\1drivermodel\1-7poll。核心代码如下所示:
ssize_t simple_read(struct file *filp, char __user *buf, size_t count,loff_t *f_pos)
{
//printk("wait_event_interruptible before\n");
wait_event_interruptible(read_queue, simple_flag);
//printk("wait_event_interruptible after\n");
if (copy_to_user(buf,demoBuffer,count))
{
count=-EFAULT;
}
return count;
}
ssize_t simple_write(struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)
{
if (copy_from_user(demoBuffer, buf, count))
{
count = -EFAULT;
goto out;
}
simple_flag=1;
wake_up(&read_queue);
out:
return count;
}
//poll接口实现
unsigned int simple_poll(struct file * file, poll_table * pt)
{
unsigned int mask = POLLIN | POLLRDNORM;
poll_wait(file, &read_queue, pt);
return mask;
}
struct file_operations simple_fops = {
.owner = THIS_MODULE,
.poll = simple_poll,
.read = simple_read,
.write= simple_write,
.open = simple_open,
.release =simple_release,
};
应用程序参考代码如下:
int fd;
void *readthread(void *arg)//读数据线程
{
char data;
fd_set rfds; //读描述符集合
fd_set wfds; //写描述符集合
int retval=0;
while(1)
{
FD_ZERO(&rfds);
FD_SET(fd, &rfds);
select(fd+1, &rfds, &wfds, NULL, NULL); //多路选择
if(FD_ISSET(fd, &rfds))
{
retval=read(fd,data,3);
if(retval==-1)
{
perror("read error\n");
exit(-1);
}
data=0;
printf("read successfully:%s\n",data);
}
}
return (void *)0;
}
void main()
{
int i;
int retval;
fd=open("/dev/fgj",O_RDWR);
if(fd==-1)
{
perror("error open\n");
exit(-1);
}
printf("open /dev/fgj successfully\n");
pthread_t tid;
pthread_create(&tid, NULL, readthread, NULL);//创建读线程
while(1)
{
retval=write(fd,"fgj",3);//主线程负责写数据
if(retval==-1)
{
perror("write error\n");
exit(-1);
}
}
close(fd);
}
本例运行结果如下:
# insmod demo.ko
# mknod /dev/fgj c 224 0
# ./test
read successfully:fgj
read successfully:fgj
read successfully:fgj
read successfully:fgj
...
异步通知
驱动程序与应用程序不能直接通信,如果设备已经准备好数据,可以采用异步通知的方式通知应用层来读取,这样应用程序就不需要一直查询设备的状态。要支持异步通知,需要实现设备驱动程序的fasync接口。当一个打开的文件的FASYNC标志变化时file_operations ->fasync()接口将被调用。file_operations ->fasync函数会调用fasync_helper从相关的进程列表中添加或去除异步通知关联。
int fasync_helper(int fd, struct file *filp, int mode, struct fasync_struct **fa);
当数据到达时 kill_fasync函数将被用来通知相关的进程:
void kill_fasync(struct fasync_struct **fa, int sig, int band);
例1.8异步通知实例
代码见光盘\src\1drivermodel\1-8fasync。驱动层代码如下:
struct simple_dev *simple_devices;
static unsigned char simple_inc=0;
static struct timer_list simple_timer;
static struct fasync_struct *fasync_queue=NULL;
int simple_open(struct inode *inode, struct file *filp)
{
struct simple_dev *dev;
dev = container_of(inode->i_cdev, struct simple_dev, cdev);
filp->private_data = dev;
simple_timer.function = &simple_timer_handler;
simple_timer.expires = jiffies + 2*HZ;
add_timer (&simple_timer);
printk("add_timer...\n");
return 0;
}
//异步通知处理函数
static int simple_fasync(int fd, struct file * filp, int mode)
{
int retval;
printk("simple_fasync...\n");
retval=fasync_helper(fd,filp,mode,&fasync_queue);
if(retval<0)
return retval;
return 0;
}
int simple_release(struct inode *inode, struct file *filp)
{
simple_fasync(-1, filp, 0);
return 0;
}
struct file_operations simple_fops = {
.owner = THIS_MODULE,
.open = simple_open,
.release= simple_release,
.fasync= simple_fasync,
};
当数据来临时通知应用层:
static void simple_timer_handler( unsigned long data)
{
printk("simple_timer_handler...\n");
if (fasync_queue)
{
//POLL_IN为可读,POLL_OUT为可写
kill_fasync(&fasync_queue, SIGIO, POLL_IN);
printk("kill_fasync...\n");
}
return ;
}
POLL_IN表示设备可读,POLL_OUT表示设备可写。应用层参考代码如下:
int fd;
void fasync_handler(int num)
{
printf("fasync_handler entering\n");
}
void main()
{
int i=2;
char data;
int oflags=0;
int retval;
signal(SIGIO, fasync_handler);//注册信号处理函数
fd=open("/dev/fcn",O_RDWR);
if(fd==-1)
{
perror("error open\n");
exit(-1);
}
printf("open /dev/fcn successfully\n");
//使能了异步的通知到当前进程
fcntl(fd, F_SETOWN, getpid());
oflags=fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, oflags | FASYNC);//修改文件标志
while(1);
close(fd);
}
运行结果如下:
# insmod demo.ko
# mknod /dev/fcn c 226 0
# ./test
add_timer...
open /dev/fcn successfullysimple_fasync...
simple_timer_handler...
kill_fasync...
fasync_handler entering
“poll和一步”中西结合{:titter:} zhenghe 发表于 2015-8-20 13:43
“poll和一步”中西结合
{:titter:}
页:
[1]