blob: 5032f2f4e250fd83fb007646033d03e77a75e464 [file] [log] [blame]
/************************************************************************
* °æÈ¨ËùÓÐ (C)2008, ÉîÛÚÊÐÖÐÐËͨѶ¹É·ÝÓÐÏÞ¹«Ë¾¡£
*
* ÎļþÃû³Æ£º soft_timer.c
* Îļþ±êʶ£º
* ÄÚÈÝÕªÒª£º ¶¨ÒåͨÓõÄÈí¼þ¶¨Ê±Æ÷Ï߳̿â
* ÆäËü˵Ã÷£º
* µ±Ç°°æ±¾£º V1.0
* ×÷ Õߣº Ö£ÓñæÃ
* Íê³ÉÈÕÆÚ£º 2010-09-02
*
* Ð޸ļǼ1£º
* ÐÞ¸ÄÈÕÆÚ£º2010-09-02
* °æ ±¾ ºÅ£ºV1.0
* ÐÞ ¸Ä ÈË£ºÖ£ÓñæÃ
* ÐÞ¸ÄÄÚÈÝ£º³õʼ°æ±¾
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/time.h>
#include <syslog.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "soft_timer.h"
/*
#define SOFT_TIMER_DEBUG 1
*/
/********************************************
* Macro declaration
*******************************************/
#define NEW_TIMER_STEP 10
#define MAX_TIMER_POOL_NUM 33
/********************************************
* static variables
*******************************************/
static SOFT_TIMER g_timer_pool[MAX_TIMER_POOL_NUM] = {0};
static SOFT_TIMER *g_pTimerHeader = NULL;
static int g_timer_initialized = 0;
pthread_mutex_t g_timer_mutex = PTHREAD_MUTEX_INITIALIZER;
static void* SoftTimer_Loop(void *args);
/********************************************
* SoftTimer_Init
* initialize global variables
*******************************************/
static int SoftTimer_Init(void)
{
int result = 0;
pthread_attr_t attribute;
pthread_t stHandle;
if(0 == g_timer_initialized)
{
g_timer_initialized = 1;
pthread_attr_init(&attribute);
pthread_attr_setstacksize(&attribute, 32*1024);
#ifdef SOFT_TIMER_DEBUG
printf("Create soft timer first time, must create a thread now!\n");
#endif
result = pthread_create(&stHandle, &attribute, SoftTimer_Loop, NULL);
if(0 != result)
{
#ifdef SOFT_TIMER_DEBUG
printf("StartSoftTimer failed, create thread fail %d!\n", result);
#endif
return ERROR;
}
g_pTimerHeader = &g_timer_pool[0];
g_pTimerHeader->next = g_pTimerHeader;
g_pTimerHeader->prev = g_pTimerHeader;
g_pTimerHeader->used = 1;
}
return OK;
}
/********************************************
* SetBasicTimerEx
* call [setitimer] to set basic timer
*******************************************/
static void SetBasicTimerEx(int value)
{
struct itimerval stTimer = {0};
struct itimerval oldTimer = {0};
#ifdef SOFT_TIMER_DEBUG
printf("SetBasicTimerEx: value=%d\n", value);
#endif
stTimer.it_value.tv_sec = value / 1000;
stTimer.it_value.tv_usec = (value * 1000) % 1000000;
//stTimer.it_interval.tv_sec = stTimer.it_value.tv_sec;
//stTimer.it_interval.tv_usec = stTimer.it_value.tv_usec;
setitimer(ITIMER_REAL, &stTimer, &oldTimer);
#ifdef SOFT_TIMER_DEBUG
printf("SetBasicTimerEx: tv_sec=%d, tv_usec=%d\n", stTimer.it_value.tv_sec, stTimer.it_value.tv_usec);
printf("SetBasicTimerEx:oldTimer tv_sec=%d, tv_usec=%d\n", oldTimer.it_value.tv_sec, oldTimer.it_value.tv_usec);
#endif
}
/********************************************
* SoftTimer_Add
* add a soft timer to double linked list
*******************************************/
static int SoftTimer_Add(SOFT_TIMER *pHeader, SOFT_TIMER *pItem)
{
SOFT_TIMER *pTmp = pHeader;
if(NULL == pHeader || NULL == pItem)
{
return -1;
}
do
{
if(pTmp->timerValue <= pItem->timerValue)
{
pTmp = pTmp->next;
}
else
{
break;
}
} while(pTmp != pHeader);
if(pTmp != pHeader)
{
pItem->next = pTmp;
pItem->prev = pTmp->prev;
pTmp->prev->next = pItem;
pTmp->prev = pItem;
}
else
{
pItem->next = pTmp;
pItem->prev = pTmp->prev;
pTmp->prev->next = pItem;
pTmp->prev = pItem;
}
return 0;
}
/********************************************
* SoftTimer_Delete
* delete a soft timer from double linked list
*******************************************/
static int SoftTimer_Delete(SOFT_TIMER *pHeader, SOFT_TIMER *pItem)
{
if(NULL == pHeader || NULL == pItem)
{
return -1;
}
if(pItem == pHeader)
{
return 0;
}
pItem->prev->next = pItem->next;
pItem->next->prev = pItem->prev;
return 0;
}
/********************************************
* SoftTimer_GetSize
* get total size of double linked list
*******************************************/
static int SoftTimer_GetSize(SOFT_TIMER *pHeader)
{
int size = 0;
SOFT_TIMER *pTmp = pHeader->next;
while(pTmp != pHeader)
{
size++;
pTmp = pTmp->next;
}
#ifdef SOFT_TIMER_DEBUG
printf("SoftTimer_GetSize: size=%d\n", size);
#endif
return size;
}
/********************************************
* SoftTimer_Adjust
* adjust soft-timer's value in the double linked list
*******************************************/
static int SoftTimer_AdjustTimerValue(SOFT_TIMER *pHeader, int value)
{
SOFT_TIMER *pTmp = pHeader->next;
while(pTmp != pHeader)
{
pTmp->timerValue -= value;
pTmp = pTmp->next;
}
return 0;
}
/********************************************
* SoftTimer_Handler
* handler of soft-timer
*******************************************/
static void SoftTimer_Handler(void)
{
int index;
SOFT_TIMER *pHeader = g_pTimerHeader;
SOFT_TIMER *pTmp = pHeader->next;
unsigned int curTime = 0;
curTime = (pTmp != pHeader?pTmp->timerValue:0);
#ifdef SOFT_TIMER_DEBUG
printf("SoftTimer_Ops: curTime=%d\n", curTime);
#endif
pthread_mutex_lock(&g_timer_mutex);
while(pTmp != pHeader)
{
pTmp->timerValue -= curTime;
if(pTmp->timerValue <= 0)
{
pTmp->procCallBack(pTmp->args);
if(TIMER_FLAG_RESTART == pTmp->ucFlag)
{
pTmp->timerValue = pTmp->ulNextInterval;
}
else
{
pTmp->timerValue = -1;
}
pTmp->done = 1;
}
pTmp = pTmp->next;
}
#ifdef SOFT_TIMER_DEBUG
printf("SoftTimer_Ops:[1] %d\n", SoftTimer_GetSize(pHeader));
#endif
for(index = 1; index < MAX_TIMER_POOL_NUM; index++)
{
if(g_timer_pool[index].used && g_timer_pool[index].done)
{
g_timer_pool[index].done = 0;
SoftTimer_Delete(pHeader, &g_timer_pool[index]);
if(g_timer_pool[index].timerValue > 0)
{
SoftTimer_Add(pHeader, &g_timer_pool[index]);
}
else
{
memset(&g_timer_pool[index], 0, sizeof(SOFT_TIMER));
}
}
}
#ifdef SOFT_TIMER_DEBUG
printf("SoftTimer_Ops:[2] %d\n", SoftTimer_GetSize(pHeader));
#endif
SetBasicTimerEx(pHeader->next->timerValue);
pthread_mutex_unlock(&g_timer_mutex);
#ifdef SOFT_TIMER_DEBUG
printf("SoftTimer_Ops: nextTime=%d\n", pHeader->next->timerValue);
#endif
return;
}
/********************************************
* SoftTimer_Loop
* A thread entry for soft-timer!
*******************************************/
static void* SoftTimer_Loop(void *args)
{
struct sigaction act;
act.sa_handler =(void*) SoftTimer_Handler;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
sigaction(SIGALRM, &act, NULL);
while(1)
{
pause();
}
}
static void SoftTimer_Process(int freeIndex)
{
ULONG ulResidue = 0;
ULONG ulQuotient = 0;
int oldTimeValue = 0;
int leftTimeValue = 0;
struct itimerval stTimer = {0};
if(0 == SoftTimer_GetSize(g_pTimerHeader))
{
SoftTimer_Add(g_pTimerHeader, &( g_timer_pool[freeIndex]));
SetBasicTimerEx(g_pTimerHeader->next->timerValue);
}
else
{
oldTimeValue = g_pTimerHeader->next->timerValue;
if(oldTimeValue > 0)
{
#ifdef SOFT_TIMER_DEBUG
printf("CreateSoftTimer: oldTimeValue=%d\n", oldTimeValue);
#endif
getitimer(ITIMER_REAL, &stTimer);
#ifdef SOFT_TIMER_DEBUG
printf("CreateSoftTimer: tv_sec=%d, tv_usec=%d\n", stTimer.it_value.tv_sec, stTimer.it_value.tv_usec);
#endif
leftTimeValue = stTimer.it_value.tv_sec * 1000 + (stTimer.it_value.tv_usec/1000);
ulResidue = leftTimeValue % NEW_TIMER_STEP;
if (0 != ulResidue)
{
ulQuotient = leftTimeValue / NEW_TIMER_STEP;
leftTimeValue = (ulQuotient + 1) * NEW_TIMER_STEP;
}
#ifdef SOFT_TIMER_DEBUG
printf("CreateSoftTimer: oldTimeValue=%d, leftTimeValue=%d\n", oldTimeValue, leftTimeValue);
#endif
if(oldTimeValue - leftTimeValue >= NEW_TIMER_STEP)
{
SoftTimer_AdjustTimerValue(g_pTimerHeader, oldTimeValue - leftTimeValue);
}
SoftTimer_Add(g_pTimerHeader, &( g_timer_pool[freeIndex]));
SetBasicTimerEx(g_pTimerHeader->next->timerValue);
}
}
}
/********************************************
* CreateSoftTimer
* create a new soft-timer!
*******************************************/
LONG CreateSoftTimer(USHORT usTimerID,
UCHAR ucFlag,
ULONG ulInterval,
void * (*procCallBack)(void *),
void *args)
{
int ucIndex = 0;
int freeIndex = 0;
ULONG ulResidue = 0;
ULONG ulQuotient = 0;
if (NULL == procCallBack)
{
#ifdef SOFT_TIMER_DEBUG
printf("CreateSoftTimer failed, procCallBack is NULL!\n");
#endif
return ERROR;
}
pthread_mutex_lock(&g_timer_mutex);
if(OK != SoftTimer_Init())
{
pthread_mutex_unlock(&g_timer_mutex);
return ERROR;
}
for(ucIndex = 1, freeIndex = 0; ucIndex < MAX_TIMER_POOL_NUM; ucIndex++)
{
/*same timer id exist, warning, return error*/
if (g_timer_pool[ucIndex].used && (usTimerID == g_timer_pool[ucIndex].usTimerID))
{
#ifdef SOFT_TIMER_DEBUG
printf("Same timer id 0x%04x exist!\n", usTimerID);
#endif
pthread_mutex_unlock(&g_timer_mutex);
return ERROR;
}
if ((0 == g_timer_pool[ucIndex].used) && (0 == freeIndex))
{
freeIndex = ucIndex;
}
}
/* No empty timer left */
if (0 == freeIndex)
{
#ifdef SOFT_TIMER_DEBUG
printf("StartSoftTimer 0x%04x failed, queue full!\n", usTimerID);
#endif
pthread_mutex_unlock(&g_timer_mutex);
return ERROR;
}
/* Adjust interval value, it must multiple of 10 */
ulResidue = ulInterval % NEW_TIMER_STEP;
if (0 != ulResidue)
{
ulQuotient = ulInterval / NEW_TIMER_STEP;
ulInterval = (ulQuotient + 1) * NEW_TIMER_STEP;
}
g_timer_pool[freeIndex].used = 1;
g_timer_pool[freeIndex].usTimerID = usTimerID;
g_timer_pool[freeIndex].ucFlag = ucFlag;
g_timer_pool[freeIndex].ulCurInterval = ulInterval;
g_timer_pool[freeIndex].ulNextInterval = ulInterval;
g_timer_pool[freeIndex].procCallBack = procCallBack;
g_timer_pool[freeIndex].args = args;
g_timer_pool[freeIndex].timerValue = ulInterval;
SoftTimer_Process(freeIndex);
#ifdef SOFT_TIMER_DEBUG
printf("CreateSoftTimer index %d success: \n"
"usTimerID = %d, \n"
"ucFlag = %d, \n"
"ulCurInterval = %ld, \n"
"ulNextInterval = %ld, \n"
"procCallBack = %p, \n"
"args = %p. \n",
freeIndex,
usTimerID,
ucFlag,
ulInterval,
ulInterval,
procCallBack,
args);
#endif
pthread_mutex_unlock(&g_timer_mutex);
return OK;
}
/********************************************
* DeleteSoftTimer
* delete a soft-timer!
*******************************************/
LONG DeleteSoftTimer(USHORT usTimerID)
{
UCHAR ucIndex = 0;
pthread_mutex_lock(&g_timer_mutex);
for(ucIndex = 1; ucIndex < MAX_TIMER_POOL_NUM; ucIndex++)
{
if(g_timer_pool[ucIndex].used && (usTimerID == g_timer_pool[ucIndex].usTimerID))
{
break;
}
}
if (ucIndex >= MAX_TIMER_POOL_NUM)
{
#ifdef SOFT_TIMER_DEBUG
printf("DeleteSoftTimer 0x%04x failed, not exist!\n", usTimerID);
#endif
pthread_mutex_unlock(&g_timer_mutex);
return ERROR;
}
SoftTimer_Delete(g_pTimerHeader, &( g_timer_pool[ucIndex]));
memset(&g_timer_pool[ucIndex], 0, sizeof(SOFT_TIMER));
#ifdef SOFT_TIMER_DEBUG
printf("DeleteSoftTimer 0x%04x success!\n", usTimerID);
#endif
pthread_mutex_unlock(&g_timer_mutex);
return OK;
}