[linux-kernel] 实现支持poll的驱动设备

作者:董昊 (要转载的同学帮忙把名字和博客链接http://oldblog.donghao.org/uii/带上,多谢了!)


ldd3上已经讲了如何开发linux下的驱动程序,怎么让该设备支持poll(和epoll),但是不够详细,这里给个例子。假设实现一个misc设备,为了实现poll,当然要有个wait_queue,注意,是dev带wait_queue,我一疏忽把wait_queue带到file上去了,调了半天才发现这个低级错误。


struct sample_dev

{

    struct miscdevice       misc;

    wait_queue_head_t    wait;

};


static struct sample_dev    s_dev;


s_dev这个设备现在既可以当miscdevice用,同时又有了wait_queue


struct file_operations sample_fops =

{

    .owner       = THIS_MODULE,

    .read         = sample_read,

    .write        = sample_write,

    .poll           = sample_poll,

};


static int __init init_sample(void)

{

    s_dev.misc.minor = MISC_DYNAMIC_MINOR;

    s_dev.misc.name = "poll_device_sample";

    s_dev.misc.fops  = &sample_fops;

    init_waitqueue_head(&s_dev.wait);

    return misc_register(&s_dev.misc);

}


static void __exit exit_sample(void)

{

    misc_unregister(&s_dev.misc);

}


这是设备的注册和注销。下面看sample_poll的做法,和ldd3上说的一样:


unsigned int sample_poll(struct file* file, poll_table* wait)

{

    unsigned int    mask = 0;


    poll_wait(file, &s_dev.wait, wait);


    /* if have something to read (代码省略)*/

        mask |= POLLIN;

    /* if have something to write (代码省略)*/

        mask |= POLLOUT;

    /* if some error occur (代码省略)*/

        mask |= POLLERR;


    return mask;

}


poll_wait是linux内核提供的,标准做法,所以最好这么用。在poll_wait里,current进程挂在了s_dev的wait_queue里,只有两种情况让他醒来:一个是poll系统调用超时(poll_table负责),另一个是读写唤醒他(后面的代码)。


sszie_t    sample_read(struct file* file, char __user* buff, loff_t* pos)

{

    /* do what you want to read(代码省略)*/

    wake_up_interruptible(&s_dev.wait); 

}


由于读走了一些数据,缓冲区(代码没有详细写)有位置了,可以往里面写了,上面标红的行便唤醒随眠的进程,他(进程)醒来后就到了poll_wait语句的后面,开始查看缓冲区并置mask,最后返回。sample_write也是同样的实现方式。


以上代码只是例子,并不完整,但原理已经充分。这样实现的设备已经可以支持poll和epoll调用,当然,epoll的原理更为复杂,和上面说的过程有一些差异,详情可以参考这里


相关文章

分类

留言:

关于文章

This page contains a single entry by DongHao published on 03 9, 2010 5:10 PM.

[linux] 文件通知机制 (dnotify, inotify) was the previous entry in this blog.

[linux-kernel] 内核里读取mmap文件的内容 is the next entry in this blog.

Find recent content on the main index or look in the 存档 to find all content.