Contents ...
udn網路城邦
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
全站分類:知識學習 科學百科
自訂分類:不分類
上一則: Oracle DB 网络配置
下一則: 分析linux的lcd驅動
你可能會有興趣的文章:

限會員,要發表迴響,請先登入