- 最近研究驱动框架,顺带研读了ringbuffer源代码,发现一处疑问,个人认为是bug,也可能能力有限分析不对,请各位大佬批评指正,代码如下:
- rt_size_t rt_ringbuffer_put_force(struct rt_ringbuffer *rb,
- const rt_uint8_t *ptr,
- rt_uint16_t length)
- {
- rt_uint16_t space_length;
- RT_ASSERT(rb != RT_NULL);
- space_length = rt_ringbuffer_space_len(rb);
- if (length > rb->buffer_size)
- {
- ptr = &ptr[length - rb->buffer_size];
- length = rb->buffer_size;
- }
- if (rb->buffer_size - rb->write_index > length)
- {
- /* read_index - write_index = empty space */
- memcpy(&rb->buffer_ptr[rb->write_index], ptr, length);
- /* this should not cause overflow because there is enough space for
- * length of data in current mirror */
- rb->write_index += length;
- if (length > space_length)
- rb->read_index = rb->write_index;
- return length;
- }
- memcpy(&rb->buffer_ptr[rb->write_index],
- &ptr[0],
- rb->buffer_size - rb->write_index);
- memcpy(&rb->buffer_ptr[0],
- &ptr[rb->buffer_size - rb->write_index],
- length - (rb->buffer_size - rb->write_index));
- /* we are going into the other side of the mirror */
- rb->write_mirror = ~rb->write_mirror;
- rb->write_index = length - (rb->buffer_size - rb->write_index);
- /******************分析这里,似乎是有bug??? ****************/
- if (length > space_length)
- {
- rb->read_mirror = ~rb->read_mirror;
- rb->read_index = rb->write_index;
- }
- return length;
- }
- RTM_EXPORT(rt_ringbuffer_put_force);
rt_ringbuffer_put_force函数,向buffer中put数据的策略为:
1)如果数据长度length > buffer_size,就将数据截断,只留后面的buffer_size长度的数据,从下面代码可以看出来:
- if (length > rb->buffer_size)
- {
- ptr = &ptr[length - rb->buffer_size];
- length = rb->buffer_size;
- }
2)space_length为空闲区长度,如果length > space_length,就将buffer中老的数据覆盖掉。
的确,rt_ringbuffer_put_force是按照上面两条策略在put数据,但是代码到下面这几行,存在问题了:
这里是一条华丽的分界线
- if (length > space_length)
- {
- rb->read_mirror = ~rb->read_mirror;
- rb->read_index = rb->write_index;
- }
这里是length >= buffer_size - write_index的情况,不然前面的代码直接return了。针对这种情况:
- write_index一定会溢出(也就是会超过buffer_size),这个时候一定有write_mirror = ~write_mirror。(问题来了:read_index是否会溢出?这得分情况讨论,看下面2)
- read_index 呢(length > space_length, read_index就一定会超过buffer_size???,我认为不一定 ),下面讨论:
情况2
write_index < read_index,这种情况下,空闲区域在缓冲区中间,有数据的区域在缓冲区两头,这种情况下,read_index和write_index都会溢出,因此有:
read_mirror = ~read_mirror
情况1
read_index < write_index,这种情况,有数据区域在缓冲区中间,缓冲区两头是空闲的,这个时候,write_index一定会溢出,但是read_index却不会溢出(因为前面限定了length最大不会超过buffer_size),这种情况下,read_mirror不变。
附一张截图,供大家理解我的意思:

所以我认为应该这样改:
- if (length > space_length && write_index ≤ read_index)
- {
- rb->read_mirror = ~rb->read_mirror;
- rb->read_index = rb->write_index;
- }
大家认为呢?