RT-Thread论坛
直播中

余温重顾

10年用户 972经验值
擅长:可编程逻辑 嵌入式技术 EMC/EMI设计
私信 关注
[问答]

对ringbuffer中rt_ringbuffer_put_force函数的疑问求解


  • 最近研究驱动框架,顺带研读了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;
  •     }


大家认为呢?


更多回帖

发帖
×
20
完善资料,
赚取积分