Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1007220
  • 博文数量: 442
  • 博客积分: 1146
  • 博客等级: 少尉
  • 技术积分: 1604
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-04 12:52
个人简介

123

文章分类

全部博文(442)

文章存档

2017年(3)

2016年(15)

2015年(132)

2014年(52)

2013年(101)

2012年(110)

2011年(29)

分类: LINUX

2012-01-29 16:12:10

本文转自:http://blog.csdn.net/leon11112010/article/details/6677210

作者:leon11112010


这是我自己实现的版本,参考 Don Libes 的 Implementing Software Timer 

我是用alarm实现的,好像不太精确,还有一个版本可以设定定时器的次数,可是随着次数增多精确度就成了不可忽略的问题了。

不排除有很多BUG, 而且有些细节没考虑。


/************** timers.h *************/  
/*  
 * Title: Answer to excersice 10.5 of APUE - Software timer 
 * By: Leon 
 * 
 * This implementation is similar to Don Libes's, and I modify 
 * it according to my thought. This timer is not very precise. 
 */  
  
#ifndef _APUE_TIMER_  
#define _APUE_TIMER_  
  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
  
#define TRUE    1  
#define FALSE    0  
  
#define MAX_TIMERS     128         /* number of timers */  
#define VERY_LONG_TIME     INT_MAX      /* longest time possible */  
  
/*  
 * no return value, the function takes  
 * only one parameter for general purpose. 
 */  
typedef void timer_handler(void *arg);      
  
struct __apue_timer  
{      
    int        inuse;        /* TRUE if in use */  
    int        time_wait;    /* relative time to wait */  
    timer_handler    *handler;    /* called when the timer has expired */  
    void        *arg;        /* argument of handler */  
};  
  
typedef struct __apue_timer ATIMER;  
  
/*  
 * initialize the timers array. 
 * This function must be called first. 
 * returns 0 on success and -1 on error. 
 */  
int timer_init(void);  
  
/*  
 * stop and cancel all timers. 
 * after this function was called, don't use functions 
 * declared here before timer_init() was called. 
 */  
void timer_cancel(void);  
  
/*  
 * Function     : decalre a timer 
 * Parameter    : time_set sets the time, timer_handler is a function pointer  
 *          points to the function wanted to call when the timer has expired.  
 * Return value    : upon successful return, the function returns a pointer points to  
 *           the declared timer. Otherwise, return NULL. 
 */  
ATIMER *timer_declare(int time_set, timer_handler *handler, void *arg);  
  
/*  
 * Function    : undeclare a timer 
 * Parameter    : a pointer points to a declared timer 
 * Return value    : returns 0 on success and -1 on error 
 */  
int timer_undeclare(ATIMER *t);  
  
/*  
 * Function      : update timers  
 * Return value   : a pointer points to the timer which will expire next 
 *            or NULL if no timers. 
 */  
ATIMER *timer_update();  
  
/* called when a timer has expired */  
void timer_out_handler(int signo);  
  
#endif  
  
/*********** timers.c *************/  
#include "timers.h"  
  
/* I prefer to use array instead of linked list, which is more brevity and simpler */  
static ATIMER             apue_timers[MAX_TIMERS];    /* array of timers */  
static ATIMER             *next_timer = NULL;        /* point to the next expired timer */  
static volatile int     time_cur = 0, time_set = 0;    /* record the time */  
static struct sigaction act;            /* new sigaction */  
static struct sigaction oldact;            /* old sigaction */  
static sigset_t        set, old_set;  
  
static void disable_interrupt(void)  
{  
    sigfillset(&set);  
    sigdelset(&set, SIGQUIT);  
    sigdelset(&set, SIGALRM);  
    if(sigprocmask(SIG_SETMASK, &set, &old_set)  < 0)  
        fprintf(stderr, "sigprocmask error\n");  
}  
  
static void enable_interrupt(void)  
{  
    if(sigprocmask(SIG_SETMASK, &old_set, NULL)  < 0)  
        fprintf(stderr, "sigprocmask error\n");  
}  
  
int timer_init(void)  
{  
    int         i;  
    sigset_t     mask;  
      
    disable_interrupt();  
      
    /* initialize timers array */  
    for(i = 0; i < MAX_TIMERS; i++)  
        apue_timers[i].inuse = FALSE;  
      
    /* initialize sigaction */  
    sigfillset(&mask);  
    sigdelset(&mask, SIGQUIT);  
    sigdelset(&set, SIGALRM);  
    act.sa_mask = mask;  
    act.sa_handler = timer_out_handler;  
    if(sigaction(SIGALRM, &act, &oldact) < 0)  
    {  
        fprintf(stderr, "sigaction error\n");  
        enable_interrupt();  
        return -1;  
    }  
      
    enable_interrupt();  
    return 0;  
}  
  
void timer_cancel(void)  
{  
    int i;  
      
    disable_interrupt();  
      
    alarm(0);  
    for(i = 0; i < MAX_TIMERS; i++)  
        apue_timers[i].inuse = FALSE;  
    /* reset sigaction */  
    if(sigaction(SIGALRM, &oldact, NULL) < 0)  
    {  
        fprintf(stderr, "sigaction error\n");  
        enable_interrupt();  
    }  
      
    enable_interrupt();  
}  
  
ATIMER *timer_declare(int time_set, timer_handler *handler, void *arg)  
{  
    ATIMER *new_timer;  
  
    disable_interrupt();  
  
    /* find a timer not inuse */  
    for( new_timer = apue_timers; new_timer < &apue_timers[MAX_TIMERS] ; new_timer++)      
    {  
        if(!new_timer->inuse)  
            break;  
    }  
    /* no timer available */  
    if(new_timer == &apue_timers[MAX_TIMERS])  
    {  
        enable_interrupt();                  
        return NULL;  
    }  
      
    /* found a timer */  
    new_timer->inuse = TRUE;  
    new_timer->time_wait = time_set;  
    new_timer->handler = handler;  
    new_timer->arg = arg;  
      
    /* update timers */  
    next_timer = timer_update();  
      
    /* set next timer */  
    if(!next_timer || new_timer->time_wait < next_timer->time_wait)  
    {  
        next_timer = new_timer;  
        alarm(0);  
        alarm(next_timer->time_wait);  
    }  
      
    enable_interrupt();  
    return new_timer;  
}  
          
      
int timer_undeclare(ATIMER *t)  
{  
    disable_interrupt();  
      
    /* check parameter t */  
    if(t < apue_timers || t >= &apue_timers[MAX_TIMERS] || !t->inuse)  
    {  
        enable_interrupt();  
        return -1;  
    }  
          
    t->inuse = FALSE;  
      
    /* reset alarm if t is next_timer */  
    if(t == next_timer)  
    {  
        alarm(0);  
        next_timer = timer_update();  
    }  
      
    enable_interrupt();  
    return 0;  
}   
      
ATIMER *timer_update()  
{  
    int     decrement;  
    int    flag = FALSE;  
    ATIMER     *t;  
    ATIMER  temp_timer = { 0, VERY_LONG_TIME, NULL };  
      
    disable_interrupt();  
      
    /* update time */  
    if(time_set == 0)  
    {  
        time_set = times(NULL);  
        decrement = 0;  
    }  
    else  
    {  
        time_cur = times(NULL);      
        /* get decrement and convert to seconds */  
        decrement = (time_cur - time_set) / sysconf(_SC_CLK_TCK);      
        /* printf("decrement = %d\n", decrement);/* !!for debug!! */  
        assert(decrement >= 0);            /* someting may happen */  
        time_set = time_cur;            /* reset time_set */  
    }  
      
    /* reset next_timer */  
    next_timer = &temp_timer;  
      
    /* update timers and get next timer */  
    for(t = apue_timers; t < &apue_timers[MAX_TIMERS]; t++)  
    {  
        if(t->inuse)  
        {  
            if(decrement < t->time_wait)  
                t->time_wait -= decrement;  
            if(t->time_wait < next_timer->time_wait)  
                next_timer = t;  
            flag = TRUE;  
        }  
    }  
      
    /* reset alarm */  
    alarm(0);  
    if(flag)         
    {  
        alarm(next_timer->time_wait);  
    }  
    else             
    {  
        next_timer = NULL;  
        time_cur = time_set = 0;  
    }  
      
    enable_interrupt();  
    return next_timer;  
}  
  
void timer_out_handler(int signo)  
{  
    /* call user hanler */  
    next_timer->handler(next_timer->arg);  
    /* update timers */  
    next_timer->inuse = FALSE;  
    next_timer = timer_update();  
}  
阅读(1020) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~