linux定時器
2015/07/23 14:17
瀏覽135
迴響0
推薦0
引用0
使用方法:
1.在進程中先調用ah_pmpt_timer_init,創建一個定時器線程
2.在另一個使用定時器的線程調用ah_pmpt_timer_create創建定時器
3.調用ah_pmpt_timer_start,將定時器掛接到定時器鏈表中,設置定時時間以開啟定時器
4.調用ah_pmpt_timer_continue重新賦值時間,重新開啟定時器 (因為該定時器超時後,定時器默認就刪除了,如果要循環使用,必須重新調用ah_pmpt_timer_continue
#define AP_PTIMER_STOPPED 0x01 /* timer already stopped */
#define AP_PTIMER_CALLING 0x02 /* timer is calling */
struct ah_ptimer_ {
struct ah_ptimer_ *ap_prev; /* double link list */
struct ah_ptimer_ *ap_next;
uint8 ap_flag;
int16 ap_count;
uint32 ap_fire; /* when to fire the timer, sec since this instance is started */
ah_ptimer_callback_t ap_func;
void *ap_data;
};
typedef struct ah_ptimer_ ah_ptimer_t;
typedef void (*ah_ptimer_callback_t)(ah_ptimer_t*, void *);
#define is_ah_ptimer_stopped(t) ( (t)->ap_flag & AP_PTIMER_STOPPED)
#define is_ah_ptimer_calling(t) ( (t)->ap_flag & AP_PTIMER_CALLING)
#define set_ah_ptimer_stopped(t) do{ (t)->ap_flag |= AP_PTIMER_STOPPED; } while(0)
#define unset_ah_ptimer_stopped(t) do{ (t)->ap_flag &= ~AP_PTIMER_STOPPED; } while(0)
#define set_ah_ptimer_calling(t) do{ (t)->ap_flag |= AP_PTIMER_CALLING; } while(0)
#define unset_ah_ptimer_calling(t) do{ (t)->ap_flag &= ~AP_PTIMER_CALLING; } while(0)
#define PTIME_TIC_SEC 1 /* tic every 1 second */
#define PTIMER_TIC_SYS 128 /* every how many <tic> to make sys call to get current time */
static boolean timer_thread_running = FALSE;
/* timer-queue-lock */
static pthread_mutex_t pmpt_timer_lock = PTHREAD_MUTEX_INITIALIZER;
static ah_ptimer_t *pmpt_timer_head; /* all timers in double link-list */
static ah_ptimer_t *pmpt_timer_tail;
struct itimerval {
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
/*
* sys alarm sig handler
*每128s去重新通過_ah_sys_up_sec()獲取當前系統時間,128s內直接通過加法實現時間的增加
*/
static void ptimer_tic (int sig)
{
static uint32 tic_count=PTIMER_TIC_SYS;
int time_now;
/* not do sys call each sec */
if ( ! (--tic_count) ) {
/* try the sys call get time */
time_now = _ah_sys_up_sec();
/* sys call fail */
if (time_now < 0) {
ap_sys_up_sec += PTIME_TIC_SEC;
tic_count = 1;
}else {/* sys call ok */
ap_sys_up_sec = time_now;
tic_count = PTIMER_TIC_SYS;
}
}
else {
ap_sys_up_sec += PTIME_TIC_SEC;
}
/* linux follow System V semantics, reset signal handler to dflt.
* so no same alarm would prempt this handler. we set the tic handler again
* after poll all the timer, so we are non-prempt at process level
*/
#if 0
if( signal(SIGALRM, ptimer_tic) == SIG_ERR ) {
ah_err("proc %d fail install SIGALRM handler\n",getpid());
ah_assert(FALSE);
}
#endif
return;
}
/* init preempt timer */
static int ah_pmpt_timer_setup(void)
{
struct itimerval alarm_tic;
if (timer_thread_running) { /*如果定時器線程已經啟動,直接返回*/
return 0;
}
pmpt_timer_head = pmpt_timer_tail = NULL;/*初始化定時器鏈表*/
ap_sys_up_sec = _ah_sys_up_sec(); /*獲取系統啟動時間*/
if (ap_sys_up_sec < 0) { /*系統啟動時間小於0,出錯,返回*/
return -1;
}
/* sys timer will send SIGALRM */
if( signal(SIGALRM, ptimer_tic) == SIG_ERR ) { /*定義信號SIGALRM的信號處理函數*/
return -1;
}
/* setup sys tic */
memset((void*)&alarm_tic, 0, sizeof(alarm_tic));
alarm_tic.it_interval.tv_sec = PTIME_TIC_SEC;/*1s*/
alarm_tic.it_value.tv_sec = PTIME_TIC_SEC;
/*ITIMER_REAL decrements in real time, and delivers SIGALRM upon expiration.*/
setitimer(ITIMER_REAL, &alarm_tic, NULL); /*設置1s定時器,1s後發送SIGALRM信號*/
return 0;
}
void ah_signal_mask(int block, int signum)
{
sigset_t mask; /*定義信號集mask*/
sigemptyset(&mask); /*初始化清空信號集mask*/
sigaddset(&mask, signum);/*將信號signum加入到信號集mask*/
if (block)
pthread_sigmask(SIG_BLOCK, &mask, NULL);/*將信號集mask加入到信號屏蔽字中*/
else
pthread_sigmask(SIG_UNBLOCK, &mask, NULL);/*將信號集mask從信號屏蔽字中清除*/
}
/* must call it when pmpt_timer_lock is locked */
static void ah_pmpt_timer_dec_ref(ah_ptimer_t *t)
{
--t->ap_count;
if (t->ap_count < 0) {
ah_log(LOG_CRIT, "preempt timer: double free.");
}
if (0 == t->ap_count) {
ah_assert(is_ah_ptimer_stopped(t));
free(t);
}
return;
}
/*
* poll the timer queue, call any expired timer's callback.
*/
void ah_pmpt_timer_poll(void)
{
ah_ptimer_t *t=NULL;
for ( ; ; ) {
if (pthread_mutex_lock(&pmpt_timer_lock) != 0) {
ah_assert(FALSE);
return;
}
if ( (NULL == pmpt_timer_head) /*定時器連邊為空,直接返回*/
|| (pmpt_timer_head->ap_fire > ap_sys_up_sec) ) { /*頭結點的定時時間沒有到,直接返回*/
pthread_mutex_unlock(&pmpt_timer_lock);
break;
}
/*。。。。。。。。。。。。頭結點的定時時間到了。。。。。。。。。*/
t = pmpt_timer_head; /*獲取定時器鏈表頭結點*/
pmpt_timer_head = t->ap_next;/*更新pmpt_timer_head為下一個節點*/
if( NULL == pmpt_timer_head ) {
pmpt_timer_tail = NULL;
} else {
pmpt_timer_head->ap_prev = NULL;
}
/*將節點t從鏈表中摘除*/
/* clean up t's forw/back ptr */
t->ap_prev = NULL;
t->ap_next = NULL;
/* prevent it be deleted when calling timer's callback */
++t->ap_count;/*防止定時器被刪除,刪除的判斷是ap_count==0*/
set_ah_ptimer_calling(t);/*設置標記,表明定時器正在被調用*/
pthread_mutex_unlock(&pmpt_timer_lock);
/* NOTE: it's the callback's responsibility to free/reset/etc.
to handle the timer ptr correctly */
ah_assert(NULL != t->ap_func);
t->ap_func(t, t->ap_data);/*調用定時器的回調函數*/
if (pthread_mutex_lock(&pmpt_timer_lock) != 0) {
ah_assert(FALSE);
return;
}
unset_ah_ptimer_calling(t);/*將被調用的標記刪除*/
ah_pmpt_timer_dec_ref(t);/*將技術值ap_count減1,如果減法後變為0,則刪除定時器*/
pthread_mutex_unlock(&pmpt_timer_lock);
}
return;
}
static void *ah_pmpt_timer_thread(void *arg)
{
ah_signal_mask(FALSE, SIGALRM);
if (ah_pmpt_timer_setup() < 0) {
return NULL;
}
timer_thread_running = TRUE;
for ( ; ; ) {
/* select(0, NULL, NULL, NULL, NULL); */
ah_sleep(1);
ah_pmpt_timer_poll();
}
return NULL;
}
/* should call it in main function firstly */
int ah_pmpt_timer_init(pthread_t *timer_id)
{
int count = 0;
ah_signal_mask(TRUE, SIGALRM);
/* Create event sub-thread *//*起一個線程進程定時器計算*/
if (ah_pthread_create(timer_id, ah_pmpt_timer_thread,
NULL, SCHED_RR,
AH_PRIORITY_CTRL, 0) != 0) {
ah_err("ah_pthread_create failed");
return -1;
}
/* Check if sub-thread is actually succeeded */
while ( (!timer_thread_running) && ((count++) < 10)) {
ah_sleep(1);
}
if (!timer_thread_running) {
ah_err("Can not run timer thread");
if (NULL != timer_id) {
*timer_id = -1;
}
return -1;
}
return 0;
}
ah_ptimer_t* ah_pmpt_timer_create(ah_ptimer_callback_t callback, void *arg)
{
ah_ptimer_t *t;
if (NULL == callback) { /*定時器沒有回調函數,直接退出*/
return NULL;
}
t = (ah_ptimer_t*)ah_calloc(1,sizeof(ah_ptimer_t)); /*分配定時器*/
if (NULL == t) {
return NULL;
}
t->ap_func = callback;
t->ap_data = arg;
t->ap_count = 1;
return t;
}
/* must call it when pmpt_timer_lock is locked */
static void ah_pmpt_timer_stop_internal(ah_ptimer_t *t)
{
set_ah_ptimer_stopped(t); /*設置定時器t的標記位為STOPPED*/
if ((NULL == t->ap_prev) && (NULL == t->ap_next) && (t != pmpt_timer_head)){
return;
}
if( t->ap_prev ) {
t->ap_prev->ap_next = t->ap_next;
} else {
pmpt_timer_head = t->ap_next;
}
if(NULL != t
1.在進程中先調用ah_pmpt_timer_init,創建一個定時器線程
2.在另一個使用定時器的線程調用ah_pmpt_timer_create創建定時器
3.調用ah_pmpt_timer_start,將定時器掛接到定時器鏈表中,設置定時時間以開啟定時器
4.調用ah_pmpt_timer_continue重新賦值時間,重新開啟定時器 (因為該定時器超時後,定時器默認就刪除了,如果要循環使用,必須重新調用ah_pmpt_timer_continue
#define AP_PTIMER_STOPPED 0x01 /* timer already stopped */
#define AP_PTIMER_CALLING 0x02 /* timer is calling */
struct ah_ptimer_ {
struct ah_ptimer_ *ap_prev; /* double link list */
struct ah_ptimer_ *ap_next;
uint8 ap_flag;
int16 ap_count;
uint32 ap_fire; /* when to fire the timer, sec since this instance is started */
ah_ptimer_callback_t ap_func;
void *ap_data;
};
typedef struct ah_ptimer_ ah_ptimer_t;
typedef void (*ah_ptimer_callback_t)(ah_ptimer_t*, void *);
#define is_ah_ptimer_stopped(t) ( (t)->ap_flag & AP_PTIMER_STOPPED)
#define is_ah_ptimer_calling(t) ( (t)->ap_flag & AP_PTIMER_CALLING)
#define set_ah_ptimer_stopped(t) do{ (t)->ap_flag |= AP_PTIMER_STOPPED; } while(0)
#define unset_ah_ptimer_stopped(t) do{ (t)->ap_flag &= ~AP_PTIMER_STOPPED; } while(0)
#define set_ah_ptimer_calling(t) do{ (t)->ap_flag |= AP_PTIMER_CALLING; } while(0)
#define unset_ah_ptimer_calling(t) do{ (t)->ap_flag &= ~AP_PTIMER_CALLING; } while(0)
#define PTIME_TIC_SEC 1 /* tic every 1 second */
#define PTIMER_TIC_SYS 128 /* every how many <tic> to make sys call to get current time */
static boolean timer_thread_running = FALSE;
/* timer-queue-lock */
static pthread_mutex_t pmpt_timer_lock = PTHREAD_MUTEX_INITIALIZER;
static ah_ptimer_t *pmpt_timer_head; /* all timers in double link-list */
static ah_ptimer_t *pmpt_timer_tail;
struct itimerval {
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
/*
* sys alarm sig handler
*每128s去重新通過_ah_sys_up_sec()獲取當前系統時間,128s內直接通過加法實現時間的增加
*/
static void ptimer_tic (int sig)
{
static uint32 tic_count=PTIMER_TIC_SYS;
int time_now;
/* not do sys call each sec */
if ( ! (--tic_count) ) {
/* try the sys call get time */
time_now = _ah_sys_up_sec();
/* sys call fail */
if (time_now < 0) {
ap_sys_up_sec += PTIME_TIC_SEC;
tic_count = 1;
}else {/* sys call ok */
ap_sys_up_sec = time_now;
tic_count = PTIMER_TIC_SYS;
}
}
else {
ap_sys_up_sec += PTIME_TIC_SEC;
}
/* linux follow System V semantics, reset signal handler to dflt.
* so no same alarm would prempt this handler. we set the tic handler again
* after poll all the timer, so we are non-prempt at process level
*/
#if 0
if( signal(SIGALRM, ptimer_tic) == SIG_ERR ) {
ah_err("proc %d fail install SIGALRM handler\n",getpid());
ah_assert(FALSE);
}
#endif
return;
}
/* init preempt timer */
static int ah_pmpt_timer_setup(void)
{
struct itimerval alarm_tic;
if (timer_thread_running) { /*如果定時器線程已經啟動,直接返回*/
return 0;
}
pmpt_timer_head = pmpt_timer_tail = NULL;/*初始化定時器鏈表*/
ap_sys_up_sec = _ah_sys_up_sec(); /*獲取系統啟動時間*/
if (ap_sys_up_sec < 0) { /*系統啟動時間小於0,出錯,返回*/
return -1;
}
/* sys timer will send SIGALRM */
if( signal(SIGALRM, ptimer_tic) == SIG_ERR ) { /*定義信號SIGALRM的信號處理函數*/
return -1;
}
/* setup sys tic */
memset((void*)&alarm_tic, 0, sizeof(alarm_tic));
alarm_tic.it_interval.tv_sec = PTIME_TIC_SEC;/*1s*/
alarm_tic.it_value.tv_sec = PTIME_TIC_SEC;
/*ITIMER_REAL decrements in real time, and delivers SIGALRM upon expiration.*/
setitimer(ITIMER_REAL, &alarm_tic, NULL); /*設置1s定時器,1s後發送SIGALRM信號*/
return 0;
}
void ah_signal_mask(int block, int signum)
{
sigset_t mask; /*定義信號集mask*/
sigemptyset(&mask); /*初始化清空信號集mask*/
sigaddset(&mask, signum);/*將信號signum加入到信號集mask*/
if (block)
pthread_sigmask(SIG_BLOCK, &mask, NULL);/*將信號集mask加入到信號屏蔽字中*/
else
pthread_sigmask(SIG_UNBLOCK, &mask, NULL);/*將信號集mask從信號屏蔽字中清除*/
}
/* must call it when pmpt_timer_lock is locked */
static void ah_pmpt_timer_dec_ref(ah_ptimer_t *t)
{
--t->ap_count;
if (t->ap_count < 0) {
ah_log(LOG_CRIT, "preempt timer: double free.");
}
if (0 == t->ap_count) {
ah_assert(is_ah_ptimer_stopped(t));
free(t);
}
return;
}
/*
* poll the timer queue, call any expired timer's callback.
*/
void ah_pmpt_timer_poll(void)
{
ah_ptimer_t *t=NULL;
for ( ; ; ) {
if (pthread_mutex_lock(&pmpt_timer_lock) != 0) {
ah_assert(FALSE);
return;
}
if ( (NULL == pmpt_timer_head) /*定時器連邊為空,直接返回*/
|| (pmpt_timer_head->ap_fire > ap_sys_up_sec) ) { /*頭結點的定時時間沒有到,直接返回*/
pthread_mutex_unlock(&pmpt_timer_lock);
break;
}
/*。。。。。。。。。。。。頭結點的定時時間到了。。。。。。。。。*/
t = pmpt_timer_head; /*獲取定時器鏈表頭結點*/
pmpt_timer_head = t->ap_next;/*更新pmpt_timer_head為下一個節點*/
if( NULL == pmpt_timer_head ) {
pmpt_timer_tail = NULL;
} else {
pmpt_timer_head->ap_prev = NULL;
}
/*將節點t從鏈表中摘除*/
/* clean up t's forw/back ptr */
t->ap_prev = NULL;
t->ap_next = NULL;
/* prevent it be deleted when calling timer's callback */
++t->ap_count;/*防止定時器被刪除,刪除的判斷是ap_count==0*/
set_ah_ptimer_calling(t);/*設置標記,表明定時器正在被調用*/
pthread_mutex_unlock(&pmpt_timer_lock);
/* NOTE: it's the callback's responsibility to free/reset/etc.
to handle the timer ptr correctly */
ah_assert(NULL != t->ap_func);
t->ap_func(t, t->ap_data);/*調用定時器的回調函數*/
if (pthread_mutex_lock(&pmpt_timer_lock) != 0) {
ah_assert(FALSE);
return;
}
unset_ah_ptimer_calling(t);/*將被調用的標記刪除*/
ah_pmpt_timer_dec_ref(t);/*將技術值ap_count減1,如果減法後變為0,則刪除定時器*/
pthread_mutex_unlock(&pmpt_timer_lock);
}
return;
}
static void *ah_pmpt_timer_thread(void *arg)
{
ah_signal_mask(FALSE, SIGALRM);
if (ah_pmpt_timer_setup() < 0) {
return NULL;
}
timer_thread_running = TRUE;
for ( ; ; ) {
/* select(0, NULL, NULL, NULL, NULL); */
ah_sleep(1);
ah_pmpt_timer_poll();
}
return NULL;
}
/* should call it in main function firstly */
int ah_pmpt_timer_init(pthread_t *timer_id)
{
int count = 0;
ah_signal_mask(TRUE, SIGALRM);
/* Create event sub-thread *//*起一個線程進程定時器計算*/
if (ah_pthread_create(timer_id, ah_pmpt_timer_thread,
NULL, SCHED_RR,
AH_PRIORITY_CTRL, 0) != 0) {
ah_err("ah_pthread_create failed");
return -1;
}
/* Check if sub-thread is actually succeeded */
while ( (!timer_thread_running) && ((count++) < 10)) {
ah_sleep(1);
}
if (!timer_thread_running) {
ah_err("Can not run timer thread");
if (NULL != timer_id) {
*timer_id = -1;
}
return -1;
}
return 0;
}
ah_ptimer_t* ah_pmpt_timer_create(ah_ptimer_callback_t callback, void *arg)
{
ah_ptimer_t *t;
if (NULL == callback) { /*定時器沒有回調函數,直接退出*/
return NULL;
}
t = (ah_ptimer_t*)ah_calloc(1,sizeof(ah_ptimer_t)); /*分配定時器*/
if (NULL == t) {
return NULL;
}
t->ap_func = callback;
t->ap_data = arg;
t->ap_count = 1;
return t;
}
/* must call it when pmpt_timer_lock is locked */
static void ah_pmpt_timer_stop_internal(ah_ptimer_t *t)
{
set_ah_ptimer_stopped(t); /*設置定時器t的標記位為STOPPED*/
if ((NULL == t->ap_prev) && (NULL == t->ap_next) && (t != pmpt_timer_head)){
return;
}
if( t->ap_prev ) {
t->ap_prev->ap_next = t->ap_next;
} else {
pmpt_timer_head = t->ap_next;
}
if(NULL != t
你可能會有興趣的文章:
限會員,要發表迴響,請先登入


