头文件
#ifndef QUEUE_H_H
#define QUEUE_H_H
#define UINT unsigned int
typedef void *HTWOBUFQUEUE;
//帧头结构
typedef struct QUEUENODE
{
char* head; //帧头本身数据
char* data;
UINT dataSize; //数据大小,不固定
}QUEUENODE_T, *PQUEUENODE_T;
/*-------------队列接口函数--------------*/
/*
* 函 数:CreateQueue(),创建队列
* 参 数:headNum,包数;headSize,帧头数据大小(可变部分大小),不是帧头大小;dataSize,数据平均大小
* 返回值:成功返回所创建的队列句柄,失败返回NULL
* 说 明:队列包含两个缓冲区,大小是分别:headNum * headSize,headNum * dataSize;
*/
HTWOBUFQUEUE CreateQueue(int headNum, int headSize, int dataSize);
int DestroyQueue(HTWOBUFQUEUE hq);
/*--------------------------------------*/
/*
* 函 数:PushQueue()进队,使用时必须先创建队列
* 参 数:hq,已创建的队列句柄;qHead,帧头指针
* 返回值:成功返回0,失败返回-1
*/
int PushQueue(HTWOBUFQUEUE hq, PQUEUENODE_T qHead);
/*
* 函 数:PushQueue()进队,使用时必须先创建队列
* 参 数:hq,已创建的队列句柄;qHead,帧头指针;qHeadLen,qHead内存大小需大于队首元素大小
* 返回值:失败返回-1,成功返回0,qHead中返回获取到的队首元素
*/
int PopQueue(HTWOBUFQUEUE hq, PQUEUENODE_T qHead, UINT qHeadLen);
/*
* 函 数:ClearQueue(),清空队列,使用时必须先创建队列
* 返回值:成功返回0,失败返回-1
*/
int ClearQueue(HTWOBUFQUEUE hq);
/*
* 函 数:IfQueueEmpty()判断队列是否为空,为空返回1,否则返回0
* 返回值:队列为空返回1,否则返回0
*/
int IfQueueEmpty(HTWOBUFQUEUE hq);
/*--------------------------------------*/
/*
* 函 数:GetQueueMaxCount()获取队列可容纳的最大包数
* GetQueueCount()获取队列中的包数
* GetQueueFreeCount()获取队列当前还可以容纳的包数,可判断队列是否已满
* GetQueueMaxDataSize()获取队列可容纳数据的最大内存空间(以byte为单位)
* GetQueueFreeDataLen()获取队列当前剩余的内存空间
*/
UINT GetQueueMaxCount(HTWOBUFQUEUE hq);
UINT GetQueueCount(HTWOBUFQUEUE hq);
UINT GetQueueFreeCount(HTWOBUFQUEUE hq);
UINT GetQueueMaxDataSize(HTWOBUFQUEUE hq);
UINT GetQueueFreeDataSize(HTWOBUFQUEUE hq);
/*--------------------------------------*/
/*
* 函 数:GetQueueHeadSize()获取队列帧头大小,因为队列结点中没有此数据结构
* GetQueueHeadDataLen()获取队列队首的数据大小
* 说 明:这些函数不是必需的,可以废弃
*/
UINT GetQueueHeadSize(HTWOBUFQUEUE hq);
UINT GetQueueHeadDataLen(HTWOBUFQUEUE hq);
#endif
/*-------------------------------------------------------------------------------------*/
源文件
#include <tmStdLib.h>
#include <stdio.h>
#include "string.h"
#include <tmosal.h>
#include "Queue.h"
typedef struct PACKQUEUE
{
//队列帧结构PQUEUENODE_T,由帧结点可得到帧头数据和可用数据位置
PQUEUENODE_T fst; //队列帧头
PQUEUENODE_T lst; //队列帧尾
//队列帧buffer和数据buffer起始位置
char* head;
char* data;
char* lstData; //数据队尾指针,push使用
//不变值
UINT headVarSize; //单个桢头可变部分大小
UINT headSize; //帧头大小 = headVarSize + sizeof(QUEUENODE_T)
UINT headMaxNum; //队列最大帧头数量
UINT averDataSize; //队列平均数据大小
UINT dataMaxSize; //队列最大可容纳数据大小 = averDataSize * headMaxNum
//変值
UINT curHeadCount; //当前队列包数,即帧头数
UINT freeHeadCount;
//---
UINT curDataLen; //当前队列数据大小,以byte为单位
UINT freeDataSize;
//---
UINT fstHeadToEndCount; //fst->head距离队列缓冲区结束点距离(以帧数为单位)
UINT fstDataToEndSize; //fst->data距离队列缓冲区结束点距离(以byte为单位)
UINT lstHeadToEndCount; //lst->head距离队列缓冲区结束点距离(以帧数为单位)
UINT lstDataToEndSize; //lst->data距离队列缓冲区结束点距离(以byte为单位)
tmosalMutexHandle_t tmQueueLock; //queue lock
}PACKQUEUE_T, *PPACKQUEUE_T;
void InitQueue(PPACKQUEUE_T q, int headNum, int headSize, int dataSize);
//参数: dataSize---表示队列data的平均大小
HTWOBUFQUEUE CreateQueue(int headNum, int headSize, int dataSize)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = NULL;
if(headSize < sizeof(QUEUENODE_T))
{
printf("CreateQueue() err: headSize is too small, headsize > %d", sizeof(QUEUENODE_T));
return NULL;
}
q = (PPACKQUEUE_T)malloc(sizeof(PACKQUEUE_T));
if(q == NULL)
{
printf("CreateQueue() err: malloc queue fail!/n");
return NULL;
}
q->head = (char*)malloc(headNum * headSize);
if(q->head == NULL)
{
printf("CreateQueue() err: malloc head fail!/n");
free(q);
return NULL;
}
q->data = (char*)malloc(headNum * dataSize);
if(q->data == NULL)
{
printf("CreateQueue() err: malloc data fail!/n");
free(q->head);
free(q);
return NULL;
}
//--------------------
rval = tmosalMutexCreate(&q->tmQueueLock, tmosalMutexCreateFlagNone);
if(TM_OK != rval)
{
free(q->head);
free(q->data);
free(q);
printf("CreateQueue() err: Create Mutex fail!/n");
return NULL;
}
//--------------------
InitQueue(q, headNum, headSize, dataSize);
return (HTWOBUFQUEUE)q;
}
void InitQueue(PPACKQUEUE_T q, int headNum, int headSize, int dataSize)
{
q->headSize = headSize;
q->headVarSize = headSize - sizeof(QUEUENODE_T);
q->headMaxNum = q->freeHeadCount = q->fstHeadToEndCount = q->lstHeadToEndCount = headNum;
q->dataMaxSize = q->freeDataSize = q->fstDataToEndSize = q->lstDataToEndSize = dataSize * headNum;
q->averDataSize = dataSize;
q->curHeadCount = 0;
q->curDataLen = 0;
q->fst = q->lst = (PQUEUENODE_T)q->head;
q->fst->head = q->lst->head = q->head + sizeof(QUEUENODE_T);
q->fst->data = q->lst->data = q->lstData = q->data;
}
//-------------------
int DestroyQueue(HTWOBUFQUEUE hq)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = (PPACKQUEUE_T)hq;
if(q == NULL)
{
return 0;
}
if(q->head != NULL)
{
free(q->head);
q->head = NULL;
}
if(q->data != NULL)
{
free(q->data);
q->data = NULL;
}
//------------------
rval = tmosalMutexDestroy(q->tmQueueLock);
if(TM_OK != rval)
{
printf("DestroyQueue() err: destroy Mutex fail!/n");
return -1;
}
//------------------
free(q);
q = NULL;
return 0;
}
//----------------------
int PushQueue(HTWOBUFQUEUE hq, PQUEUENODE_T qHead)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = NULL;
int ret = 0;
//error check
if(hq == NULL || qHead == NULL)
{
printf("PushQueue() err: HTWOBUFQUEUE is NULL, queue is NULL!/n");
return -1;
}
q = (PPACKQUEUE_T)hq;
rval = tmosalMutexEnter(q->tmQueueLock, Null); //ENTER MUTEX
if(TM_OK != rval)
{
printf("PushQueue() err: enter Mutex fail/n");
return -1;
}
//check queue free space
if(q->freeHeadCount <= 0 || q->freeDataSize < qHead->dataSize)
{
printf("PushQueue() err: queue is full or dataSize is too large! freeHeadCount = %d, freeData = %d(b)/n", q->freeHeadCount, q->freeDataSize);
ret = -1;
}
else
{
//qHead进队
memcpy(q->lst->head, qHead->head, q->headVarSize); //帧头可变数据部分
q->lst->data = q->lstData;
if(qHead->dataSize > q->lstDataToEndSize) //the end of q->data
{
UINT dataOverLen = qHead->dataSize - q->lstDataToEndSize;
//printf("****************push to end!...dataOverLen = %d, freeHeadCount = %d, freeDataLen = %d/n", dataOverLen, q->freeHeadCount, q->freeDataSize);
memcpy(q->lst->data, qHead->data, q->lstDataToEndSize);
memcpy(q->data, qHead->data + q->lstDataToEndSize, dataOverLen);
q->lstDataToEndSize = q->dataMaxSize - dataOverLen;
}
else
{
memcpy(q->lst->data, qHead->data, qHead->dataSize);
if((q->lstDataToEndSize -= qHead->dataSize) == 0) //the end of q->data
{
q->lstDataToEndSize = q->dataMaxSize;
}
}
q->lst->dataSize = qHead->dataSize;
q->curHeadCount++;
q->freeHeadCount--;
q->curDataLen += q->lst->dataSize;
q->freeDataSize -= q->lst->dataSize;
//lst后移
if(--(q->lstHeadToEndCount) == 0) //the end of head
{
q->lst = (PQUEUENODE_T)q->head;
q->lstHeadToEndCount = q->headMaxNum;
}
else
{
q->lst = (PQUEUENODE_T)((char*)q->lst + q->headSize);
}
q->lst->head = (char*)q->lst + sizeof(QUEUENODE_T);
q->lstData = q->data + (q->dataMaxSize - q->lstDataToEndSize);
}
rval = tmosalMutexExit(q->tmQueueLock); //EXIT MUTEX
if(TM_OK != rval)
{
printf("PushQueue() err: exit Mutex fail/n");
return -1;
}
return ret;
}
//-------------------
//出队,qHeadLen是qHead指针所的缓冲区大小
int PopQueue(HTWOBUFQUEUE hq, PQUEUENODE_T qHead, UINT qHeadLen)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = NULL;
int ret = 0;
if(hq == NULL || qHead == NULL)
{
printf("PopQueue() err: HTWOBUFQUEUE is NULL, queue is NULL!/n");
return -1;
}
q = (PPACKQUEUE_T)hq;
rval = tmosalMutexEnter(q->tmQueueLock, Null); //ENTER MUTEX
if(TM_OK != rval)
{
printf("PopQueue() err: enter Mutex fail/n");
return -1;
}
//--------
if(q->curHeadCount == 0)
{
printf("PopQueue() err: queue is empty!/n");
ret = -1;
}
else if(qHeadLen < (q->fst->dataSize + q->headSize))
{
printf("PopQueue() err: qHeadLen is too small, minSize = %d(b)/n", q->fst->dataSize + q->headSize);
ret = -1;
}
else
{
memset(qHead, 0, qHeadLen);
qHead->head = (char*)qHead + sizeof(QUEUENODE_T);
qHead->data = (char*)qHead + q->headSize;
qHead->dataSize = q->fst->dataSize;
//拷贝数据
memcpy(qHead->head, q->fst->head, q->headVarSize);
if(qHead->dataSize <= q->fstDataToEndSize) //data是否跨尾
{
//no
memcpy(qHead->data, q->fst->data, qHead->dataSize);
if((q->fstDataToEndSize -= qHead->dataSize) == 0) //进队后data到达队列边界
{
q->fstDataToEndSize = q->dataMaxSize;
}
}
else
{
//yes
UINT dataOverLen = qHead->dataSize - q->fstDataToEndSize;
memcpy(qHead->data, q->fst->data, q->fstDataToEndSize);
memcpy(qHead->data + q->fstDataToEndSize, q->data, dataOverLen);
q->fstDataToEndSize = q->dataMaxSize - dataOverLen;
//printf("******************pop end!/n");
}
q->curHeadCount--;
q->freeHeadCount++;
q->curDataLen -= q->fst->dataSize;
q->freeDataSize += q->fst->dataSize;
//fst后移
if(--(q->fstHeadToEndCount) == 0) //if the end of head
{
q->fst = (PQUEUENODE_T)q->head;
q->fstHeadToEndCount = q->headMaxNum;
}
else
{
q->fst = (PQUEUENODE_T)((char*)q->fst + q->headSize);
}
q->fst->head = (char*)q->fst + sizeof(QUEUENODE_T);
q->fst->data = q->data + (q->dataMaxSize - q->fstDataToEndSize);
}
rval = tmosalMutexExit(q->tmQueueLock); //EXIT MUTEX
if(TM_OK != rval)
{
printf("PopQueue() err: exit Mutex fail/n");
return -1;
}
return 0;
}
int ClearQueue(HTWOBUFQUEUE hq)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = Null;
if(hq == NULL)
{
return -1;
}
q = (PPACKQUEUE_T)hq;
rval = tmosalMutexEnter(q->tmQueueLock, Null); /* ENTER MUTEX */
if(TM_OK != rval)
{
printf("ClearQueue() err: enter Mutex fail/n");
return -1;
}
if(q->curHeadCount != 0)
{
q->curHeadCount = 0;
q->freeHeadCount = q->fstHeadToEndCount = q->lstHeadToEndCount = q->headMaxNum;
q->curDataLen = 0;
q->freeDataSize = q->fstDataToEndSize = q->lstDataToEndSize = q->dataMaxSize;
q->fst = q->lst = (PQUEUENODE_T)q->head;
q->fst->head = q->lst->head = q->head + sizeof(QUEUENODE_T);
q->fst->data = q->lst->data = q->lstData = q->data;
}
rval = tmosalMutexExit(q->tmQueueLock); /* EXIT MUTEX */
if(TM_OK != rval)
{
printf("ClearQueue() err: exit Mutex fail/n");
return -1;
}
return 0;
}
int IfQueueEmpty(HTWOBUFQUEUE hq)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = NULL;
int ret = -1;
if(q == NULL)
{
return -1;
}
q = (PPACKQUEUE_T)hq;
rval = tmosalMutexEnter(q->tmQueueLock, Null); /* ENTER MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: enter Mutex fail/n");
return -1;
}
ret = (q->curDataLen == 0);
rval = tmosalMutexExit(q->tmQueueLock); /* EXIT MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: exit Mutex fail/n");
return -1;
}
return ret;
}
UINT GetQueueMaxCount(HTWOBUFQUEUE hq)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = NULL;
UINT ret = 0;
if(q == NULL)
{
return 0;
}
q = (PPACKQUEUE_T)hq;
rval = tmosalMutexEnter(q->tmQueueLock, Null); /* ENTER MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: enter Mutex fail/n");
return 0;
}
ret = q->headMaxNum;
rval = tmosalMutexExit(q->tmQueueLock); /* EXIT MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: exit Mutex fail/n");
return 0;
}
return ret;
}
UINT GetQueueCount(HTWOBUFQUEUE hq)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = NULL;
UINT ret = 0;
if(q == NULL)
{
return 0;
}
q = (PPACKQUEUE_T)hq;
rval = tmosalMutexEnter(q->tmQueueLock, Null); /* ENTER MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: enter Mutex fail/n");
return 0;
}
ret = q->curHeadCount;
rval = tmosalMutexExit(q->tmQueueLock); /* EXIT MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: exit Mutex fail/n");
return 0;
}
return ret;
}
//可以用来判断队列是否已满,有可能队列未满,但是放不下较大的数据,可以用GetQueueFreeDataLen()查看
UINT GetQueueFreeCount(HTWOBUFQUEUE hq)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = NULL;
UINT ret = 0;
if(q == NULL)
{
return 0;
}
q = (PPACKQUEUE_T)hq;
rval = tmosalMutexEnter(q->tmQueueLock, Null); /* ENTER MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: enter Mutex fail/n");
return 0;
}
ret = q->freeHeadCount;
rval = tmosalMutexExit(q->tmQueueLock); /* EXIT MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: exit Mutex fail/n");
return 0;
}
return ret;
}
UINT GetQueueMaxDataSize(HTWOBUFQUEUE hq)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = NULL;
UINT ret = 0;
if(q == NULL)
{
return 0;
}
q = (PPACKQUEUE_T)hq;
rval = tmosalMutexEnter(q->tmQueueLock, Null); /* ENTER MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: enter Mutex fail/n");
return 0;
}
ret = q->dataMaxSize;
rval = tmosalMutexExit(q->tmQueueLock); /* EXIT MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: exit Mutex fail/n");
return 0;
}
return ret;
}
UINT GetQueueFreeDataSize(HTWOBUFQUEUE hq)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = NULL;
UINT ret = 0;
if(q == NULL)
{
return 0;
}
q = (PPACKQUEUE_T)hq;
rval = tmosalMutexEnter(q->tmQueueLock, Null); /* ENTER MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: enter Mutex fail/n");
return 0;
}
ret = q->freeDataSize;
rval = tmosalMutexExit(q->tmQueueLock); /* EXIT MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: exit Mutex fail/n");
return 0;
}
return ret;
}
//获取队列帧头大小,因为队列结点中没有此数据结构
UINT GetQueueHeadSize(HTWOBUFQUEUE hq)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = NULL;
UINT ret = 0;
if(q == NULL)
{
return 0;
}
q = (PPACKQUEUE_T)hq;
rval = tmosalMutexEnter(q->tmQueueLock, Null); /* ENTER MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: enter Mutex fail/n");
return 0;
}
ret = q->headSize;
rval = tmosalMutexExit(q->tmQueueLock); /* EXIT MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: exit Mutex fail/n");
return 0;
}
return ret;
}
//获取队列队首的数据大小
UINT GetQueueHeadDataLen(HTWOBUFQUEUE hq)
{
tmErrorCode_t rval = TM_OK;
PPACKQUEUE_T q = NULL;
UINT ret = 0;
if(q == NULL)
{
return 0;
}
q = (PPACKQUEUE_T)hq;
rval = tmosalMutexEnter(q->tmQueueLock, Null); /* ENTER MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: enter Mutex fail/n");
return 0;
}
ret = q->fst->dataSize;
rval = tmosalMutexExit(q->tmQueueLock); /* EXIT MUTEX */
if(TM_OK != rval)
{
printf("PushQueue() err: exit Mutex fail/n");
return 0;
}
return ret;
}