blob: 5032f2f4e250fd83fb007646033d03e77a75e464 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/************************************************************************
2* °æÈ¨ËùÓÐ (C)2008, ÉîÛÚÊÐÖÐÐËͨѶ¹É·ÝÓÐÏÞ¹«Ë¾¡£
3*
4* ÎļþÃû³Æ£º soft_timer.c
5* Îļþ±êʶ£º
6* ÄÚÈÝÕªÒª£º ¶¨ÒåͨÓõÄÈí¼þ¶¨Ê±Æ÷Ï߳̿â
7* ÆäËü˵Ã÷£º
8* µ±Ç°°æ±¾£º V1.0
9* ×÷ Õߣº Ö£ÓñæÃ
10* Íê³ÉÈÕÆÚ£º 2010-09-02
11*
12* Ð޸ļǼ1£º
13* ÐÞ¸ÄÈÕÆÚ£º2010-09-02
14* °æ ±¾ ºÅ£ºV1.0
15* ÐÞ ¸Ä ÈË£ºÖ£ÓñæÃ
16* ÐÞ¸ÄÄÚÈÝ£º³õʼ°æ±¾
17************************************************************************/
18#include <stdio.h>
19#include <stdlib.h>
20#include <signal.h>
21#include <sys/time.h>
22#include <syslog.h>
23#include <fcntl.h>
24#include <pthread.h>
25#include <stdlib.h>
26#include <string.h>
27#include <errno.h>
28#include "soft_timer.h"
29
30/*
31#define SOFT_TIMER_DEBUG 1
32*/
33/********************************************
34 * Macro declaration
35 *******************************************/
36#define NEW_TIMER_STEP 10
37#define MAX_TIMER_POOL_NUM 33
38
39/********************************************
40 * static variables
41 *******************************************/
42static SOFT_TIMER g_timer_pool[MAX_TIMER_POOL_NUM] = {0};
43static SOFT_TIMER *g_pTimerHeader = NULL;
44static int g_timer_initialized = 0;
45
46pthread_mutex_t g_timer_mutex = PTHREAD_MUTEX_INITIALIZER;
47
48static void* SoftTimer_Loop(void *args);
49
50/********************************************
51 * SoftTimer_Init
52 * initialize global variables
53 *******************************************/
54static int SoftTimer_Init(void)
55{
56 int result = 0;
57 pthread_attr_t attribute;
58 pthread_t stHandle;
59
60 if(0 == g_timer_initialized)
61 {
62 g_timer_initialized = 1;
63
64 pthread_attr_init(&attribute);
65 pthread_attr_setstacksize(&attribute, 32*1024);
66
67 #ifdef SOFT_TIMER_DEBUG
68 printf("Create soft timer first time, must create a thread now!\n");
69 #endif
70 result = pthread_create(&stHandle, &attribute, SoftTimer_Loop, NULL);
71 if(0 != result)
72 {
73 #ifdef SOFT_TIMER_DEBUG
74 printf("StartSoftTimer failed, create thread fail %d!\n", result);
75 #endif
76 return ERROR;
77 }
78
79 g_pTimerHeader = &g_timer_pool[0];
80 g_pTimerHeader->next = g_pTimerHeader;
81 g_pTimerHeader->prev = g_pTimerHeader;
82 g_pTimerHeader->used = 1;
83 }
84
85 return OK;
86}
87
88/********************************************
89 * SetBasicTimerEx
90 * call [setitimer] to set basic timer
91 *******************************************/
92static void SetBasicTimerEx(int value)
93{
94 struct itimerval stTimer = {0};
95 struct itimerval oldTimer = {0};
96
97 #ifdef SOFT_TIMER_DEBUG
98 printf("SetBasicTimerEx: value=%d\n", value);
99 #endif
100
101 stTimer.it_value.tv_sec = value / 1000;
102 stTimer.it_value.tv_usec = (value * 1000) % 1000000;
103
104 //stTimer.it_interval.tv_sec = stTimer.it_value.tv_sec;
105 //stTimer.it_interval.tv_usec = stTimer.it_value.tv_usec;
106
107 setitimer(ITIMER_REAL, &stTimer, &oldTimer);
108
109 #ifdef SOFT_TIMER_DEBUG
110 printf("SetBasicTimerEx: tv_sec=%d, tv_usec=%d\n", stTimer.it_value.tv_sec, stTimer.it_value.tv_usec);
111 printf("SetBasicTimerEx:oldTimer tv_sec=%d, tv_usec=%d\n", oldTimer.it_value.tv_sec, oldTimer.it_value.tv_usec);
112 #endif
113}
114
115/********************************************
116 * SoftTimer_Add
117 * add a soft timer to double linked list
118 *******************************************/
119static int SoftTimer_Add(SOFT_TIMER *pHeader, SOFT_TIMER *pItem)
120{
121 SOFT_TIMER *pTmp = pHeader;
122
123 if(NULL == pHeader || NULL == pItem)
124 {
125 return -1;
126 }
127
128 do
129 {
130 if(pTmp->timerValue <= pItem->timerValue)
131 {
132 pTmp = pTmp->next;
133 }
134 else
135 {
136 break;
137 }
138 } while(pTmp != pHeader);
139
140 if(pTmp != pHeader)
141 {
142 pItem->next = pTmp;
143 pItem->prev = pTmp->prev;
144 pTmp->prev->next = pItem;
145 pTmp->prev = pItem;
146 }
147 else
148 {
149 pItem->next = pTmp;
150 pItem->prev = pTmp->prev;
151 pTmp->prev->next = pItem;
152 pTmp->prev = pItem;
153 }
154
155 return 0;
156}
157
158/********************************************
159 * SoftTimer_Delete
160 * delete a soft timer from double linked list
161 *******************************************/
162static int SoftTimer_Delete(SOFT_TIMER *pHeader, SOFT_TIMER *pItem)
163{
164 if(NULL == pHeader || NULL == pItem)
165 {
166 return -1;
167 }
168
169 if(pItem == pHeader)
170 {
171 return 0;
172 }
173
174 pItem->prev->next = pItem->next;
175 pItem->next->prev = pItem->prev;
176
177 return 0;
178}
179
180/********************************************
181 * SoftTimer_GetSize
182 * get total size of double linked list
183 *******************************************/
184static int SoftTimer_GetSize(SOFT_TIMER *pHeader)
185{
186 int size = 0;
187 SOFT_TIMER *pTmp = pHeader->next;
188
189 while(pTmp != pHeader)
190 {
191 size++;
192 pTmp = pTmp->next;
193 }
194
195 #ifdef SOFT_TIMER_DEBUG
196 printf("SoftTimer_GetSize: size=%d\n", size);
197 #endif
198 return size;
199}
200
201/********************************************
202 * SoftTimer_Adjust
203 * adjust soft-timer's value in the double linked list
204 *******************************************/
205static int SoftTimer_AdjustTimerValue(SOFT_TIMER *pHeader, int value)
206{
207 SOFT_TIMER *pTmp = pHeader->next;
208
209 while(pTmp != pHeader)
210 {
211 pTmp->timerValue -= value;
212 pTmp = pTmp->next;
213 }
214 return 0;
215}
216
217/********************************************
218 * SoftTimer_Handler
219 * handler of soft-timer
220 *******************************************/
221static void SoftTimer_Handler(void)
222{
223 int index;
224 SOFT_TIMER *pHeader = g_pTimerHeader;
225 SOFT_TIMER *pTmp = pHeader->next;
226 unsigned int curTime = 0;
227
228 curTime = (pTmp != pHeader?pTmp->timerValue:0);
229
230 #ifdef SOFT_TIMER_DEBUG
231 printf("SoftTimer_Ops: curTime=%d\n", curTime);
232 #endif
233
234 pthread_mutex_lock(&g_timer_mutex);
235
236 while(pTmp != pHeader)
237 {
238 pTmp->timerValue -= curTime;
239 if(pTmp->timerValue <= 0)
240 {
241 pTmp->procCallBack(pTmp->args);
242
243 if(TIMER_FLAG_RESTART == pTmp->ucFlag)
244 {
245 pTmp->timerValue = pTmp->ulNextInterval;
246 }
247 else
248 {
249 pTmp->timerValue = -1;
250 }
251 pTmp->done = 1;
252 }
253 pTmp = pTmp->next;
254 }
255
256 #ifdef SOFT_TIMER_DEBUG
257 printf("SoftTimer_Ops:[1] %d\n", SoftTimer_GetSize(pHeader));
258 #endif
259
260 for(index = 1; index < MAX_TIMER_POOL_NUM; index++)
261 {
262 if(g_timer_pool[index].used && g_timer_pool[index].done)
263 {
264 g_timer_pool[index].done = 0;
265
266 SoftTimer_Delete(pHeader, &g_timer_pool[index]);
267
268 if(g_timer_pool[index].timerValue > 0)
269 {
270 SoftTimer_Add(pHeader, &g_timer_pool[index]);
271 }
272 else
273 {
274 memset(&g_timer_pool[index], 0, sizeof(SOFT_TIMER));
275 }
276 }
277 }
278
279 #ifdef SOFT_TIMER_DEBUG
280 printf("SoftTimer_Ops:[2] %d\n", SoftTimer_GetSize(pHeader));
281 #endif
282
283 SetBasicTimerEx(pHeader->next->timerValue);
284
285 pthread_mutex_unlock(&g_timer_mutex);
286
287 #ifdef SOFT_TIMER_DEBUG
288 printf("SoftTimer_Ops: nextTime=%d\n", pHeader->next->timerValue);
289 #endif
290
291 return;
292}
293
294/********************************************
295 * SoftTimer_Loop
296 * A thread entry for soft-timer!
297 *******************************************/
298static void* SoftTimer_Loop(void *args)
299{
300 struct sigaction act;
301
302 act.sa_handler =(void*) SoftTimer_Handler;
303 act.sa_flags = 0;
304 sigemptyset(&act.sa_mask);
305 sigaction(SIGALRM, &act, NULL);
306
307 while(1)
308 {
309 pause();
310 }
311}
312
313static void SoftTimer_Process(int freeIndex)
314{
315 ULONG ulResidue = 0;
316 ULONG ulQuotient = 0;
317 int oldTimeValue = 0;
318 int leftTimeValue = 0;
319
320 struct itimerval stTimer = {0};
321
322 if(0 == SoftTimer_GetSize(g_pTimerHeader))
323 {
324 SoftTimer_Add(g_pTimerHeader, &( g_timer_pool[freeIndex]));
325 SetBasicTimerEx(g_pTimerHeader->next->timerValue);
326 }
327 else
328 {
329 oldTimeValue = g_pTimerHeader->next->timerValue;
330 if(oldTimeValue > 0)
331 {
332 #ifdef SOFT_TIMER_DEBUG
333 printf("CreateSoftTimer: oldTimeValue=%d\n", oldTimeValue);
334 #endif
335 getitimer(ITIMER_REAL, &stTimer);
336 #ifdef SOFT_TIMER_DEBUG
337 printf("CreateSoftTimer: tv_sec=%d, tv_usec=%d\n", stTimer.it_value.tv_sec, stTimer.it_value.tv_usec);
338 #endif
339 leftTimeValue = stTimer.it_value.tv_sec * 1000 + (stTimer.it_value.tv_usec/1000);
340
341 ulResidue = leftTimeValue % NEW_TIMER_STEP;
342 if (0 != ulResidue)
343 {
344 ulQuotient = leftTimeValue / NEW_TIMER_STEP;
345 leftTimeValue = (ulQuotient + 1) * NEW_TIMER_STEP;
346 }
347 #ifdef SOFT_TIMER_DEBUG
348 printf("CreateSoftTimer: oldTimeValue=%d, leftTimeValue=%d\n", oldTimeValue, leftTimeValue);
349 #endif
350 if(oldTimeValue - leftTimeValue >= NEW_TIMER_STEP)
351 {
352 SoftTimer_AdjustTimerValue(g_pTimerHeader, oldTimeValue - leftTimeValue);
353 }
354
355 SoftTimer_Add(g_pTimerHeader, &( g_timer_pool[freeIndex]));
356 SetBasicTimerEx(g_pTimerHeader->next->timerValue);
357 }
358 }
359}
360
361/********************************************
362 * CreateSoftTimer
363 * create a new soft-timer!
364 *******************************************/
365LONG CreateSoftTimer(USHORT usTimerID,
366 UCHAR ucFlag,
367 ULONG ulInterval,
368 void * (*procCallBack)(void *),
369 void *args)
370{
371 int ucIndex = 0;
372 int freeIndex = 0;
373
374 ULONG ulResidue = 0;
375 ULONG ulQuotient = 0;
376
377 if (NULL == procCallBack)
378 {
379 #ifdef SOFT_TIMER_DEBUG
380 printf("CreateSoftTimer failed, procCallBack is NULL!\n");
381 #endif
382 return ERROR;
383 }
384
385 pthread_mutex_lock(&g_timer_mutex);
386
387 if(OK != SoftTimer_Init())
388 {
389 pthread_mutex_unlock(&g_timer_mutex);
390 return ERROR;
391 }
392
393 for(ucIndex = 1, freeIndex = 0; ucIndex < MAX_TIMER_POOL_NUM; ucIndex++)
394 {
395 /*same timer id exist, warning, return error*/
396 if (g_timer_pool[ucIndex].used && (usTimerID == g_timer_pool[ucIndex].usTimerID))
397 {
398 #ifdef SOFT_TIMER_DEBUG
399 printf("Same timer id 0x%04x exist!\n", usTimerID);
400 #endif
401 pthread_mutex_unlock(&g_timer_mutex);
402 return ERROR;
403 }
404 if ((0 == g_timer_pool[ucIndex].used) && (0 == freeIndex))
405 {
406 freeIndex = ucIndex;
407 }
408 }
409
410 /* No empty timer left */
411 if (0 == freeIndex)
412 {
413 #ifdef SOFT_TIMER_DEBUG
414 printf("StartSoftTimer 0x%04x failed, queue full!\n", usTimerID);
415 #endif
416 pthread_mutex_unlock(&g_timer_mutex);
417 return ERROR;
418 }
419
420 /* Adjust interval value, it must multiple of 10 */
421 ulResidue = ulInterval % NEW_TIMER_STEP;
422 if (0 != ulResidue)
423 {
424 ulQuotient = ulInterval / NEW_TIMER_STEP;
425 ulInterval = (ulQuotient + 1) * NEW_TIMER_STEP;
426 }
427
428 g_timer_pool[freeIndex].used = 1;
429 g_timer_pool[freeIndex].usTimerID = usTimerID;
430 g_timer_pool[freeIndex].ucFlag = ucFlag;
431 g_timer_pool[freeIndex].ulCurInterval = ulInterval;
432 g_timer_pool[freeIndex].ulNextInterval = ulInterval;
433 g_timer_pool[freeIndex].procCallBack = procCallBack;
434 g_timer_pool[freeIndex].args = args;
435 g_timer_pool[freeIndex].timerValue = ulInterval;
436
437 SoftTimer_Process(freeIndex);
438 #ifdef SOFT_TIMER_DEBUG
439 printf("CreateSoftTimer index %d success: \n"
440 "usTimerID = %d, \n"
441 "ucFlag = %d, \n"
442 "ulCurInterval = %ld, \n"
443 "ulNextInterval = %ld, \n"
444 "procCallBack = %p, \n"
445 "args = %p. \n",
446 freeIndex,
447 usTimerID,
448 ucFlag,
449 ulInterval,
450 ulInterval,
451 procCallBack,
452 args);
453 #endif
454 pthread_mutex_unlock(&g_timer_mutex);
455
456 return OK;
457}
458
459/********************************************
460 * DeleteSoftTimer
461 * delete a soft-timer!
462 *******************************************/
463LONG DeleteSoftTimer(USHORT usTimerID)
464{
465 UCHAR ucIndex = 0;
466
467 pthread_mutex_lock(&g_timer_mutex);
468
469 for(ucIndex = 1; ucIndex < MAX_TIMER_POOL_NUM; ucIndex++)
470 {
471 if(g_timer_pool[ucIndex].used && (usTimerID == g_timer_pool[ucIndex].usTimerID))
472 {
473 break;
474 }
475 }
476
477 if (ucIndex >= MAX_TIMER_POOL_NUM)
478 {
479 #ifdef SOFT_TIMER_DEBUG
480 printf("DeleteSoftTimer 0x%04x failed, not exist!\n", usTimerID);
481 #endif
482 pthread_mutex_unlock(&g_timer_mutex);
483 return ERROR;
484 }
485
486 SoftTimer_Delete(g_pTimerHeader, &( g_timer_pool[ucIndex]));
487 memset(&g_timer_pool[ucIndex], 0, sizeof(SOFT_TIMER));
488 #ifdef SOFT_TIMER_DEBUG
489 printf("DeleteSoftTimer 0x%04x success!\n", usTimerID);
490 #endif
491 pthread_mutex_unlock(&g_timer_mutex);
492 return OK;
493}