ptpd 1588协议关于多个定时器的实现方式解析

来源:互联网 发布:mac邮箱怎么设置签名 编辑:程序博客网 时间:2024/06/05 02:28

1588时间协议,需要实现多个定时器,以对系统各个事件进行定时管理,那它怎么实现多个定时器的,真的挺巧妙的,我们来解析下

PtpClock *
ptpdStartup(int argc, char **argv, Integer16 * ret, RunTimeOpts * rtOpts)

{

...

 if(!timerSetup(ptpClock->timers)) {    //初始化所有的计时器,保留一个指向所有计时器的指针
  PERROR("failed to set up event timers");
  *ret = 2;
  free(ptpClock);
  return 0;
 }

...

}


Boolean timerSetup(IntervalTimer *itimers)
{
    Boolean ret = TRUE;
/* WARNING: these descriptions MUST be in the same order,
 * and in the same number as the enum in ptp_timers.h
 */
    static const char* timerDesc[PTP_MAX_TIMER] = {   //这里是我们需要的计时器类型
  "PDELAYREQ_INTERVAL",
  "DELAYREQ_INTERVAL",
  "SYNC_INTERVAL",
  "ANNOUNCE_RECEIPT",
  "ANNOUNCE_INTERVAL",
  "UNICAST_GRANT",
  "OPERATOR_MESSAGES",
  "LEAP_SECOND_PAUSE",
  "STATUSFILE_UPDATE",
  "PANIC_MODE",
  "PERIODIC_INFO_TIMER",
#ifdef PTPD_STATISTICS
  "STATISTICS_UPDATE",
#endif /* PTPD_STATISTICS */
  "MASTER_NETREFRESH",
  "CALIBRATION_DELAY",
  "CLOCK_UPDATE",
  "TIMINGDOMAIN_UPDATE"
    };
    int i = 0;
    startEventTimers();
    for(i=0; i<PTP_MAX_TIMER; i++) {  //创建上面所枚举的计时器
 itimers[i].data = NULL;
 itimers[i].data = (void *)(createEventTimer(timerDesc[i]));
 if(itimers[i].data == NULL) {
     ret = FALSE;
 }
    }
    return ret;
}

void
startEventTimers(void)
{
 struct itimerval itimer;
 DBG("initTimer\n");
#ifdef __sun
 sigset(SIGALRM, SIG_IGN);
#else
 signal(SIGALRM, SIG_IGN);
#endif /* __sun */
 elapsed = 0;
 itimer.it_value.tv_sec = itimer.it_interval.tv_sec = 0;
 itimer.it_value.tv_usec = itimer.it_interval.tv_usec =
     US_TIMER_INTERVAL;
#ifdef __sun
 sigset(SIGALRM, timerSignalHandler);
#else 
 signal(SIGALRM, timerSignalHandler);  //定时响应行数
#endif /* __sun */
 setitimer(ITIMER_REAL, &itimer, 0);   //使用高精度定时
}

static void
timerSignalHandler(int sig)
{
 elapsed++;   //非常简单,就使用这个全局计数器进行计时,这个是定时器使用的关键
 /* be sure to NOT call DBG in asynchronous handlers! */
}

//接下来我们看看它怎么创建定时器的
EventTimer
*createEventTimer(const char* id)
{
 EventTimer *timer;
        if ( !(timer = calloc (1, sizeof(EventTimer))) ) {
            return NULL;
        }

 setupEventTimer(timer);
        strncpy(timer->id, id, EVENTTIMER_MAX_DESC);
 /* maintain the linked list */
 if(_first == NULL) {//创建定时器链表
  _first = timer;
 }
 if(_last != NULL) {
     timer->_prev = _last;
     timer->_prev->_next = timer;
 }
 _last = timer;
 timer->_first = _first;
 DBGV("created itimer eventtimer %s\n", timer->id);
        return timer;
}


void
setupEventTimer(EventTimer *timer)
{
 if(timer == NULL) {
     return;
 }
 memset(timer, 0, sizeof(EventTimer));
 timer->start = eventTimerStart_itimer;  //启动
 timer->stop = eventTimerStop_itimer;  //停止
 timer->reset = eventTimerReset_itimer;  //复位
 timer->shutdown = eventTimerShutdown_itimer; //关闭
 timer->isExpired = eventTimerIsExpired_itimer;  //判断定时器是否溢出,或者说是否到期了
 timer->isRunning = eventTimerIsRunning_itimer;   //定时器状态
}

//我们关键看下,启动和判断溢出
static void
eventTimerStart_itimer(EventTimer *timer, double interval)
{
 timer->expired = FALSE;
 timer->running = TRUE;
 /*
  *  US_TIMER_INTERVAL defines the minimum interval between sigalarms.
  *  timerStart has a float parameter for the interval, which is casted to integer.
  *  very small amounts are forced to expire ASAP by setting the interval to 1
  */
 timer->itimerLeft = (interval * 1E6) / US_TIMER_INTERVAL;
 if(timer->itimerLeft == 0){
  /*
   * the interval is too small, raise it to 1 to make sure it expires ASAP
   */
  timer->itimerLeft = 1;   //最小的计时单位时1
 }
 
 timer->itimerInterval = timer->itimerLeft;  //设置响应间隔
 DBG2("timerStart:     Set timer %s to %f  New interval: %d; new left: %d\n", timer->id, interval, timer->itimerLeft , timer->itimerInterval);
}

//溢出判断
static Boolean
eventTimerIsExpired_itimer(EventTimer *timer)
{
 Boolean ret;
 itimerUpdate(timer);
 ret = timer->expired;
 DBG2("timerIsExpired:   Timer %s %s expired\n", timer->id,
  timer->expired ? "is" : "is not");
 if(ret) {
     timer->expired = FALSE;
 }
 return ret;
}


static void
itimerUpdate(EventTimer *et)
{
 EventTimer *timer = NULL;
 if (elapsed <= 0)
  return;
 /*
  * if time actually passed, then decrease every timer left
  * the one(s) that went to zero or negative are:
  *  a) rearmed at the original time (ignoring the time that may have passed ahead)
  *  b) have their expiration latched until timerExpired() is called
  */
/*每次都减去elapsed,elapsed前面已经说了,是个全局计时
 *如果时间已经溢出了,他就重新计时,并返回溢出信号
 */

 for(timer = et->_first; timer != NULL; timer = timer->_next) {
     if ( (timer->itimerInterval > 0) && ((timer->itimerLeft -= elapsed) <= 0)) {
   timer->itimerLeft = timer->itimerInterval;
   timer->expired = TRUE;
  DBG("TimerUpdate:    Timer %s has now expired.  Re-armed with interval %d\n", timer->id, timer->itimerInterval);
     }
 }
 elapsed = 0;   //已经减去了,重置
}
//简单点说,就是使用一个全局定时器计数,再创建一系列定时器,轮询这些定时器是否溢出,已达到多个定时器的目的