| /************************************************************************ |
| * °æÈ¨ËùÓÐ (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; |
| } |