轉自:https://blog.csdn.net/eydwyz/article/details/56671023
都只有一個的情況下,否則也要加鎖。下面就內核中提取出來,而經過修改后的fifo進
行簡要的分析。
先看其只要數據結構:
struct my_fifo {
unsignedchar *buffer;/* the buffer holding the data*/
unsignedint size;/* the size of the allocated buffer*/
unsignedint in;/* data is added at offset (in % size)*/
unsignedint out;/* data is extracted from off. (out % size)*/
}
也不用多說,一看就明白。size, in, out 都設成無符號型的,因為都不存在負值的情型。
/*form kernel/kfifo.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <fifo.h>
#define min(a,b) ((a) < (b) ? (a):(b))
/*
my_fifo_init
*/
struct my_fifo *my_fifo_init(unsignedchar *buffer,unsigned int size){
struct my_fifo *fifo;
fifo = malloc(sizeof(struct my_fifo));
if (!fifo)
returnNULL;
fifo->buffer = buffer;
fifo->size = size;
fifo->in = fifo->out = 0;
return fifo;
}
這個初始化fifo結構的函數一般也不會在應用層里進行調用,而是被下面的fifo_alloc
調用。依我的觀點來看,這兩個函數合成一個函數會更加的清晰,但是這一情況只針對
buffer是系統開辟的空間,如果buffer的空間是由其它的函數來提供,就只能用上面的這個函數。
/*
my_fifo_alloc
*/
struct my_fifo *my_fifo_alloc(unsignedint size)
{
unsignedchar *buffer;
struct my_fifo *ret;
/*
* round up to the next power of 2, since our 'let the indices
* wrap' tachnique works only in this case.
*/
buffer = malloc(size);
if (!buffer)
returnNULL;
ret = my_fifo_init(buffer, size);
if (ret ==NULL)
free(buffer);
return ret;
}
/*
* my_fifo_free
*/
void my_fifo_free(struct my_fifo *fifo)
{
free(fifo->buffer);
free(fifo);
}
這兩個函數也不作過多的分析,都很清晰。

/*
my_fifo_put()
*/
unsignedint my_fifo_put(struct my_fifo *fifo,
unsignedchar *buffer, unsigned int len)
{
unsignedint l;
len = min(len, fifo->size - fifo->in + fifo->out);/*可能是緩沖區的空閑長度或者要寫長度*/
/* first put the data starting from fifo->in to buffer end*/
l = min(len, fifo->size - (fifo->in & (fifo->size -1)));
memcpy(fifo->buffer + (fifo->in & (fifo->size -1)), buffer, l);
/* then put the rest (if any) at the beginning of the buffer*/
memcpy(fifo->buffer, buffer + l, len - l);
fifo->in += len;
return len;
}
/*
my_fifo_get
*/
unsignedint my_fifo_get(struct my_fifo *fifo,
unsignedchar *buffer, unsigned int len)
{
unsignedint l;
len = min(len, fifo->in - fifo->out); /*可讀數據*/
/* first get the data from fifo->out until the end of the buffer*/
l = min(len, fifo->size - (fifo->out & (fifo->size -1)));
memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size -1)), l);
/* then get the rest (if any) from the beginning of the buffer*/
memcpy(buffer + l, fifo->buffer, len - l);
fifo->out += len;
return len;
}
這兩個讀寫結構才是循環緩沖區的重點。在fifo結構中,size是緩沖區的大小,是由用
戶自己定義的,但是在這個設計當中要求它的大小必須是2的冪次。
當in==out時,表明緩沖區為空的,當(in-out)==size 時,說明緩沖區已滿。
我們看下具體實現,在86行處如果size-in+out ==0,也即獲得的len值會0,而沒有數
據寫入到緩沖區中。所以在設計緩沖區的大小的時候要恰當,讀出的速度要比定入的速
度要快,否則緩沖區滿了會使數據丟失,可以通過成功寫入的反回值來做判斷嘗試再次
寫入.
另一種情況則是緩沖區有足夠的空間給要寫入的數據,但是試想一下,如果空閑的空間
在緩沖的首尾兩次,這又是如何實現呢?這部分代碼實現得非常巧妙。
我們看fifo->in &(fifo->size-1) 這個表達式是什么意思呢?我們知道size是2的冪次
項,那么它減1即表示其值的二進制所有位都為1,與in相與的最終結果是in%size,比
size要小,所以看in及out的值都是不斷地增加,但再相與操作后,它們即是以size為
周期的一個循環。89行就是比較要寫入的數據應該是多少,如果緩沖區后面的還有足夠
的空間可寫,那么把全部的值寫到后面,否則寫滿后面,再寫到前面去93行。
讀數據也可以作類似的分析,108行表示請求的數據要比緩沖區的數據要大時,只
讀取緩沖區中可用的數據。
staticinline void my_fifo_reset(struct my_fifo *fifo)
{
fifo->in = fifo->out = 0;
}
staticinline unsigned int my_fifo_len(struct my_fifo *fifo)
return fifo->in - fifo->out;
}
在頭文件里還有緩沖區置位及返回緩沖區中數據大小兩個函數,很簡單,不必解釋
