内核2.6.36版本kfifo代码修改分析

最近调试openwrt spi驱动,将原来2.6.23版本内核升级到2.6.36,发现调用kfifo相关api函数的代码无法编译通过。原来是内核升级后,kfifo代码进行了修改。以下就列举修改前和修改后的一些差别。

本质上,kfifo修改的目的在于为了使用kfifo api更加通用,而不是像原来内核中kfifo,只能使用在数据元素为字符型(unsigned char)的环形缓冲应用场景。

 

1struct kfifo定义的变化

在内核2.6.23代码中kfifo结构体定义如下:

struct kfifo {

unsigned char *buffer; /* the buffer holding the data */

unsigned int size; /* the size of the allocated buffer */

unsigned int in; /* data is added at offset (in % size) */

unsigned int out; /* data is extracted from off. (out % size) */

spinlock_t *lock; /* protects concurrent modifications */

};

而在2.6.36内核中,struct kfifo定义进行了一次大扩充。

struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void);

 

#define __STRUCT_KFIFO_PTR(type, recsize, ptrtype) \

{ \

__STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \

type buf[0]; \

}

 

#define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \

union { \

struct __kfifo kfifo; \

datatype *type; \

char (*rectype)[recsize]; \

ptrtype *ptr; \

const ptrtype *ptr_const; \

}

这段精妙的宏结构体设计可以看出,kfifo结构体中本身并不包含任何数据类型,使用者可以随意指定环形队列元素类型(datatype可以随意定义,这里使用的还是字符型)。更为强大的是,虽然结构体本身不包含队列数据类型,但它保存了这些信息。当使用者需要知道定义的是什么数据类型,可以通过 typeof(*fifo->type) 轻松获取。相比于老版代码中,只能定义unsigned char类型队列元素,显然通用性大大增加。

 

2、函数调用的变化

2.6.23代码中,使用kfifo_init或者kfifo_alloc函数为环形队列初始化,函数本身会为结构体分配空间,分配成功返回指向队列的指针。而在2.6.36kfifo_initkfifo_alloc函数只为队列缓存区开辟空间,并不为结构体本身分配空间。所以,在以前的代码中可以定义一个指向fifo的指针,而在新版本代码中,定义一个fifo结构体实体显然是更方便的。相应的函数调用方式也会跟着改变,从直接使用指针变量变成需要取地址指针。如下所示:

函数调用从:

spi_task_rec_fifo = kfifo_alloc(MAX_REC_BUF_LEN, GFP_KERNEL, &spi_buf_lock);

spi_task_rec_fifo = kfifo_init((unsigned char*)spi_bootmem, size, GFP_KERNEL, &spi_buf_lock);

变为:

kfifo_alloc(&spi_task_rec_fifo, MAX_REC_BUF_LEN, GFP_KERNEL);

kfifo_init(&spi_task_rec_fifo, spi_bootmem, spi_bootmem_size);

同时,在2.6.23版内核代码中,调用kfifo_put入队列函数和kfifo_get出队列函数是带三个参数的,比2.6.36版本内核代码多了一个表示长度的参数len(该参数表示入队和出队的元素个数)。在2.6.36版本内核代码中kfifo_putkfifo_get只有两个参数,这两个api已经分别被修改为单次只能入队和出队一个元素。那么该怎么一次处理多个呢?在2.6.36版本内核代码中,为用户提供了kfifo_inkfifo_in_spinlockedkfifo_outkfifo_out_spinlocked四个api,其中带spinlockedapi用在环形队列需要加锁保护的场景,需要用户自己先创建并初始化一个自旋锁,作为参数传入。在我们的应用场景中是使用了自旋锁的,实际上在实际应用中,假如fifo只有一个生产者和消费者,是不需要自旋锁的。这比在2.6.23版内核代码中必须使用自旋锁的设计,显然显得更加合理,同时在无需自旋锁场景下也能提高出入队列效率。

另外在2.6.36版内核代码中还提供了kfifo_peek(只取出数据而不从队列删除)、kfifo_skip(跳过某些数据)等api,另外一些更详细的代码,请参见内核代码kfifo.ckfifo.h

从以上分析可以看的出来,kfifo内核代码在兼容性、扩展性方面大大提高,而在易用性上并没有相应变得复杂,并且继承了旧版代码kfifo设计上的精巧之处,足见内核kfifo代码设计者深厚的功力。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值