1.1 从AP来看Linux系统提供的时间机制
1.1.1 Time的表达方式
在Linux中从AP来看,时间有两种表达方式:
1. wall-clock time: 自从1970年1月1日0时0分0秒以来到现在的时间差,理论上精确到nano-second。我们称这个时间点为Linux基准时间(或者linux epoch)。此种表达方式有利于software实现。User Application可以使用time()/stime(),gettimeofday()/settimeofday()来获得;前者精确到second,后者理论上到nano-second。(ARM系统中一般到10ms)。
2. 现在的绝对时间,即:年,月,日,时,分,秒。这是User最终想看到的时间;RTC时间也如此。User Application可以使用gmtime()/mktime(),ctime()/asctime(),loactime()来进行两个表达方式的转换。(注意:这些都不是thread safe的,thread safe的版本:xxx_r,具体信息大家可以man一下就知道了。Why?)。
通常AP还需要创建一些定时器即timer,如:getitimer()/ setitimer():这些我们通常叫做Interval Timer,简称itimer,是指定时器采用“间隔”值(interval)作为计时方式,当定时器启动后,间隔值interval将不断减小。当 interval值减到0时,我们就说该间隔定时器到期,到期之后,内核一般会发送相应的signal给相应的进程。如果不删除itimer,itimer会周期性的到期并发送信号。
具体itimer可以使用不同的time base,具体如下:
◆ ITIMER_REAL:以ITIMER_REAL为time base的itimer在启动后,不管进程是否运行,不管是运行在内核态还是用户态,每个时钟滴答都将其间隔计数器减1。当减到0值时,内核向进程发送SIGALRM信号。
◆ ITIMER_VIRT:以ITIMER_VIRT为time base的itimer在启动后,只有该timer的owner进程是运行在用户态的时候,每个时钟滴答才将其间隔计数器减1。当减到0值时,内核向进程发送SIGVTALRM信号。
◆ ITIMER_PROF:以ITIMER_PROF为time base的itimer在启动后,只有在该timer的owner进程处于运行状态(不管是在用户态还是通过系统调用进入内核态)的时候,每个时钟滴答才将其间隔计数器减1。当减到0值时,内核向进程发送SIGPROF信号。
1.2 用top-down的方法从gettimeofday出发搞清楚Linux time的来龙去脉
gettimeofday(C lib function)=>> sys_gettimeofday=>>do_gettimeofday=>>__get_realtime_clock_ts:
static inline void __get_realtime_clock_ts(struct timespec *ts)
{
unsigned long seq;
s64 nsecs;
do {
seq = read_seqbegin(&xtime_lock);
*ts = xtime;
nsecs = __get_nsec_offset();
} while (read_seqretry(&xtime_lock, seq));
timespec_add_ns(ts, nsecs);
}
xtime的定义如下:(kernel/time/timekeeping.c)
struct timespec xtime __attribute__ ((aligned (16)));
该structure的定义如下:
struct timespec {
time_t tv_sec; /* seconds */ //自从1970年1月1日0时0分0秒数
long tv_nsec; /* nanoseconds */
};
1.2.2 xtime何时被初始化
cold boot的时候用rtc time更新xtime
start_kernel () =>> rest_init() =>> kernel_init() =>> do_basic_setup() =>> do_initcalls()中会调用rtc_hctosys:
1. rtc_read_time获得当前的rtc time。
2. rtc_tm_to_time将当前的rtc time转换为自从1970年1月1日0时0分0秒数
3. do_settimeofday=>>set_normalized_timespec(&xtime, sec, nsec); 设置xitme