Linux 內核的隊列實現--kfifo

今天研讀了2.6.26內核的kfifo代碼,感覺實現得巧妙,隊列的隊頭隊尾下標不受隊列長度的限制,就算隊頭下標大於隊列長度,也一樣可以使用,原理就在於,數據不是全部放在隊頭(fifo->out)和隊尾(fifo->in)之間的內存空間,而是把超出隊頭隊尾之間長度的數據放到整個隊列buffer的開始處,如圖:


藍色部分爲真實數據所在內存段,白色部分其實爲邏輯上假定的數據所在地,也就是說,爲了給用戶一種真正的隊列感覺——從尾部推進數據,從頭部拉取數據,那麼就必須讓fifo->out和fifo->in只能一直往一個方向推進,但是由於fifo所分配的buffer是有限的一段連續內存,fifo->out和fifo->in遲早要“越界”,因此,代碼中是這樣來處理所謂的“越界”情況的:

首先是入隊列的操作,保證fifo->out和fifo->in是一直往右推進的:

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

{

unsigned int 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;

}

可以明顯看到,如果fifo->in小於buffer->size,那麼先放完buffer->size-fifo->in這段內存空間,剩下的部分,轉移到buffer的可用空間開頭存放;如果fifo->in大於buffer->size,那麼直接把要入隊列的數據放到buffer可用空間開頭。

其次是出隊列的操作:

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

{

unsigned int 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;

}

情況1:fifo->in大於fifo->size而fifo->out小於fifo->size(即只有fifo->in“越界”),則先讀取fifo->out到fifo->size-1的那一段,大小爲l個byte,然後再讀取剩下的從buffer開頭,大小爲len-l個byte的數據(如下圖所示,即先讀data A段, 再讀出data B段);


情況2:fifo->in和fifo->out都“越界”了,那麼l = min(len, fifo->size - (fifo->out & (fifo->size - 1))); 這一語句便起作用了,此時fifo->out&fifo->size-1的結果即實際要讀的數據所在的內存地址相對於buffer起始地址的偏移值(如下圖所示,左邊爲實際上存在於內存中的data A段, 而右邊虛線框爲邏輯上的data A段的位置);


最後我自己有個疑問,fifo->out和fifo->in是unsign int(32bit)類型,如果應用程序在使用kfifo的時候,不斷偏移,最終導致fifo->out或者fifo->in溢出,那麼這種情況如何處理呢?kfifo的代碼中並沒有提到這種問題,等待深究。

來源:http://yiphon.diandian.com/post/2011-09-10/4918347

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章