当前实际时间(墙上时间)
- 在<Time.h(incluce/linux)>中
- extern struct timespec xtime;
- #ifndef _STRUCT_TIMESPEC
- #define _STRUCT_TIMESPEC
- struct timespec {
- time_t tv_sec; /* seconds */
- long tv_nsec; /* nanoseconds 十亿分之一秒*/
- };
- #endif
xtime.tv_sec以秒为单位,存放着自1970年7月1日(UTC)以来经过的时间,1970年1月1日被称为纪元。多数Unix系统的墙上时间都是基于该纪元而言的。xtime.tv_nsec记录自上一秒开始经过的纳秒数。
读写xtime变量需要使用xtime_lock锁,该锁是一个seqlock锁。
更新xtime首先要申请一个seqlock锁:
- write_seqlock(&xtime_lock);
- ……
- /*update xtime*/
- ……
- write_sequnlock(&xtime_lock);
读取xtime时也要使用read_seqbegin()函数和read_seqtry()函数:
- do{
- unsigned long lost;
- seq=read_seqbegin(&xtime_lock);
- usec=timer->get_offset();
- lost=jiffies-wall_jiffies;
- if(lost)
- usec+=lost*(1000000/HZ);
- sec=xtime.tv_sec;
- usec+=(xtime.tv_nsec/1000);
- }while(read_seqretry(&xtime_lock,seq))
该循环不断重复,直到读者确认读取数据时没有写操作介入。如果发现循环期间有时钟中断处理程序更新xtime,那么read_seqtry()函数就返回无效序列号,继续循环等待。
从用户空间取得墙上时间的主要接口是gettimeofday(),在内核中对应的系统调用为sys_gettimeofday():
- 在<Time.c(kernel)>中
- asmlinkage long sys_gettimeofday(struct timeval __user *tv, struct timezone __user *tz)
- {
- if (likely(tv != NULL)) {
- struct timeval ktv;
- do_gettimeofday(&ktv);
- if (copy_to_user(tv, &ktv, sizeof(ktv)))
- return -EFAULT;
- }
- if (unlikely(tz != NULL)) {
- if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))//把系统时区sys_tz返回用户
- return -EFAULT;
- }
- return 0;
- }
- //该函数与体系结构相关
- void do_gettimeofday (struct timeval *tv)
- {
- unsigned long seq, nsec, usec, sec, offset;
- //循环读取xtime
- do {
- seq = read_seqbegin(&xtime_lock);
- offset = time_interpolator_get_offset();
- sec = xtime.tv_sec;
- nsec = xtime.tv_nsec;
- } while (unlikely(read_seqretry(&xtime_lock, seq)));
- usec = (nsec + offset) / 1000;
- while (unlikely(usec >= USEC_PER_SEC)) {
- usec -= USEC_PER_SEC;
- ++sec;
- }
- tv->tv_sec = sec;
- tv->tv_usec = usec;
- }
- #ifdef CONFIG_TIME_INTERPOLATION
- void getnstimeofday (struct timespec *tv)
- {
- unsigned long seq,sec,nsec;
- do {
- seq = read_seqbegin(&xtime_lock);
- sec = xtime.tv_sec;
- nsec = xtime.tv_nsec+time_interpolator_get_offset();
- } while (unlikely(read_seqretry(&xtime_lock, seq)));
- while (unlikely(nsec >= NSEC_PER_SEC)) {
- nsec -= NSEC_PER_SEC;
- ++sec;
- }
- tv->tv_sec = sec;
- tv->tv_nsec = nsec;
- }
- #else
- #ifndef CONFIG_GENERIC_TIME
- /*
- * Simulate gettimeofday using do_gettimeofday which only allows a timeval
- * and therefore only yields usec accuracy
- */
- void getnstimeofday(struct timespec *tv)
- {
- struct timeval x;
- do_gettimeofday(&x);
- tv->tv_sec = x.tv_sec;
- tv->tv_nsec = x.tv_usec * NSEC_PER_USEC;
- }
- 在<Time.h(include/linux)>中
- struct timeval {
- time_t tv_sec; /* seconds */
- suseconds_t tv_usec; /* microseconds */
- };
- struct timezone {
- int tz_minuteswest; /* minutes west of Greenwich */
- int tz_dsttime; /* type of dst correction */
- };
虽然内核也实现了time()系统调用,但是gettimeofday()几乎完全取代了它。C库函数也提供了墙上时间相关的库调用,比如ftime(),ctime()。
除了更新xtime时间外,内核不会想用户空间程序那样频繁的使用xtime。但是,在文件系统的实现代码中存放访问时间戳(创建,存取,修改等)需要使用xtime。