#ifndef __GTC_FIFO_H_ #define __GTC_FIFO_H_ #ifndef GTC_MAX #define GTC_MAX(a,b) ((a) > (b) ? (a) : (b)) #endif #ifndef GTC_MIN #define GTC_MIN(a,b) ((a) < (b) ? (a) : (b)) #endif #ifdef __cplusplus extern "C" { #endif struct gfifo { 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) */ }; //队列初始化 int gfifo_alloc(struct gfifo *fifo, unsigned int size); //压入队列 unsigned int gfifo_put(struct gfifo *fifo, const unsigned char *buffer, unsigned int len); //弹出队列 unsigned int gfifo_get(struct gfifo *fifo, unsigned char *buffer, unsigned int len); #ifdef __cplusplus } #endif #endif
#include "gfifo.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> /******************************************************** Func Name: gfifo_init Date Created: 2019-4-1 Description: 初始化 Input: Output: Return: Caution: *********************************************************/ static void gfifo_init(struct gfifo *fifo, void *buffer, unsigned int size) { fifo->buffer = buffer; fifo->size = size; fifo->in = 0; fifo->out = 0; } /******************************************************** Func Name: gfifo_roundup Date Created: 2019-4-1 Description: 扩展 Input: Output: Return: size Caution: *********************************************************/ static unsigned int gfifo_roundup(unsigned int x) { unsigned int i = 0; unsigned int y = 1; if (!x) { return 1; } for (i = x; i != 0; ) { i >>= 1; y <<= 1; } return y; } /******************************************************** Func Name: gfifo_alloc Date Created: 2019-4-1 Description: 内存分配 Input: Output: Return: error code Caution: *********************************************************/ int gfifo_alloc(struct gfifo *fifo, unsigned int size) { assert(fifo); unsigned char *buffer; /* size的值总是在调用者传进来的size参数的基础上向2的幂扩展,这是内核一贯的做法。 这样的好处不言而喻--对kfifo->size取模运算可以转化为与运算,如下: fifo->in % fifo->size 可以转化为 fifo->in & (fifo->size – 1) 在kfifo_alloc函数中,使用size & (size – 1)来判断size 是否为2幂,如果条件为真,则表示size不是2的幂,然后调用roundup_pow_of_two将之向上扩展为2的幂。 */ if (size & (size - 1)) { size = gfifo_roundup(size); } buffer = calloc(1, size); if (NULL == buffer) { return -1; } gfifo_init(fifo, buffer, size); return 0; } /******************************************************** Func Name: gfifo_put Date Created: 2019-4-1 Description: 压入队列 Input: Output: Return: 压入队列数据长度 Caution: *********************************************************/ unsigned int gfifo_put(struct gfifo *fifo, const unsigned char *buffer, unsigned int len) { unsigned int left_over = 0; /* 计算出实际写入队列数据大小 (fifo->in - fifo->out) 已经使用空间大小 fifo->size - (fifo->in - fifo->out) 可以使用空间大小 len 需要写入数据大小 */ len = GTC_MIN(len, fifo->size - (fifo->in - fifo->out)); /* 计算出在队列in后面插入数据的大小 fifo->in & (fifo->size - 1) 等同于 fifo->in % fifo->size fifo->size - (fifo->in & (fifo->size - 1)) 表示in后面可写数据的长度 */ left_over = GTC_MIN(len, fifo->size - (fifo->in & (fifo->size - 1))); //拷贝数据到in后面 memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, left_over); //将剩余的数据拷贝到out前面 memcpy(fifo->buffer, buffer + left_over, len - left_over); //更新in fifo->in += len; return len; } /******************************************************** Func Name: gfifo_get Date Created: 2019-4-1 Description: 弹出队列 Input: Output: Return: 弹出队列 Caution: *********************************************************/ unsigned int gfifo_get(struct gfifo *fifo, unsigned char *buffer, unsigned int len) { assert(buffer); unsigned int readable_length = 0; /* 计算出实际可读队列数据大小 (fifo->in - fifo->out) 已经使用空间大小 */ len = GTC_MIN(len, fifo->in - fifo->out); /* 计算出在队列out后面插入数据的大小 fifo->in & (fifo->size - 1) 等同于 fifo->in % fifo->size fifo->size - (fifo->out & (fifo->size - 1)) 表示out后面可读数据的长度 */ readable_length = GTC_MIN(len, fifo->size - (fifo->out & (fifo->size - 1))); //拷贝数据 memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), readable_length); //拷贝能从头部获取的数据 memcpy(buffer + readable_length, fifo->buffer, len - readable_length); //更新out fifo->out += len; return len; }