From 0b01f88f6a613dfcf5964be3698909f9e48ca56d Mon Sep 17 00:00:00 2001 From: Liu Chao Date: Sun, 22 Apr 2018 22:30:59 +0800 Subject: [PATCH] fix(timer): timer thread may quit after it is created --- src/timer.c | 256 ++++++++++++++++++++++++++-------------------------- 1 file changed, 130 insertions(+), 126 deletions(-) diff --git a/src/timer.c b/src/timer.c index e9abe90c6..a71244e60 100644 --- a/src/timer.c +++ b/src/timer.c @@ -1,7 +1,7 @@ /* timer.c -- timer support. * * Copyright (c) 2018, Liu chao All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * @@ -34,136 +34,139 @@ #include #include -#define STATE_RUN 1 -#define STATE_PAUSE 0 +#define STATE_RUN 1 +#define STATE_PAUSE 0 /*----------------------------- Timer --------------------------------*/ typedef struct TimerRec_ { - int state; /**< 状态 */ - LCUI_BOOL reuse; /**< 是否重复使用该定时器 */ - long int id; /**< 定时器ID */ - int64_t start_time; /**< 定时器启动时的时间 */ - int64_t pause_time; /**< 定时器暂停时的时间 */ - long int total_ms; /**< 定时时间(单位:毫秒) */ - long int pause_ms; /**< 定时器处于暂停状态的时长(单位:毫秒) */ - void (*func)(void*); /**< 回调函数 */ - void *arg; /**< 函数的参数 */ - LinkedListNode node; /**< 位于定时器列表中的节点 */ + int state; /**< 状态 */ + long int id; /**< 定时器ID */ + LCUI_BOOL reuse; /**< 是否重复使用该定时器 */ + + int64_t start_time; /**< 定时器启动时的时间 */ + int64_t pause_time; /**< 定时器暂停时的时间 */ + long int total_ms; /**< 定时时间(单位:毫秒) */ + long int pause_ms; /**< 定时器处于暂停状态的时长(单位:毫秒) */ + + void (*func)(void *); /**< 回调函数 */ + void *arg; /**< 函数的参数 */ + LinkedListNode node; /**< 位于定时器列表中的节点 */ } TimerRec, *Timer; static struct TimerModule { - int id_count; /**< 定时器ID计数 */ - LinkedList timer_list; /**< 定时器数据记录 */ - LCUI_BOOL is_running; /**< 定时器线程是否正在运行 */ - LCUI_Cond sleep_cond; /**< 用于控制定时器睡眠的条件变量 */ - LCUI_Mutex mutex; /**< 定时器记录操作互斥锁 */ - LCUI_Thread tid; /**< 定时器处理线程ID */ + int id_count; /**< 定时器ID计数 */ + LCUI_BOOL active; /**< 定时器线程是否正在运行 */ + LCUI_Thread tid; /**< 定时器处理线程ID */ + LCUI_Mutex mutex; /**< 定时器记录操作互斥锁 */ + LCUI_Cond sleep_cond; /**< 用于控制定时器睡眠的条件变量 */ + LinkedList timers; /**< 定时器数据记录 */ } self; /*----------------------------- Private ------------------------------*/ /** 更新定时器在定时器列表中的位置 */ -static void TimerList_AddNode( LinkedListNode *node ) +static void TimerList_AddNode(LinkedListNode *node) { Timer timer; int64_t t, tt; LinkedListNode *cur; /* 计算该定时器的剩余定时时长 */ timer = node->data; - t = LCUI_GetTimeDelta( timer->start_time ); + t = LCUI_GetTimeDelta(timer->start_time); t = timer->total_ms - t + timer->pause_ms; - for( LinkedList_Each( cur, &self.timer_list ) ) { + for (LinkedList_Each(cur, &self.timers)) { timer = cur->data; - tt = LCUI_GetTimeDelta( timer->start_time ); + tt = LCUI_GetTimeDelta(timer->start_time); tt = timer->total_ms - tt + timer->pause_ms; - if( t <= tt ) { - LinkedList_Link( &self.timer_list, cur->prev, node ); + if (t <= tt) { + LinkedList_Link(&self.timers, cur->prev, node); return; } } - LinkedList_AppendNode( &self.timer_list, node ); + LinkedList_AppendNode(&self.timers, node); } //#define DEBUG_TIMER #ifdef DEBUG_TIMER -/** 打印列表中的定时器信息 */ -static void TimerList_Print( void ) +static void TimerList_Print(void) { int i = 0; Timer timer; LinkedListNode *node; - _DEBUG_MSG("timer list(%d) start:\n", self.timer_list.length); - for( LinkedList_Each( node, &self.timer_list ) { + _DEBUG_MSG("timer list(%d) start:\n", self.timers.length); + for (LinkedList_Each(node, &self.timers)) { timer = node->data; - _DEBUG_MSG("[%02d] %ld, func: %p, cur_ms: %ldms, total_ms: %ldms\n", - i++, timer->id, timer->func, timer->total_ms - (long int)LCUI_GetTimeDelta(timer->start_time), timer->total_ms ); + _DEBUG_MSG( + "[%02d] %ld, func: %p, cur_ms: %ldms, total_ms: %ldms\n", + i++, timer->id, timer->func, + timer->total_ms - + (long int)LCUI_GetTimeDelta(timer->start_time), + timer->total_ms); } _DEBUG_MSG("timer list end\n\n"); } #endif - /** 定时器线程,用于处理列表中各个定时器 */ -static void TimerThread( void *arg ) +static void TimerThread(void *arg) { long n_ms, lost_ms; LinkedListNode *node; LCUI_TaskRec task = { 0 }; - LCUIMutex_Lock( &self.mutex ); - LOG( "[timer] timer thread is working\n" ); - while( self.is_running ) { + LCUIMutex_Lock(&self.mutex); + LOG("[timer] timer thread is working\n"); + while (self.active) { Timer timer = NULL; - for( LinkedList_Each( node, &self.timer_list ) ) { + for (LinkedList_Each(node, &self.timers)) { timer = node->data; - if( timer && timer->state == STATE_RUN ) { + if (timer && timer->state == STATE_RUN) { break; } } /* 没有要处理的定时器,停留一段时间再进行下次循环 */ - if( !node ) { - LCUIMutex_Unlock( &self.mutex ); - LCUI_MSleep( 10 ); - LCUIMutex_Lock( &self.mutex ); + if (!node) { + LCUIMutex_Unlock(&self.mutex); + LCUI_MSleep(10); + LCUIMutex_Lock(&self.mutex); continue; } - lost_ms = (long)LCUI_GetTimeDelta( timer->start_time ); + lost_ms = (long)LCUI_GetTimeDelta(timer->start_time); /* 减去处于暂停状态的时长 */ lost_ms -= timer->pause_ms; /* 若流失的时间未达到总定时时长,则睡眠一段时间 */ - if( lost_ms < timer->total_ms ) { + if (lost_ms < timer->total_ms) { n_ms = timer->total_ms - lost_ms; - LCUICond_TimedWait( &self.sleep_cond, - &self.mutex, n_ms ); + LCUICond_TimedWait(&self.sleep_cond, &self.mutex, n_ms); continue; } /* 准备任务数据 */ task.func = (LCUI_AppTaskFunc)timer->func; task.arg[0] = timer->arg; /* 若需要重复使用,则重置剩余等待时间 */ - LinkedList_Unlink( &self.timer_list, node ); - if( timer->reuse ) { + LinkedList_Unlink(&self.timers, node); + if (timer->reuse) { timer->pause_ms = 0; timer->start_time = LCUI_GetTime(); - TimerList_AddNode( node ); + TimerList_AddNode(node); } else { - free( timer ); + free(timer); } /* 添加该任务至指定程序的任务队列 */ - LCUI_PostTask( &task ); + LCUI_PostTask(&task); } - LOG( "[timer] timer thread stopped working\n" ); - LCUIMutex_Unlock( &self.mutex ); - LCUIThread_Exit( NULL ); + LOG("[timer] timer thread stopped working\n"); + LCUIMutex_Unlock(&self.mutex); + LCUIThread_Exit(NULL); } -static Timer TimerList_Find( int timer_id ) +static Timer TimerList_Find(int timer_id) { Timer timer; LinkedListNode *node; - for( LinkedList_Each( node, &self.timer_list ) ) { + for (LinkedList_Each(node, &self.timers)) { timer = node->data; - if( timer && timer->id == timer_id ) { + if (timer && timer->id == timer_id) { return timer; } } @@ -173,15 +176,15 @@ static Timer TimerList_Find( int timer_id ) /*----------------------------- Public -------------------------------*/ -int LCUITimer_Set( long int n_ms, void (*func)(void*), - void *arg, LCUI_BOOL reuse ) +int LCUITimer_Set(long int n_ms, void (*func)(void *), void *arg, + LCUI_BOOL reuse) { Timer timer; - if( !self.is_running ) { + if (!self.active) { return -1; } - LCUIMutex_Lock( &self.mutex ); - timer = malloc( sizeof(TimerRec) ); + LCUIMutex_Lock(&self.mutex); + timer = malloc(sizeof(TimerRec)); timer->arg = arg; timer->func = func; timer->reuse = reuse; @@ -193,121 +196,122 @@ int LCUITimer_Set( long int n_ms, void (*func)(void*), timer->node.next = NULL; timer->node.prev = NULL; timer->node.data = timer; - TimerList_AddNode( &timer->node ); - LCUICond_Signal( &self.sleep_cond ); - LCUIMutex_Unlock( &self.mutex ); - DEBUG_MSG("set timer, id: %ld, total_ms: %ld\n", timer->id, timer->total_ms); + TimerList_AddNode(&timer->node); + LCUICond_Signal(&self.sleep_cond); + LCUIMutex_Unlock(&self.mutex); + DEBUG_MSG("set timer, id: %ld, total_ms: %ld\n", timer->id, + timer->total_ms); return timer->id; } -int LCUITimer_SetTimeout( long int n_ms, - void( *callback )(void*), - void *arg ) +int LCUITimer_SetTimeout(long int n_ms, void (*callback)(void *), void *arg) { - return LCUITimer_Set( n_ms, callback, arg, FALSE ); + return LCUITimer_Set(n_ms, callback, arg, FALSE); } -int LCUITimer_SetInterval( long int n_ms, - void( *callback )(void*), - void *arg ) +int LCUITimer_SetInterval(long int n_ms, void (*callback)(void *), void *arg) { - return LCUITimer_Set( n_ms, callback, arg, TRUE ); + return LCUITimer_Set(n_ms, callback, arg, TRUE); } -int LCUITimer_Free( int timer_id ) +int LCUITimer_Free(int timer_id) { Timer timer; - if( !self.is_running ) { + if (!self.active) { return -1; } - LCUIMutex_Lock( &self.mutex ); - timer = TimerList_Find( timer_id ); - if( !timer ) { - LCUIMutex_Unlock( &self.mutex ); + LCUIMutex_Lock(&self.mutex); + timer = TimerList_Find(timer_id); + if (!timer) { + LCUIMutex_Unlock(&self.mutex); return -1; } - LinkedList_Unlink( &self.timer_list, &timer->node ); - free( timer ); - LCUICond_Signal( &self.sleep_cond ); - LCUIMutex_Unlock( &self.mutex ); + LinkedList_Unlink(&self.timers, &timer->node); + free(timer); + LCUICond_Signal(&self.sleep_cond); + LCUIMutex_Unlock(&self.mutex); return 0; } -int LCUITimer_Pause( int timer_id ) +int LCUITimer_Pause(int timer_id) { Timer timer; - if( !self.is_running ) { + if (!self.active) { return -1; } - LCUIMutex_Lock( &self.mutex ); - timer = TimerList_Find( timer_id ); - if( timer ) { + LCUIMutex_Lock(&self.mutex); + timer = TimerList_Find(timer_id); + if (timer) { /* 记录暂停时的时间 */ timer->pause_time = LCUI_GetTime(); timer->state = STATE_PAUSE; } - LCUICond_Signal( &self.sleep_cond ); - LCUIMutex_Unlock( &self.mutex ); - return timer ? 0:-1; + LCUICond_Signal(&self.sleep_cond); + LCUIMutex_Unlock(&self.mutex); + return timer ? 0 : -1; } -int LCUITimer_Continue( int timer_id ) +int LCUITimer_Continue(int timer_id) { Timer timer; - if( !self.is_running ) { + if (!self.active) { return -1; } - LCUIMutex_Lock( &self.mutex ); - timer = TimerList_Find( timer_id ); - if( timer ) { + LCUIMutex_Lock(&self.mutex); + timer = TimerList_Find(timer_id); + if (timer) { /* 计算处于暂停状态的时长 */ - timer->pause_ms += (long int)LCUI_GetTimeDelta( timer->pause_time ); + timer->pause_ms += + (long int)LCUI_GetTimeDelta(timer->pause_time); timer->state = STATE_RUN; } - LCUICond_Signal( &self.sleep_cond ); - LCUIMutex_Unlock( &self.mutex ); - return timer ? 0:-1; + LCUICond_Signal(&self.sleep_cond); + LCUIMutex_Unlock(&self.mutex); + return timer ? 0 : -1; } -int LCUITimer_Reset( int timer_id, long int n_ms ) +int LCUITimer_Reset(int timer_id, long int n_ms) { Timer timer; - if( !self.is_running ) { + if (!self.active) { return -1; } - LCUIMutex_Lock( &self.mutex ); - timer = TimerList_Find( timer_id ); - if( timer ) { + LCUIMutex_Lock(&self.mutex); + timer = TimerList_Find(timer_id); + if (timer) { timer->pause_ms = 0; timer->total_ms = n_ms; timer->start_time = LCUI_GetTime(); } - LCUICond_Signal( &self.sleep_cond ); - LCUIMutex_Unlock( &self.mutex ); - return timer ? 0:-1; + LCUICond_Signal(&self.sleep_cond); + LCUIMutex_Unlock(&self.mutex); + return timer ? 0 : -1; } -void LCUI_InitTimer( void ) +void LCUI_InitTimer(void) { - LOG( "[timer] init ...\n" ); + self.active = TRUE; + LOG("[timer] init ...\n"); LCUITime_Init(); - LCUIMutex_Init( &self.mutex ); - LCUICond_Init( &self.sleep_cond ); - LinkedList_Init( &self.timer_list ); - LCUIThread_Create( &self.tid, TimerThread, NULL ); - self.is_running = TRUE; + LCUIMutex_Init(&self.mutex); + LCUICond_Init(&self.sleep_cond); + LinkedList_Init(&self.timers); + LCUIThread_Create(&self.tid, TimerThread, NULL); } -void LCUI_FreeTimer( void ) +void LCUI_FreeTimer(void) { - self.is_running = FALSE; - LCUIMutex_Lock( &self.mutex ); - LCUICond_Broadcast( &self.sleep_cond ); - LCUIMutex_Unlock( &self.mutex ); - LCUIThread_Join( self.tid, NULL ); - LinkedList_ClearData( &self.timer_list, free ); - LCUICond_Destroy( &self.sleep_cond ); - LCUIMutex_Destroy( &self.mutex ); + if (!self.active) { + return; + } + self.active = FALSE; + LCUIMutex_Lock(&self.mutex); + LCUICond_Broadcast(&self.sleep_cond); + LCUIMutex_Unlock(&self.mutex); + LCUIThread_Join(self.tid, NULL); + LinkedList_ClearData(&self.timers, free); + LCUICond_Destroy(&self.sleep_cond); + LCUIMutex_Destroy(&self.mutex); } /*---------------------------- End Public -----------------------------*/