目录
kfifo说明
kfifo分为两种
1、普通的kfifo,类似于普通的循环队列,每一个buff空间都用来存放数据
data | data | data | data | data | data | data | data |
适用范围:流数据的存储,一个线程入队,一个线程出队
2、带有长度记录的kfifo_rec,与kfifo不同的是,每次入队时都会在本次数据之前的1/2个字节来表示本次数据的长度。
len1 | data1 | data1 | data1 | data1 | len2 | data2 | data2 |
适用范围:块数据的数据缓存,操作单位是块
关于自旋锁的官方说明:
①单个读写操作不用上锁
②不调用kfifo_reset()不上锁
③调用kfifo_reset_out(),只需出队是上锁即可
④对于多个入队对应一个出队时,只需入队线程加锁即可
⑤对于多个出队对应一个入队时,只需出队线程加锁即可
kfifo的优点
实现了简单高效的队列操作。
定义kfifo结构体
#define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \
union { \
struct __kfifo kfifo; \
datatype *type; \
const datatype *const_type; \
char (*rectype)[recsize]; \
ptrtype *ptr; \
ptrtype const *ptr_const; \
}
#define __STRUCT_KFIFO_PTR(type, recsize, ptrtype) \
{ \
__STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \
type buf[0]; \
}
/*
* define compatibility "struct kfifo" for dynamic allocated fifos
*/
struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void);
//将上面两个宏定义展开可得:
struct kfifo{
union {
struct __kfifo kfifo;
datatype *type; //传进来的是unsigned char类型
const datatype *const_type;
char (*rectype)[recsize]; //对于普通的kfifo recsize为0, kfiro_rec recsize大小为1或2
ptrtype *ptr; //传进来的是void类型
ptrtype const *ptr_const;
}
unsigned char buf[0];
}
/*其中struct __kfifo:*/
struct __kfifo {
unsigned int in; //队尾下标,入队列的offset为(in % size 或者 in & mask)
unsigned int out; //队首下标,出队列的offset为(out % size 或者 out & mask)
unsigned int mask; //缓冲区元素个数(size) - 1;使用&mask,替换%size,提升效率
unsigned int esize; //缓存区每个元素的size(element size)
void *data; //用于存放数据的缓存区
};
kfifo初始化方法一
//kfifo初始化 方法1
/**
* kfifo_alloc - 动态分配一个新的fifo缓冲区
* @fifo: pointer to the fifo
* @size: the number of elements in the fifo, this must be a power of 2
* @gfp_mask: get_free_pages mask, passed to kmalloc()
*
* The numer of elements will be rounded-up to a power of 2.
* The fifo will be release with kfifo_free().
* Return 0 if no error, otherwise an error code.
*/
#define kfifo_alloc(fifo, size, gfp_mask) \
__kfifo_int_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
__is_kfifo_ptr(__tmp) ? \
__kfifo_alloc(__kfifo, size, sizeof(*__tmp->type), gfp_mask) : \
-EINVAL; \
}) \
)
//typeof()是C语言的关键字,用于获取表达式的类型
//fifo的类型为struct kfifo*,fifo+1根据类型转换还是指针类型,typeof((fifo)+1)就是struct kfifo*
/*指针+1的操作,相当于取同类型下一个元素的地址,所以只有是指针才能正确,防止传进来的是数组,因此typeof(x + 1)主要是用来检查传进来的参数确保是指针
参考文章:http://blog.chinaunix.net/uid-9672747-id-4045550.html*/
//将宏展开:
#define kfifo_alloc(fifo,size,gfp_mask)
{
struct kfifo* __tmp = (fifo);
struct __kfifo* __kfifo = &__tmp->kfifo;
return __is_kfifo_ptr(__tmp) ? __kfifo_alloc(__kfifo,size,sizeof(*__tmp->type),gfp_mask): -EINVAL;
//EINVAL #define EINVAL 22 /* Invalid argument */
//#define __is_kfifo_ptr(fifo) (sizeof(*fifo) == sizeof(struct __kfifo)) 判断kfifo是不是普通的kfifo
}
//调用__kfifo_alloc()
int __kfifo_alloc(struct __kfifo *fifo, unsigned int size,
size_t esize, gfp_t gfp_mask)
{
/*
* round down to the next power of 2, since our 'let the indices wrap' technique works only in this case.
* 向下四舍五入到2的下一次方,因为我们的“让索引包起来”技术只适用于这种情况。
*/
size = roundup_pow_of_two(size);
fifo->in = 0;
fifo->out = 0;
fifo->esize = esize;
if (size < 2) {
fifo->data = NULL;
fifo->mask = 0;
return -EINVAL;
}
fifo->data = kmalloc(size * esize, gfp_mask);
if (!fifo->data) {
fifo->mask = 0;
return -ENOMEM;
}
fifo->mask = size - 1;
return 0;
}
kfifo初始化方法二
//kfifo 初始化 方法二 与 kfifo_alloc的区别就在于一个是动态申请内存,一个是静态设置缓存
/**
* kfifo_init - 使用预分配的缓冲区初始化fifo
* @fifo: the fifo to assign the buffer
* @buffer: the preallocated buffer to be used
* @size: the size of the internal buffer, this have to be a power of 2
*/
#define kfifo_init(fifo, buffer, size) \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
__is_kfifo_ptr(__tmp) ? \
__kfifo_init(__kfifo, buffer, size, sizeof(*__tmp->type)) : \
-EINVAL; \
})
//宏展开
#define kfifo_init(fifo, buffer, size)
{
struct kfifo* __tmp = (fifo);
struct __kfifo *__kfifo = &__tmp->kfifo;
__is_kfifo_ptr(__tmp) ? __kfifo_init(__kfifo, buffer, size, sizeof(*__tmp->type)) : -EINVAL;
}
//调用__kfifo_init()
int __kfifo_init(struct __kfifo *fifo, void *buffer,
unsigned int size, size_t esize)
{
size /= esize;
size = roundup_pow_of_two(size);
fifo->in = 0;
fifo->out = 0;
fifo->esize = esize;
fifo->data = buffer;
if (size < 2) {
fifo->mask = 0;
return -EINVAL;
}
fifo->mask = size - 1;
return 0;
}
函数名 | 功能 |
kfifo_alloc | 动态申请缓存 |
kfifo_init | 预先设置buff缓存 |
释放kfifo
//释放kfifo
/**
* kfifo_free - frees the fifo
* @fifo: the fifo to be freed
*/
#define kfifo_free(fifo) \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
if (__is_kfifo_ptr(__tmp)) \
__kfifo_free(__kfifo); \
})
//宏展开
#define kfifo_free(fifo)
{
struct kfifo* __tmp = (fifo);
struct __kfifo* __kfifo = &_tmp->kfifo;
if(__is_kfifo_ptr(__tmp))
__kfifo_free(__kfifo);
}
//调用__kfifo_free()
void __kfifo_free(struct __kfifo *fifo)
{
kfree(fifo->data);
fifo->in = 0;
fifo->out = 0;
fifo->esize = 0;
fifo->data = NULL;
fifo->mask = 0;
}
kfifo入队方法一
//入队1
/**
* kfifo_in - 入队
* @fifo: address of the fifo to be used
* @buf: the data to be added
* @n: number of elements to be added
*
* This macro copies the given buffer into the fifo and returns the
* number of copied elements.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_in(fifo, buf, n) \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof(__tmp->ptr_const) __buf = (buf); \
unsigned long __n = (n); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ?\
__kfifo_in_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_in(__kfifo, __buf, __n); \
})
//宏展开
#define kfifo_in(fifo, buf, n)
{
struct kfifo* __tmp = (fifo);
void const * __buf = (buf);
unsigned long __n = (n);
const size_t __recsize = sizeof(*__tmp->rectype); //这里__resize = 0;
struct __kfifo *__kfifo = &__tmp->kfifo;
(__recsize) ?__kfifo_in_r(__kfifo, __buf, __n, __recsize) : __kfifo_in(__kfifo, __buf, __n);
//kfiro_rec 调用__kfifo_in_r(__kfifo, __buf, __n, __recsize)
//kfiro 调用__kfifo_in(__kfifo, __buf, __n)
}
//调用__kfifo_in()
unsigned int __kfifo_in(struct __kfifo *fifo,
const void *buf, unsigned int len)
{
unsigned int l;
l = kfifo_unused(fifo);//获取未使用的缓存长度
if (len > l)
len = l;
kfifo_copy_in(fifo, buf, len, fifo->in);
fifo->in += len;
return len;
}
/*获取kfifo未使用的缓存长度*/
static inline unsigned int kfifo_unused(struct __kfifo *fifo)
{
return (fifo->mask + 1) - (fifo->in - fifo->out);
}
/**/
static void kfifo_copy_in(struct __kfifo *fifo, const void *src,
unsigned int len, unsigned int off)
{
unsigned int size = fifo->mask + 1;
unsigned int esize = fifo->esize;
unsigned int l;
off &= fifo->mask;//与运算代替取余运算效率更高 入队列的offset为(in % size 或者 in & mask) 获取到 fifo->in 在内存 buffer 中的对应位置
if (esize != 1) {
off *= esize;
size *= esize;
len *= esize;
}
/*
*拷贝数据到 in 后面的内存
*如果 in 后面的内存 buffer 段不够存放
*则将剩余的数据拷贝到内存 buffer 的开头对应的位置
*/
l = min(len, size - off);
memcpy(fifo->data + off, src, l);
memcpy(fifo->data, src + l, len - l);
/*
* make sure that the data in the fifo is up to date before
* incrementing the fifo->in index counter
*/
smp_wmb();//内存屏障 #define smp_wmb() barrier() static inline void barrier(void){ asm volatile("" : : : "memory");}
}
kfifo入队方法二
//入队2
/**
* kfifo_in_spinlocked - 使用自旋锁将数据放入fifo进行锁定
* @fifo: address of the fifo to be used
* @buf: the data to be added
* @n: number of elements to be added
* @lock: pointer to the spinlock to use for locking
*
* This macro copies the given values buffer into the fifo and returns the
* number of copied elements.
*/
#define kfifo_in_spinlocked(fifo, buf, n, lock) \
({ \
unsigned long __flags; \
unsigned int __ret; \
spin_lock_irqsave(lock, __flags); \
__ret = kfifo_in(fifo, buf, n); \
spin_unlock_irqrestore(lock, __flags); \
__ret; \
})
//宏展开
#define kfifo_in_spinlocked(fifo, buf, n, lock)
{
unsigned long __flags;
unsigned int __ret;
spin_lock_irqsave(lock, __flags); //自旋锁在任何情况下使用spin_lock_irq都是安全的。因为它既禁止本地中断,又禁止内核抢占
__ret = kfifo_in(fifo, buf, n);
spin_unlock_irqrestore(lock, __flags);
return __ret;
})
函数/宏定义 | 功能 |
#define kfifo_put(fifo, val) | 单字节入队 |
#define kfifo_in(fifo, buf, n) | 多字节入队 |
#define kfifo_in_spinlocked(fifo, buf, n, lock) | 入队时上锁 |
kfifo出队方法一
//出队
/**
* kfifo_out - 将数据从fifo中出队
* @fifo: address of the fifo to be used
* @buf: pointer to the storage buffer
* @n: max. number of elements to get
*
* This macro get some data from the fifo and return the numbers of elements
* copied.
*
* Note that with only one concurrent reader and one concurrent
* writer, you don't need extra locking to use these macro.
*/
#define kfifo_out(fifo, buf, n) \
__kfifo_uint_must_check_helper( \
({ \
typeof((fifo) + 1) __tmp = (fifo); \
typeof(__tmp->ptr) __buf = (buf); \
unsigned long __n = (n); \
const size_t __recsize = sizeof(*__tmp->rectype); \
struct __kfifo *__kfifo = &__tmp->kfifo; \
(__recsize) ?\
__kfifo_out_r(__kfifo, __buf, __n, __recsize) : \
__kfifo_out(__kfifo, __buf, __n); \
}) \
)
//宏展开
#define kfifo_out(fifo, buf, n)
{
struct kfifo* __tmp = (fifo);
void* __buf = (buf);
unsigned long __n = (n);
const size_t __recsize = sizeof(*__tmp->resctype);//此时为0
struct __kfifo *__kfifo = &__tmp->kfifo;
(__recsize) ? __kfifo_out_r(__kfifo, __buf, __n, __recsize) : __kfifo_out(__kfifo, __buf, __n);
}
//调用 __kfifo_out()
unsigned int __kfifo_out(struct __kfifo *fifo,
void *buf, unsigned int len)
{
len = __kfifo_out_peek(fifo, buf, len);
fifo->out += len;
return len;
}
kfifo出队方法二
//出队2
/**
* kfifo_out_spinlocked - 使用自旋锁从fifo获取数据进行锁定
* @fifo: address of the fifo to be used
* @buf: pointer to the storage buffer
* @n: max. number of elements to get
* @lock: pointer to the spinlock to use for locking
*
* This macro get the data from the fifo and return the numbers of elements
* copied.
*/
#define kfifo_out_spinlocked(fifo, buf, n, lock) \
__kfifo_uint_must_check_helper( \
({ \
unsigned long __flags; \
unsigned int __ret; \
spin_lock_irqsave(lock, __flags); \
__ret = kfifo_out(fifo, buf, n); \
spin_unlock_irqrestore(lock, __flags); \
__ret; \
}) \
)
//宏展开
#define kfifo_out_spinlocked(fifo, buf, n, lock)
{
unsigned long __flags;
unsigned int __ret;
spin_lock_irqsave(lock, __flags); //自旋锁
__ret = kfifo_out(fifo, buf, n);
spin_unlock_irqrestore(lock, __flags);
__ret;
}
函数/宏定义 |
#define kfifo_get(fifo, val) |
#define kfifo_peek(fifo, val) |
#define kfifo_out(fifo, buf, n) |
kfifo_out_peek(fifo, buf, n) |
#define kfifo_out_spinlocked(fifo, buf, n, lock) |
参考:https://blog.csdn.net/Bruno_Mars/article/details/100061793