SmartOS/Core/Queue.cpp

167 lines
3.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "_Core.h"
#include "Queue.h"
extern void EnterCritical();
extern void ExitCritical();
Queue::Queue() : _s((void*)nullptr, 0)
{
Clear();
}
void Queue::SetCapacity(int len)
{
_s.SetLength(len);
}
void Queue::Clear()
{
_s.SetLength(_s.Capacity());
_head = 0;
_tail = 0;
_size = 0;
}
// 关键性代码,放到开头
INROOT void Queue::Enqueue(byte dat)
{
int total = _s.Capacity();
if(!total) _s.SetLength(64);
// 溢出不再接收
if(_size >= total) return;
_s[_head++] = dat;
//_head %= _s.Capacity();
// 除法运算是一个超级大祸害,它浪费了大量时间,导致串口中断接收丢数据
if(_head >= total) _head -= total;
EnterCritical();
_size++;
ExitCritical();
}
INROOT byte Queue::Dequeue()
{
if(_size == 0) return 0;
EnterCritical();
_size--;
ExitCritical();
/*
昨晚发现串口频繁收发一段数据后出现丢数据现象也即是size为0然后tail比head小刚开始小一个字节然后会逐步拉大。
经过分析得知ARM指令没有递加递减指令更没有原子操作。
size拿出来减一然后再保存回去但是保存回去之前串口接收中断写入拿到了旧的size导致最后的size比原计划要小1。
该问题只能通过关闭中断来解决。为了减少关中断时间以提升性能增加了专门的Read方法。
*/
int total = _s.Capacity();
byte dat = _s[_tail++];
//_tail %= _s.Capacity();
if(_tail >= total) _tail -= total;
return dat;
}
int Queue::Write(const Buffer& bs)
{
int total = _s.Capacity();
if(!total) _s.SetLength(64);
// 溢出不再接收
if(_size >= total) return 0;
/*
1数据写入队列末尾
2如果还剩有数据则从开头开始写入
3循环处理2
4如果队列过小很有可能后来数据会覆盖前面数据
*/
int len = bs.Length();
// 如果队列满了,不需要覆盖
if(_size + len > total)
len = total - _size;
int rs = 0;
while(true)
{
// 计算这一个循环剩下的位置
int remain = _s.Capacity() - _head;
// 如果要写入的数据足够存放
if(len <= remain)
{
_s.Copy(_head, bs, rs, len);
rs += len;
_head += len;
if(_head >= _s.Length()) _head -= _s.Length();
break;
}
// 否则先写一段,指针回到开头
_s.Copy(_head, bs, rs, remain);
len -= remain;
rs += remain;
_head = 0;
}
EnterCritical();
_size += rs;
ExitCritical();
return rs;
}
int Queue::Read(Buffer& bs)
{
if(_size == 0) return 0;
/*
1读取当前数据到末尾
2如果还剩有数据则从头开始读取
3循环处理2
4如果队列过小很有可能后来数据会覆盖前面数据
*/
int len = bs.Length();
if(!len) return 0;
if(len > _size) len = _size;
int rs = 0;
while(true)
{
int total = _s.Capacity();
// 计算这一个循环剩下的位置
int remain = total - _tail;
// 如果要读取的数据都在这里
if(len <= remain)
{
bs.Copy(rs, _s, _tail, len);
rs += len;
_tail += len;
if(_tail >= total) _tail -= total;
break;
}
// 否则先读一段,指针回到开头
bs.Copy(rs, _s, _tail, remain);
len -= remain;
rs += remain;
_tail = 0;
}
bs.SetLength(rs);
EnterCritical();
_size -= rs;
ExitCritical();
return rs;
}
WEAK void EnterCritical() { }
WEAK void ExitCritical() { }