欢迎访问小站,阅读此文http://www.yandong.org/archives/501
墙上时间,也就是距离1970年1月1日的时间,在linux kernel内部没多大用处,对其的应用多在用户空间。
本文的目的在于在kernel里面计算得到 进程创建的墙上时间
xtime.tv_sec - (jiffies/HZ ) + 300 + p->real_start_time.tv_sec
意思就是,当前的 墙上时间(xtime) 减去 系统启动后的节拍(jiffies) / 频率(HZ) 这样得到的是系统启动的墙上时间,即距离1970.1.1的秒数,然后再加上进程结构体中 保存的距离系统启动时间的秒数(p->real_start_time.tv_sec)。
下面分别解释:
p->real_start_time.tv_sec
其中的p是task_struct指针,指向的是进程创建距离系统启动的时间.
task_struct中有两个时间:start_time 和 real_start_time,其中后者包含睡眠时间。
下面是进程创建的部分源码
do_posix_clock_monotonic_gettime(&p->start_time); p->real_start_time = p->start_time; monotonic_to_bootbased(&p->real_start_time); //真实启动时间还须要加 上总的睡眠时间
摘自《深入理解linux内核》
所有的PC都包含一个叫实时时钟(Renl Time Clock RTC)的时钟,它是独立于CPU和所有其他芯片的。
即使当PC呗切断电源,RTC还继续工作,因为它靠一个小电池或蓄电池供电。CMOS RAM和RTC被集成在一个芯片上。
…
Linux只用RTC来获取时间和日期。不过对/dev/rtc设备文件操作,也允许对RTC编程。
内核利用 get_cmos_time函数从实时时钟上读取字1970.1.1(UTC)午夜以来经过的秒数。
xtime_lock顺序所(seqlock)消除了对xtime变量同时访问而可能发生的竞争条件,
对于2.6内核,其定义为(/include/linux/time.h)
extern struct timespec xtime;
对于3.5内核,其定义为(kernel/time/timekeeping.c)
struct timekeeper { ... struct timespec xtime; ... }; static struct timekeeper timekeeper;
xtime的获取
因为很难原子的访问结构体中的两个变量,所以kernel并不鼓励直接访问xtime变量,可以使用相关函数
//include/linux/time.h struct timespec current_kernel_time(void); extern void do_gettimeofday(struct timeval *tv);
所以如果在module里面直接使用 xtime,是不行的。但是可以通过硬编码的方式获取
比如:
long * xtime_ptr = &xtime; 或者 long * xtimr_ptr = 0xc0803980
其中的 0xc0803980这个值,是从System.map中获得的,xtime是个全局符号,所有从sytem.map中可以获得它的地址
root@hyd:/home/l# cat /boot/System.map-2.6 | grep xtime c0156230 T update_xtime_cache c06e3c00 D xtime_lock c072f654 D inet_peer_gc_maxtime c0803980 B xtime c08039a0 b xtime_cache
简介
全局变量jiffies用来记录自系统启动以来产生的节拍的总数。
它被用来记录系统自开机以来,已经过了多少tick。每发生一次timer interrupt,Jiffies变数会被加一。
启动时,内核将该变量初始化为0,此后,每次时钟中断处理程序都会增加该变量的值。
因为一秒内时钟中断的次数等于Hz,所以jiffes一秒内增加的值也就为Hz,系统运行时间以秒为单位计算,就等于jiffes/Hz。
定义
extern u64 __jiffy_data jiffies_64; extern unsigned long volatile __jiffy_data jiffies;
其中,jiffies_64 和 jiffies 的低32位是重合的,因为32为的jiffies 最多50天就溢出了,而jiffies_64则不用关注溢出问题。
初始化
#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) jiffies =INITIAL_JIFFIES
可以看出 jiffies 被初始化为5分钟后溢出的一个值,这是为了方便内核调试,以便故障早点出来。
获取
由于jiffies_64 是一个符合变量,不能直接获取,需要下面的使用辅助函数
#if (BITS_PER_LONG < 64) u64 get_jiffies_64(void); #else static inline u64 get_jiffies_64(void) { return (u64)jiffies; } #endif
当然也可以使用硬编码的方式使用 jiffies
root@hy:/home/# cat /boot/System.map | grep "D jiffies" c06e3b00 D jiffies c06e3b00 D jiffies_64
从中也可以看到 jiffies 与 jiffies_64的地址是相同的
使用
由于jiffies在五分钟之后,便溢出,所以使用jiffies的原则如下
//如果jiffies变量类型是32位无符号int max_count = 0xffffffff or max_count = 0xffffffff ffffffff (64-bit) //如果没有溢出,系统启动后运行的节拍数: jiffies - ITIAL_JIFFIES //系统启动来5分钟的节拍数就是(到jiffies溢出的前一拍): max_count - INITIAL_JIFFIES
在我的代码中,我是这样使用的
unsigend long jiffies_test = jiffies + HZ; if( time_after(jiffies, jiffies_test)) { jiffies = MAX_JIFFIES - jiffies; }else { jiffies = jiffies - INITIAL_JIFFIES; }
其中的 time_after 是内核提供的四个比较函数之一
#define time_after(a,b) \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((long)(b) - (long)(a) < 0)) #define time_before(a,b) time_after(b,a) #define time_after_eq(a,b) \ (typecheck(unsigned long, a) && \ typecheck(unsigned long, b) && \ ((long)(a) - (long)(b) >= 0)) #define time_before_eq(a,b) time_after_eq(b,a)
为什么time_after能判断溢出呢?
待续,或者 参考下面链接
http://book.51cto.com/art/200810/93773.htm
http://blog.csdn.net/michaelcao1980/article/details/7826326
http://lxr.oss.org.cn/source/include/linux/jiffies.h?v=2.6.30#L167
http://blog.csdn.net/chchchdx123/article/details/6270022
http://linux.gongxiang8.com/456430/
如果您喜欢这篇文章,欢迎分享订阅。本文内容遵CC版权协议 转载请注明出处www.yandong.org