在生产者和消费者都只有一个的情况,环形缓冲区从实现机制上可以打到免锁的效果。环形缓冲区在相应中断处理速度方面效果非凡。
#include "stdafx.h"
#include "stdio.h"
#include "memory.h"
typedef unsigned long ULONG;
typedef unsigned short USHORT;
typedef unsigned char UCHAR;
#define NULL_PTR NULL
#define VOID void
#define VOS_OK 0
#define VOS_ERR 1
#define SIZE_OF_TL (5)
typedef struct tagTlv
{
UCHAR ucType; /* TLV类型 */
UCHAR ucLen1; /* TLV长度24-31比特 */
UCHAR ucLen2; /* TLV长度16-23比特 */
UCHAR ucLen3; /* TLV长度08-15比特 */
UCHAR ucLen4; /* TLV长度00-07比特 */
UCHAR aucValue[3]; /* 保留位,四字节对齐 */
} TLV_S;
#define RING_BUFFER_SIZE (30)
typedef struct tagRingBuffer
{
ULONG ulUsedBufferSize; /* 环形缓冲区已使用空间大小 */
UCHAR ucType; /* 通过TLV结构保存数据,代表Type */
UCHAR ucSrv[3]; /* 保留位,四字节对齐 */
UCHAR *pucReadCursor; /* 数据读取游标 */
UCHAR *pucWriteCursor; /* 数据写入游标 */
UCHAR aucBuffer[RING_BUFFER_SIZE]; /* 缓冲区 */
} RING_BUFFER_S;
RING_BUFFER_S g_stRingBuffer;
/************************************************************************
* 功能描述:初始化环形缓冲区
* 参数说明:UCHAR ucType 环形缓冲区TLV类型
* 原理说明:
* 返 回 值:环形缓冲区指针
*************************************************************************/
VOID *VOS_InitRingBuffer(UCHAR ucType)
{
g_stRingBuffer.ulUsedBufferSize = 0;
g_stRingBuffer.ucType = ucType;
g_stRingBuffer.pucReadCursor = g_stRingBuffer.aucBuffer;
g_stRingBuffer.pucWriteCursor = g_stRingBuffer.aucBuffer;
return &g_stRingBuffer;
}
/************************************************************************
* 功能描述:获取环形缓冲区已使用空间大小
* 参数说明:VOID *pRingBuffer 环形缓冲区指针
* 原理说明:
* 返 回 值:已使用空间大小
*************************************************************************/
ULONG VOS_GetUsedRingBufferSize(VOID *pRingBuffer)
{
RING_BUFFER_S *pstRingBuffer;
/* 内部函数不检查参数合法性 */
pstRingBuffer = (RING_BUFFER_S *)(pRingBuffer);
return pstRingBuffer->ulUsedBufferSize;
}
/************************************************************************
* 功能描述:获取环形缓冲区空闲空间大小
* 参数说明:VOID *pRingBuffer 环形缓冲区指针
* 原理说明:
* 返 回 值:ULONG 空闲空间大小
*************************************************************************/
ULONG VOS_GetFreeRingBufferSize(VOID *pRingBuffer)
{
RING_BUFFER_S *pstRingBuffer;
/* 内部函数不检查参数合法性 */
pstRingBuffer = (RING_BUFFER_S *)(pRingBuffer);
return (sizeof(pstRingBuffer->aucBuffer) - pstRingBuffer->ulUsedBufferSize);
}
/************************************************************************
* 功能描述:智能拷贝数据到环形缓冲区
* 参数说明:UCHAR *pucRingBuffer 环形缓冲区指针
ULONG ulRingBufferSize 环形缓冲区大小
UCHAR *pucDst 数据拷贝目的指针(位于环形缓冲区内)
UCHAR *pucSrc 数据拷贝源指针
ULONG ulSrcSize 数据拷贝大小
* 原理说明:
* 返 回 值:CUAHR * 拷贝完数据后指针
*************************************************************************/
UCHAR *VOS_SmartCopyInfoBuffer(UCHAR *pucRingBuffer, ULONG ulRingBufferSize, UCHAR *pucDst, UCHAR *pucSrc, ULONG ulSrcSize)
{
ULONG ulTailLen;
UCHAR *pucCopyEnd;
/* 函数参数合法性检查 */
if ((NULL == pucRingBuffer) || (NULL_PTR == pucDst) || (NULL_PTR == pucSrc))
{
return NULL_PTR;
}
/* 获取环形缓冲区尾部可用空间大小 */
ulTailLen = (ULONG)((pucRingBuffer + ulRingBufferSize) - pucDst);
if (ulTailLen >= ulSrcSize)
{
/* 环形缓冲区尾部空间足够时,直接拷贝数据到尾部 */
memcpy(pucDst, pucSrc, ulSrcSize);
pucCopyEnd = pucDst + ulSrcSize;
}
else
{
/* 环形缓冲区尾部空间不足时,拷贝部分数据到尾部,然后再拷贝数据到头部 */
memcpy(pucDst, pucSrc, ulTailLen);
memcpy(pucRingBuffer, pucSrc + ulTailLen, ulSrcSize - ulTailLen);
pucCopyEnd = pucRingBuffer + (ulSrcSize - ulTailLen);
}
return pucCopyEnd;
}
/************************************************************************
* 功能描述:智能从环形缓冲区拷贝数据
* 参数说明:UCHAR *pucRingBuffer 环形缓冲区指针
ULONG ulRingBufferSize 环形缓冲区大小
UCHAR *pucSrc 数据拷贝源指针(位于环形缓冲区内)
UCHAR *pucDst 数据拷贝目的指针
ULONG ulDstSize 数据拷贝大小
* 原理说明:
* 返 回 值:UCHAR * 拷贝完数据后指针
*************************************************************************/
UCHAR *VOS_SmartCopyFromBuffer(UCHAR *pucRingBuffer, ULONG ulRingBufferSize, UCHAR *pucSrc, UCHAR *pucDst, ULONG ulDstSize)
{
ULONG ulTailLen;
UCHAR *pucCopyEnd;
/* 函数参数合法性检查 */
if ((NULL == pucRingBuffer) || (NULL_PTR == pucSrc) || (NULL_PTR == pucDst))
{
return NULL_PTR;
}
/* 获取环形缓冲区尾部空间大小 */
ulTailLen = (ULONG)((pucRingBuffer + ulRingBufferSize) - pucSrc);
if (ulTailLen >= ulDstSize)
{
/* 环形缓冲区尾部空间足够时,直接从尾部拷贝数据 */
memcpy(pucDst, pucSrc, ulDstSize);
pucCopyEnd = pucSrc + ulDstSize;
}
else
{
/* 环形缓冲区尾部空间不足时,从尾部拷贝部分数据,然后再从头部拷贝数据 */
memcpy(pucDst, pucSrc, ulTailLen);
memcpy(pucDst + ulTailLen, pucRingBuffer, ulDstSize - ulTailLen);
pucCopyEnd = pucRingBuffer + (ulDstSize - ulTailLen);
}
return pucCopyEnd;
}
/************************************************************************
* 功能描述:将用户数据压入环形缓冲区
* 参数说明:VOID *pRingBuffer 环形缓冲区指针
VOID *pFrameBuffer 用户数据指针
ULONG ulFrameBufferLen 用户数据大小
* 原理说明:
* 返 回 值:VOS_OK 数据压入环形缓冲区成功
VOS_ERR 数据压入环形缓冲区失败
*************************************************************************/
ULONG VOS_PushBuffer(VOID *pRingBuffer, VOID *pFrameBuffer, ULONG ulFrameBufferLen)
{
ULONG ulFreeRingBufferSize;
TLV_S stTlv;
UCHAR *pucCopyEnd;
RING_BUFFER_S *pstRingBuffer;
/* 函数参数合法性检查 */
if ((NULL_PTR == pRingBuffer) || (NULL_PTR == pFrameBuffer))
{
return VOS_ERR;
}
pstRingBuffer = (RING_BUFFER_S *)pRingBuffer;
/* 获取环形缓冲区可用空间 */
ulFreeRingBufferSize = VOS_GetFreeRingBufferSize(pstRingBuffer);
/* 环形缓冲区可用空间不足 */
if (ulFreeRingBufferSize < (ulFrameBufferLen + SIZE_OF_TL))
{
return VOS_ERR;
}
/* 写入TL字段 */
stTlv.ucType = pstRingBuffer->ucType;
stTlv.ucLen1 = (UCHAR)((ulFrameBufferLen >> 24) & 0xFF);
stTlv.ucLen2 = (UCHAR)((ulFrameBufferLen >> 16) & 0xFF);
stTlv.ucLen3 = (UCHAR)((ulFrameBufferLen >> 8) & 0xFF);
stTlv.ucLen4 = (UCHAR)((ulFrameBufferLen >> 0) & 0xFF);
pucCopyEnd = VOS_SmartCopyInfoBuffer(pstRingBuffer->aucBuffer,
sizeof(pstRingBuffer->aucBuffer),
pstRingBuffer->pucWriteCursor,
(UCHAR *)(&stTlv),
SIZE_OF_TL);
pstRingBuffer->pucWriteCursor = pucCopyEnd;
pstRingBuffer->ulUsedBufferSize += SIZE_OF_TL;
/* 写入用户数据 */
pucCopyEnd = VOS_SmartCopyInfoBuffer(pstRingBuffer->aucBuffer,
sizeof(pstRingBuffer->aucBuffer),
pstRingBuffer->pucWriteCursor,
(UCHAR *)(pFrameBuffer),
ulFrameBufferLen);
pstRingBuffer->pucWriteCursor = pucCopyEnd;
pstRingBuffer->ulUsedBufferSize += ulFrameBufferLen;
return VOS_OK;
}
/************************************************************************
* 功能描述:从环形缓冲区读取数据
* 参数说明:VOID *pRingBuffer 环形缓冲区指针
VOID *pFrameBuffer 用户数据指针(用户保证内存不存在越界)
ULONG *pulFrameBufferLen用户数据大小
* 原理说明:
* 返 回 值:VOS_OK 数据压入环形缓冲区成功
VOS_ERR 数据压入环形缓冲区失败
*************************************************************************/
ULONG VOS_PopBuffer(VOID *pRingBuffer, VOID *pFrameBuffer, ULONG *pulFrameBufferLen)
{
ULONG ulUsedRingBufferSize;
ULONG ulFrameBufferLen;
TLV_S stTlv;
UCHAR *pucCopyEnd;
RING_BUFFER_S *pstRingBuffer;
/* 函数参数合法性检查 */
if ((NULL_PTR == pRingBuffer) || (NULL_PTR == pFrameBuffer) || (NULL_PTR == pulFrameBufferLen))
{
return VOS_ERR;
}
pstRingBuffer = (RING_BUFFER_S *)pRingBuffer;
/* 获取环形缓冲区已用空间 */
ulUsedRingBufferSize = VOS_GetUsedRingBufferSize(pstRingBuffer);
/* 环形缓冲区无使用空间,不存在用户数据 */
if (0 == ulUsedRingBufferSize)
{
return VOS_ERR;
}
/* 读取TL字段 */
pucCopyEnd = VOS_SmartCopyFromBuffer(pstRingBuffer->aucBuffer,
sizeof(pstRingBuffer->aucBuffer),
pstRingBuffer->pucReadCursor,
(UCHAR *)(&stTlv),
SIZE_OF_TL);
if (stTlv.ucType != pstRingBuffer->ucType)
{
return VOS_ERR;
}
pstRingBuffer->pucReadCursor = pucCopyEnd;
pstRingBuffer->ulUsedBufferSize -= SIZE_OF_TL;
/* 读取用户数据 */
ulFrameBufferLen = (stTlv.ucLen1 << 24) + (stTlv.ucLen2 << 16) + (stTlv.ucLen3 << 8) + (stTlv.ucLen4 << 0);
pucCopyEnd = VOS_SmartCopyFromBuffer(pstRingBuffer->aucBuffer,
sizeof(pstRingBuffer->aucBuffer),
pstRingBuffer->pucReadCursor,
(UCHAR *)(pFrameBuffer),
ulFrameBufferLen);
pstRingBuffer->pucReadCursor = pucCopyEnd;
pstRingBuffer->ulUsedBufferSize -= ulFrameBufferLen;
/* 回填返回数据大小 */
*pulFrameBufferLen = ulFrameBufferLen;
return VOS_OK;
}