panyuanyi 发表于 2015-8-20 11:50:52

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

zhenghe 发表于 2015-8-20 13:43:05

“poll和一步”中西结合{:titter:}

panyuanyi 发表于 2015-8-26 11:21:03

zhenghe 发表于 2015-8-20 13:43
“poll和一步”中西结合

{:titter:}
页: [1]
查看完整版本: poll和一步通讯