您的位置:首页 > 编程语言 > PHP开发

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

2017-06-23 17:07 393 查看
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;   //已经减去了,重置
}
//简单点说,就是使用一个全局定时器计数,再创建一系列定时器,轮询这些定时器是否溢出,已达到多个定时器的目的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: