0%

Linux 定时器

time api使用,定时器管理

  • clock_gettime
  • timespec_to_timeval
  • timeradd
  • timersub
  • timercmp

struct

enum
{
    DSMCC_TIMEOUT_DSI,
    DSMCC_TIMEOUT_DII,
    DSMCC_TIMEOUT_MODULE,
    DSMCC_TIMEOUT_NEXTBLOCK
};

struct dsmcc_timeout
{
    struct dsmcc_object_carousel *carousel;  /*< carousel this timeout applies to */
    int                           type;      /*< type of timeout */
    uint16_t                      module_id; /*< module ID, for type == DSMCC_TIMEOUT_MODULE or DSMCC_TIMEOUT_NEXTBLOCK */
    struct timeval                abstime;   /*< absolute time */

    struct dsmcc_timeout *next;
};

add/remove

void dsmcc_timeout_remove(struct dsmcc_object_carousel *carousel, int type, uint16_t module_id)
{
    struct dsmcc_timeout *current, *prev;

    current = carousel->state->timeouts;
    prev = NULL;
    while (current)
    {
        int match = current->carousel == carousel && current->type == type;
        if (type == DSMCC_TIMEOUT_MODULE || type == DSMCC_TIMEOUT_NEXTBLOCK)
            match &= current->module_id == module_id;
        if (match)
        {
            if (prev)
                prev->next = current->next;
            else
                carousel->state->timeouts = current->next;
            free(current);
            return;
        }
        prev = current;
        current = current->next;
    }
}

void dsmcc_timeout_set(struct dsmcc_object_carousel *carousel, int type, uint16_t module_id, uint32_t delay_us)
{
    struct dsmcc_timeout *timeout;
    struct dsmcc_timeout *current, *next;
    struct timeval now, delay;
    struct timespec ts;

    dsmcc_timeout_remove(carousel, type, module_id);

    if (!delay_us)
        return;

    DSMCC_DEBUG("Adding timeout for carousel 0x%08x type %d module id 0x%04hhx delay %uus", carousel->cid, type, module_id, delay_us);

    timeout = malloc(sizeof(struct dsmcc_timeout));
    timeout->carousel = carousel;
    timeout->type = type;
    timeout->module_id = module_id;

    clock_gettime(CLOCK_REALTIME, &ts);
    timespec_to_timeval(&ts, &now);

    delay.tv_sec = delay_us / 1000000;
    delay.tv_usec = delay_us - delay.tv_sec * 1000000;
    timeradd(&now, &delay, &timeout->abstime);

    current = NULL;
    next = carousel->state->timeouts;
    while (next && timercmp(&next->abstime, &timeout->abstime, <))
    {
        current = next;
        next = current->next;
    }
    timeout->next = next;
    if (current)
        current->next = timeout;
    else
        carousel->state->timeouts = timeout;
}

timer

struct dsmcc_timeout *prevtimeout, *timeout, *nexttimeout;

DSMCC_DEBUG("Current timeouts:");
timeout = state->timeouts;
prevtimeout = NULL;
while (timeout)
{
    struct timeval curtime;

    clock_gettime(CLOCK_REALTIME, &ts);
    timespec_to_timeval(&ts, &curtime);

    if (dsmcc_log_enabled(DSMCC_LOG_DEBUG))
    {
        struct timeval waittime;
        timersub(&timeout->abstime, &curtime, &waittime);
        DSMCC_DEBUG("CID 0x%08x DELAY %d.%06d TYPE %d MODULE_ID 0x%04hhx", timeout->carousel->cid, waittime.tv_sec, waittime.tv_usec,>
    }

    nexttimeout = timeout->next;
    if (timercmp(&timeout->abstime, &curtime, <))
    {
        dsmcc_object_carousel_set_status(timeout->carousel, DSMCC_STATUS_TIMEDOUT);
        dsmcc_filecache_notify_status(timeout->carousel, NULL);

        /* remove timeout */
        if (prevtimeout)
            prevtimeout->next = timeout->next;
        else
            state->timeouts = timeout->next;
        free(timeout);
    }
    timeout = nexttimeout;
}

api

头文件sys/time.h定义

Unix/Linux都是采用UTC(Universal Coordinated Time)1970.1.1到现在的秒数,采用time_t(long int)存储。

时间结构体包括time_t, timeval, time_spec,精度越来越高

typedef long time_t

表示为从UTC(coordinated universal time)时间1970 年 1 月 1 日 00 时 00 分 00 秒( 也称为 Linux 系统的 Epoch 时间 ) 到当前时刻的秒数,只是精确到秒

struct timeval
{
    time_t  tv_sec; // 秒 s
    long    tv_usec;// 微秒 us
};

精确到微秒

struct timespec
{
    long int tv_sec;    // 秒 s
    long int tv_nsec;   // 纳秒 ns
};

精确到纳秒

clock_gettime

#include <time.h>

struct timespec {
    time_t   tv_sec;        /* seconds */
    long     tv_nsec;       /* nanoseconds */
};

int clock_gettime(clockid_t clk_id, struct timespec *tp);

clk_id常用:

  1. CLOCK_REALTIME, 系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,中间时刻如果系统时间被用户改成其他,则对应的时间相应改变
  2. CLOCK_MONOTONIC, 从系统启动这一刻起开始计时,不受系统时间被用户改变的影响

timespec_to_timeval

struct timespecstruct timespec之间的转换

/* Macros for converting between `struct timeval' and `struct timespec'.  */
# define TIMEVAL_TO_TIMESPEC(tv, ts) {                                   \
        (ts)->tv_sec = (tv)->tv_sec;                                    \
        (ts)->tv_nsec = (tv)->tv_usec * 1000;                           \
}
# define TIMESPEC_TO_TIMEVAL(tv, ts) {                                   \
        (tv)->tv_sec = (ts)->tv_sec;                                    \
        (tv)->tv_usec = (ts)->tv_nsec / 1000;                           \
}

timeval 运算

sys/time.h中定义了如下运算

/* Convenience macros for operations on timevals.
   NOTE: `timercmp' does not work for >= or <=.  */
# define timerisset(tvp)    ((tvp)->tv_sec || (tvp)->tv_usec)
# define timerclear(tvp)    ((tvp)->tv_sec = (tvp)->tv_usec = 0)
# define timercmp(a, b, CMP)                              \
  (((a)->tv_sec == (b)->tv_sec) ?                         \
   ((a)->tv_usec CMP (b)->tv_usec) :                          \
   ((a)->tv_sec CMP (b)->tv_sec))
# define timeradd(a, b, result)                           \
  do {                                        \
    (result)->tv_sec = (a)->tv_sec + (b)->tv_sec;                 \
    (result)->tv_usec = (a)->tv_usec + (b)->tv_usec;                  \
    if ((result)->tv_usec >= 1000000)                         \
      {                                       \
    ++(result)->tv_sec;                           \
    (result)->tv_usec -= 1000000;                         \
      }                                       \
  } while (0)
# define timersub(a, b, result)                           \
  do {                                        \
    (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;                 \
    (result)->tv_usec = (a)->tv_usec - (b)->tv_usec;                  \
    if ((result)->tv_usec < 0) {                          \
      --(result)->tv_sec;                             \
      (result)->tv_usec += 1000000;                       \
    }                                         \
  } while (0)