linux 循环缓冲区 源码,Linux中的循环缓冲区

在学习到

第十章 中断处理 时,其中的中断驱动的I/O需要使用缓冲区,我觉得与其自己实现一个缓冲区,不如利用内核已经写好的fifo。内核里有一个通用的循环缓冲区的实现在

使用的数据结构如下:

struct kfifo {

unsigned char *buffer;    /* 使用的缓冲区头指针 */

unsigned int size;    /* 缓冲区总大小 */

unsigned int in;    /* 已写入缓冲区的数据总量,当前缓冲区写指针的偏移量:(in % size) */

unsigned int out;    /* 已读出缓冲区的数据总量,当前缓冲区读指针的偏移量:(out % size) */

spinlock_t *lock;    /* 为避免竞态的自旋锁 */

};/*当in==out时,缓冲区为空;当(in-out)==size时,缓冲区已满*/

kfifo提供的循环缓冲的部分函数分为2类:

(1)以双下划线开头,没有使用自旋锁函数;

(2)没有双下划线开头,需要额外加锁的情况下使用的函数。

其实第二类只是在第一类的基础上进行加锁后,实际的代码如下:

unsigned long flags;

spin_lock_irqsave(fifo->lock, flags);

/*第一类函数*/

spin_unlock_irqrestore(fifo->lock, flags);

以下我按使用的顺序介绍每个函数的使用,部分函数源码在kernel/kfifo.c中定义,这些接口是经过精心构造的,可以小心地避免一些边界情况,原理其实很简单,建议去看源码弄清楚实现的原理,可以学到一些编程技巧。

(0)声明循环缓冲数据结构指针

struct kfifo *tekkamanfifo;

(1)初始化循环缓冲结构体

struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,

gfp_t gfp_mask, spinlock_t *lock);

/*调用kfifo_init必须保证size是2的整数次幂,而且buffer只接受一个已分配好空间的指针。也就是说之前要使用kmalloc分配好空间,将返回的指针传递到buffer*/

struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask,

spinlock_t *lock);

/*调用kfifo_alloc不必保证size是2的幂,它内部会把size向上调整到2的整数次幂。空间分配的内部实现使用kmalloc。函数内部调用kfifo_init/

buffer:之前要使用kmalloc分配好的空间指针;

size:循环缓冲空间大小;

gfp_mask:和kmalloc使用的分配标志(flags)一样。(参阅Linux设备驱动程序学习(8)-分配内存)

lock:是事先声明并初始化好的自旋锁结构体指针;

返回值 为初始化好的循环缓冲数据结构指针 。

(2) 向缓冲区里写入数据

unsigned int kfifo_put(struct kfifo *fifo,unsigned char *buffer, unsigned int len);

unsigned int __kfifo_put(struct kfifo *fifo,unsigned char *buffer, unsigned int len);

fifo:要写入数据的缓冲区结构体指针;

buffer:要写入的数据指针,指向内核空间。如需要用户空间数据,之前要用copy_from_user复制数据到内核空间;

len:要写入的数据大小;

返回值 为写入缓冲区的数据字节数。

(3)从缓冲区里读出数据

unsigned int kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len);

unsigned int __kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len);

参数定义和kfifo_put类似。

返回值 为从缓冲区读出的数据字节数。

(4)得到缓冲区已有的数据字节数

unsigned int kfifo_len(struct kfifo *fifo);

unsigned int __kfifo_len(struct kfifo *fifo);

fifo:要操作的缓冲区结构体指针;

函数返回缓冲区实际已有的数据字节数,内部实现十分简单,就是in - out;

返回值 为缓冲区已有的数据字节数。

(5)清空缓冲区

void __kfifo_reset(struct kfifo *fifo);

void kfifo_reset(struct kfifo *fifo);

内部实现十分简单,就是in = out = 0。

(6)使用结束,释放缓冲区。

void kfifo_free(struct kfifo *fifo);

所有的kfifo提供的循环缓冲的函数就是这些。在理解内部实现原理的基础上才能更好的使用它,所以再次建议阅读源码,因为源码很简单,但是很精巧。

ARM9开发板实验

实验现象:

[Tekkaman2440@SBC2440V4]#cd /lib/modules/

[Tekkaman2440@SBC2440V4]#insmod scull_kfifo.ko

[Tekkaman2440@SBC2440V4]#cat /proc/devices

Character devices:

1 mem

2 pty

3 ttyp

4 /dev/vc/0

4 tty

4 ttyS

5 /dev/tty

5 /dev/console

5 /dev/ptmx

7 vcs

10 misc

13 input

14 sound

81 video4linux

89 i2c

90 mtd

116 alsa

128 ptm

136 pts

153 spi

180 usb

189 usb_device

204 s3c2410_serial

252 scull_kfifo

253 usb_endpoint

254 rtc

Block devices:

1 ramdisk

256 rfd

7 loop

31 mtdblock

93 nftl

96 inftl

179 mmc

[Tekkaman2440@SBC2440V4]#mknod -m 666 /dev/scull_kfifo c 252 0

[Tekkaman2440@SBC2440V4]#echo 1234567890 > /dev/scull_kfifo

"sh" did write 11 bytes

[Tekkaman2440@SBC2440V4]#/tmp/scull_kfifo_test

scull_kfifo: the module can not lseek!

please input the command :1

scull_kfifo: ioctl SCULL_KFIFO_SIZE len=11

please input the command :2

scull_kfifo: SCULL_KFIFO_RESET code=0

please input the command :1

scull_kfifo: ioctl SCULL_KFIFO_SIZE len=0

please input the command :q

[Tekkaman2440@SBC2440V4]#echo 123456789012345678901234567890 > /dev/scull_kfifo

"sh" did write 31 bytes

[Tekkaman2440@SBC2440V4]#echo 123456789012345678901234567890 > /dev/scull_kfifo

"sh" did write 31 bytes

[Tekkaman2440@SBC2440V4]#echo 1234567890 > /dev/scull_kfifo

"sh" did write 2 bytes

"sh" did write 0 bytes

"sh" did write 0 bytes

"sh" did write 0 bytes

"sh" did write 0 bytes

"sh" did write 0 bytes

"sh" did write 0 bytes

"sh" did write 0 bytes

"sh" did write 0 bytes

printk: 204310 messages suppressed.

"sh" did write 0 bytes

1234567890

[Tekkaman2440@SBC2440V4]#/tmp/scull_kfifo_test

scull_kfifo: the module can not lseek!

please input the command :1

scull_kfifo: ioctl SCULL_KFIFO_SIZE len=64

please input the command :q

[Tekkaman2440@SBC2440V4]#cat /dev/scull_kfifo

printk: 1493677 messages suppressed.

"cat" did read 64 bytes

1234"cat" reading: going to sleep

56789012345678901234567890

123456789012345678901234567890

12

[Tekkaman2440@SBC2440V4]#/tmp/scull_kfifo_test

scull_kfifo: the module can not lseek!

please input the command :2

scull_kfifo: SCULL_KFIFO_RESET code=0

please input the command :q

[Tekkaman2440@SBC2440V4]#rmmod scull_kfifo

[Tekkaman2440@SBC2440V4]#lsmod

Module Size Used by Not tainted

[Tekkaman2440@SBC2440V4]#

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值