linux - 内核kfifo.c中in和out的问题【已解决】
黄舟
黄舟 2017-04-17 11:23:30
0
1
862

先上内核循环缓冲结构体的定义:

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 */
};

如果对“Linux内核中的循环缓冲区”不是很了解的话,可以先参考 这里。内核中有关kfifo.c和kfifo.h两个文件的源码以及该问题的具体情况,可以查看这里。

对于结构体内的in和out两个变量,内核是作如下处理的:1、在读入数据时增加in;2、在取出数据时增加out;3、当检测到两个相等的时候将它们复位归0。1和2不作讨论和分析,针对第3点的处理,内核代码如下:

static inline unsigned int kfifo_get(struct kfifo *fifo,
                                     unsigned char *buffer, unsigned int len)
{
        unsigned long flags;
        unsigned int ret;

        spin_lock_irqsave(fifo->lock, flags);
        ret = __kfifo_get(fifo, buffer, len);

        /*
         * optimization: if the FIFO is empty, set the indices to 0
         * so we don't wrap the next time
         */
        if (fifo->in == fifo->out)
                fifo->in = fifo->out = 0;

        spin_unlock_irqrestore(fifo->lock, flags);

        return ret;
}

问题:当数据写入速度大于读取速度的时候,in和out的值将永远不会相等,也就是说buffer永远是有数据的,这样的话in和out都存在超出自身数值表示范围,从而导致错误?

针对这个问题,不知大家有什么好的建议?

黄舟
黄舟

人生最曼妙的风景,竟是内心的淡定与从容!

全部回覆(1)
阿神

之前看錯你的問題了。

從原始碼的實作上來說,in和out的確是有可能會出現溢出,但是出現的情況非常極端:每次讀取資料的時候都比目前緩衝區中的資料還少、而且這種情況持續直到寫入的資料超過4GB。通常應該是不會遇到的;鑑於墨菲定律可能帶來的惡果,的確還是得考慮一下。

不過可以再想想,溢出了就真的會導致程式出錯嗎?

回頭再仔細看看 __kfifo_put() 裡面的程式碼,在寫入的時候是這樣實現的:

    /* 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);

注意(fifo->in & (fifo->size - 1) 這裡用了& 符號,而不是直接% fifo->size ,也就是說,初始化的時候size必然得設定成2的n次方(這個限制在核心裡很合理,因為核心分配的空間通常是2的倍數,例如一個page)。

在像x86這種溢位跟取模運算等價的處理器上,對於目前的寫入操作其實「剛好」沒有風險。同樣的,由於in/out都是 unsigned int ,在後續的 kfifo_get/kfifo_len 裡面 in - out (比如說 2 - 4294967295,你可以試試),結果仍然「正好」是正確的。

結論就是,它居然真的沒有風險(前提是在溢位、無符號整數減法操作與x86處理器類似的CPU上)。

不得不說,核心原始碼的開發者真吝嗇啊,多寫一個賦值運算都不捨得。


你既然都翻到源碼了,為什麼不仔細看看 的實作呢? kfifo_put()

它所呼叫的 的程式碼足以解釋了你的問題: __kfifo_put() 在寫入之前會先比較待寫入資料的長度和緩衝區的最大可寫入長度,取其小者,寫入,然後返回寫入的資料長度。具體程式碼沒幾行,自己去看吧。 __kfifo_put()

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板