linux 队列缓冲,linux驱动的等待队列(阻塞操作)和轮询(poll),缓冲区笔记

觉得还是贴代码最直接,以后要用的时候也方便参考。

先是相应驱动的详细代码:

/* linux/drivers/char/sep4020_char/sep4020_fifo.c

*

* Copyright (c) 2009 leeming

*

* sep4020 fifo driver.

*

* Changelog:

* 12-Aug-2009 leeming Initial version

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*/

#include #include #include #include #include #include #include #include #include #include #include #include #include

#include #include #include #include #include

#define FIFO_MAJOR 252          //主设备号

#define MAX_FIFO_BUF 16         //按键缓冲区的大小

struct fifodev

{

unsigned char buf[MAX_FIFO_BUF];   //按键缓冲区

unsigned int current_len;

wait_queue_head_t r_wait;            //读等待队列

wait_queue_head_t w_wait;            //写等待队列

struct cdev cdev;

} ;

struct fifodev *fifo_dev;     //键盘结构体

//返回读到的字节数

static ssize_t sep4020_fifo_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)

{

int ret;

// 第二个参数condition必须满足,否则阻塞

wait_event_interruptible(fifo_dev->r_wait, fifo_dev->current_len != 0);

if(size > fifo_dev->current_len)

size = fifo_dev->current_len;

if(copy_to_user(buf, fifo_dev->buf, size))

{

ret = -EFAULT;

goto out;

}

else

{

memcpy(fifo_dev->buf, fifo_dev->buf+size, fifo_dev->current_len-size);

fifo_dev->current_len = fifo_dev->current_len - size;

wake_up_interruptible(&fifo_dev->w_wait);

ret = size;

}

out:

return ret;

}

//返回写入的字节数

static ssize_t sep4020_fifo_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)

{

int ret;

wait_event_interruptible(fifo_dev->r_wait, fifo_dev->current_len != MAX_FIFO_BUF);

if(size > (MAX_FIFO_BUF-fifo_dev->current_len))

{

size = MAX_FIFO_BUF-fifo_dev->current_len;

}

if(copy_from_user(fifo_dev->buf+fifo_dev->current_len, buf, size))

{

ret = -EFAULT;

goto out;

}

else

{

fifo_dev->current_len += size;

ret = size;

}

wake_up_interruptible(&fifo_dev->r_wait);

out:

return ret;

}

//在使用echo或者cat的时候都会调用open函数

static int sep4020_fifo_open(struct inode *inode, struct file *filp)

{

//memset(fifo_dev->buf, 0, MAX_FIFO_BUF);

//fifo_dev->current_len = 0;

return 0;

}

static int sep4020_fifo_release(struct inode *inode, struct file *filp)

{

return 0;

}

/*

#define POLLIN   0x0001  //有数据可以读入,read不会阻塞,注意:select的请情况下,即使到EOF也是ready的.

#define POLLPRI  0x0002 //紧急数据,比如TCP,或者packet模式的peseudo-terminal发现slave的状态有变化.

#define POLLOUT  0x0004 //写入不会阻塞.

#define POLLERR  0x0008 //输出出错

#define POLLHUP  0x0010 //Hang up (output only).

#define POLLNVAL  0x0020 //Invalid request: fd not open (output only).

The rest seem to be more-or-less nonstandard. Check them!

#define POLLRDNORM 0x0040 //POLLIN.

#define POLLRDBAND 0x0080 //高优先级的数据read for read (generally unused on Linux).

#define POLLWRNORM 0x0100 //Equivalent to POLLOUT.

#define POLLWRBAND 0x0200 //Priority data may be written.

#define POLLMSG  0x0400

#define POLLREMOVE 0x1000

*/

static unsigned int sep4020_fifo_poll(struct file *filp, poll_table *wait)

{

unsigned int mask = 0;

//加入这两句话是为了在读写状态发生变化的时候,通知核心层,让核心层重新调用poll函数查询信息。也就是说这两句只会在select阻塞的时候用到

//当利用select函数发现既不能读又不能写时,select函数会阻塞,但是此时的阻塞并不是轮询,而是睡眠,通过下面两个队列发生变化时通知select

poll_wait(filp, &fifo_dev->r_wait, wait);

poll_wait(filp, &fifo_dev->w_wait, wait);

if(fifo_dev->current_len != 0)

{

mask |= POLLIN | POLLRDNORM;//可读,同时写上POLLRDNORM

}

if(fifo_dev->current_len != MAX_FIFO_BUF)

{

mask |= POLLOUT | POLLWRNORM;//可写,同时写上POLLWRNORM

}

return mask;

}

static struct file_operations sep4020_fifo_fops =

{

.owner = THIS_MODULE,

.read  = sep4020_fifo_read,

.write = sep4020_fifo_write,

.poll  = sep4020_fifo_poll,

.open  = sep4020_fifo_open,

.release = sep4020_fifo_release,

};

static int __init sep4020_fifo_init(void)

{

int err,result;

dev_t devno;

devno = MKDEV(FIFO_MAJOR, 0);

result = register_chrdev_region(devno, 1, "sep4020_fifo");   //向系统静态申请设备号

if (result < 0)

{

return result;

}

fifo_dev = kmalloc(sizeof(struct fifodev), GFP_KERNEL);

if (fifo_dev == NULL)

{

result = -ENOMEM;

unregister_chrdev_region(devno, 1);

return result;

}

memset(fifo_dev,0,sizeof(struct fifodev));  //初始化

cdev_init(&fifo_dev->cdev, &sep4020_fifo_fops);

fifo_dev->cdev.owner = THIS_MODULE;

//初始化等待对列

init_waitqueue_head(&fifo_dev->r_wait);

init_waitqueue_head(&fifo_dev->w_wait);

//向系统注册该字符设备

err = cdev_add(&fifo_dev->cdev, devno, 1);

if (err)

{

printk("fifo adding err\r\n");

unregister_chrdev_region(devno,1);

kfree(fifo_dev);

return err;

}

return 0;

}

static void __exit sep4020_fifo_exit(void)

{

cdev_del(&fifo_dev->cdev);

kfree(fifo_dev);

unregister_chrdev_region(MKDEV(FIFO_MAJOR, 0), 1);

}

module_init(sep4020_fifo_init);

module_exit(sep4020_fifo_exit);

MODULE_AUTHOR("Leeming Zhang");

MODULE_LICENSE("GPL");

/*****************************************************************************************************************/

接下来是相应的应用程序:

#include #include #include #include

int main(int argc, char **argv)

{

int fd;

char buf[16];

fd_set rfds,wfds; //读写描述符集合

unsigned char w_buf[7] = {'a','b','c','d','e','f','g'};

//open的标志位有:O_RDONLY O_WRONLY O_RDWR O_NONBLOCK O_NDELAY O_SYNC O_NOCTY

fd = open("/dev/fifo",O_RDWR);

if(fd == -1)

{

printf("wrong\r\n");

exit(-1);

}

while(1)

{

//初始化文件描述符集合

//清零

FD_ZERO(&rfds);

FD_ZERO(&wfds);

//将文件描述符加入文件描述符集合中,利用函数FD_CLR(int fd,fd_set *set)将一个文件描述符从文件描述符集中清除

FD_SET(fd, &rfds);

FD_SET(fd, &wfds);

//函数原型:int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

//readfds writefds exceptfds分别是被select监视的读,写和异常处理的文件描述符集合,numfds是需要检查的文件描述符加1。

select(fd+1, &rfds, &wfds, NULL, NULL);

//判断是否被置位,通过select函数调用驱动poll函数的返回值,来判断是否可读,还是可写,还是又能读又能写;当然如果驱动又不能读又不能写,在select那儿会阻塞,直到能读或者能写为止

if(FD_ISSET(fd, &rfds))

{

printf("Poll monitor: can be read\n");

}

if(FD_ISSET(fd, &wfds))

{

printf("Poll monitor: can be written\n");

}

}

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值