hwclock和date源码分析

摘要:
一.hwclock1.1hwclock源码在哪里? 二.date2.1date的源码在哪里coreutils2.2获取源码gitclonehttps://github.com/coreutils/coreutils.git或wgethttps://ftp.gnu.org/pub/gnu/coreutils/coreutils-8.31.tar.xz2.3date的源码路径src/date.c2.4如何获取时间使用gettime接口2.5gettime接口又是怎么实现的呢? /*Getthesystemtimeinto*TS.*/voidgettime{#ifdefinedCLOCK_REALTIME&&HAVE_CLOCK_GETTIMEclock_gettime;#elsestructtimevaltv;gettimeofday;ts-˃tv_sec=tv.tv_sec;ts-˃tv_nsec=tv.tv_usec*1000;#endif}2.6从以上源码中可以看出时间要么通过clock_gettime获取,要么通过gettimeofday获取这两个接口的差异为:clock_gettime提供纳秒级精度,而后者提供微秒级精度2.7如何设置时间呢?  /*Setthesystemtime.*/intsettime{#ifdefinedCLOCK_REALTIME&&HAVE_CLOCK_SETTIME{intr=clock_settime;ifreturnr;}#endif#ifHAVE_SETTIMEOFDAY{structtimevaltv;tv.tv_sec=ts-˃tv_sec;tv.tv_usec=ts-˃tv_nsec/1000;returnsettimeofday;}#elifHAVE_STIME/*ThisfailstocompileonOSF1V5.1,duetostimerequiringa'longint*'andtv_secis'int'.Butthatsystemdoesprovidesettimeofday.*/returnstime;#elseerrno=ENOSYS;return-1;#endif}2.9从以上settime的源码可以看出,要么通过clock_settime接口设置,要么通过settimeofday接口设置2.10那么linux内核中clock_settime是如何实现的呢?先看看kernel/time/posix-timers.c文件中的定义     SYSCALL_DEFINE2{conststructk_clock*kc=clockid_to_kclock;structtimespec64new_tp;if(!

一. hwclock

1.1 hwclock源码在哪里?

util-linux 或者busybox

1.2 获取源码

git clone https://github.com/karelzak/util-linux.git

git clonegit://git.busybox.net/busybox

1.3 hwclock的源码路径

sys-utils/hwclock.c

util-linux/hwclock.c

1.4 分析busybox中的util-linux/hwclock.c

    if (opt &HWCLOCK_OPT_HCTOSYS)
        to_sys_clock(&rtcname, utc);
    else if (opt &HWCLOCK_OPT_SYSTOHC)
        from_sys_clock(&rtcname, utc);
    else if (opt &HWCLOCK_OPT_SYSTZ)
        set_system_clock_timezone(utc);
    else
        /*default HWCLOCK_OPT_SHOW */
        show_clock(&rtcname, utc);

1.4.1 分析from_sys_clock     

static void from_sys_clock(const char **pp_rtcname, intutc)
{
#if 1
    structtimeval tv;
    structtm tm_time;
    intrtc;
    rtc =rtc_xopen(pp_rtcname, O_WRONLY);
    gettimeofday(&tv, NULL);
    /*Prepare tm_time */
    if (sizeof(time_t) == sizeof(tv.tv_sec)) {
        if(utc)
            gmtime_r((time_t*)&tv.tv_sec, &tm_time);
        else
            localtime_r((time_t*)&tv.tv_sec, &tm_time);
    } else{
        time_t t =tv.tv_sec;
        if(utc)
            gmtime_r(&t, &tm_time);
        else
            localtime_r(&t, &tm_time);
    }
#else
...
#endif
   tm_time.tm_isdst = 0;
   xioctl(rtc, RTC_SET_TIME, &tm_time);if(ENABLE_FEATURE_CLEAN_UP)
       close(rtc);
}

总结: hwclock将会从rtc硬件(寄存器)中读取时间或往rtc硬件中写入时间,与rtc硬件息息相关。 

二. date

2.1 date的源码在哪里

coreutils

2.2 获取源码

git clonehttps://github.com/coreutils/coreutils.git

wgethttps://ftp.gnu.org/pub/gnu/coreutils/coreutils-8.31.tar.xz

2.3 date的源码路径

src/date.c

2.4 如何获取时间

使用gettime接口(这是glibc中的接口)

2.5 gettime接口又是怎么实现的呢? 

/*Get the system time into *TS.  */
void
gettime (struct timespec *ts)
{
#if defined CLOCK_REALTIME && HAVE_CLOCK_GETTIME
  clock_gettime (CLOCK_REALTIME, ts);
#else
  structtimeval tv;
  gettimeofday (&tv, NULL);
  ts->tv_sec =tv.tv_sec;
  ts->tv_nsec = tv.tv_usec * 1000;
#endif
}

2.6 从以上源码中可以看出时间要么通过clock_gettime获取,要么通过gettimeofday获取

这两个接口的差异为:

clock_gettime提供纳秒级精度,而后者提供微秒级精度

2.7 如何设置时间呢?

使用settime接口(这是glibc中的接口)

2.8 settime接口又是怎么实现的呢?  

/*Set the system time.  */
int
settime (struct timespec const *ts)
{
#if defined CLOCK_REALTIME && HAVE_CLOCK_SETTIME
  {
    int r =clock_settime (CLOCK_REALTIME, ts);
    if (r == 0 || errno ==EPERM)
      returnr;
  }
#endif
#if HAVE_SETTIMEOFDAY
  {
    structtimeval tv;
    tv.tv_sec = ts->tv_sec;
    tv.tv_usec = ts->tv_nsec / 1000;
    return settimeofday (&tv, 0);
  }
#elif HAVE_STIME
  /*This fails to compile on OSF1 V5.1, due to stime requiring
     a 'long int*' and tv_sec is 'int'.  But that system does provide
     settimeofday.  */
  return stime (&ts->tv_sec);
#else
  errno =ENOSYS;
  return -1;
#endif
}

2.9 从以上settime的源码可以看出,要么通过clock_settime接口(linux内核中的系统调用)设置,要么通过settimeofday接口(linux内核中的系统调用)设置

2.10 那么linux内核中clock_settime是如何实现的呢?

请看下面的系统调用定义     

#define __NR_clock_settime64 404
__SYSCALL(__NR_clock_settime64, sys_clock_settime)

2.10.1 __SYSCALL是如何定义的?(arch/arm64/kernel/sys.c)

#define __SYSCALL(nr, sym)      [nr] = __arm64_##sym,

2.10.2 展开后即为

[404] = __arm64_sys_clock_settime,

2.10.3 看一下__arm64_sys_clock_settime在哪里?先看看kernel/time/posix-timers.c文件中的定义     

SYSCALL_DEFINE2(clock_settime, constclockid_t, which_clock,
                const struct __kernel_timespec __user *, tp)
{
        const struct k_clock *kc =clockid_to_kclock(which_clock);
        structtimespec64 new_tp;
        if (!kc || !kc->clock_set)
                return -EINVAL;
        if (get_timespec64(&new_tp, tp))
                return -EFAULT;
        return kc->clock_set(which_clock, &new_tp);
}

2.10.4 SYSCALL_DEFINE2是如何定义的? (include/linux/syscalls.h)

#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__)

#define SYSCALL_DEFINEx(x, sname, ...)
SYSCALL_METADATA(sname, x, __VA_ARGS__)
__SYSCALL_DEFINEx(x, sname, __VA_ARGS__)    

#define SYSCALL_METADATA(sname, nb, ...)                        
        static const char *types_##sname[] ={                  
                __MAP(nb,__SC_STR_TDECL,__VA_ARGS__)            
        };                                                      
        static const char *args_##sname[] ={                   
                __MAP(nb,__SC_STR_ADECL,__VA_ARGS__)            
        };                                                      
        SYSCALL_TRACE_ENTER_EVENT(sname);                       
        SYSCALL_TRACE_EXIT_EVENT(sname);                        
        static structsyscall_metadata __used                   
          __syscall_meta_##sname ={                            
                .name           = "sys"#sname,                  
                .syscall_nr     = -1,   /*Filled in at boot */
                .nb_args        =nb,                           
                .types          = nb ?types_##sname : NULL,    
                .args           = nb ?args_##sname : NULL,     
                .enter_event    = &event_enter_##sname,         
                .exit_event     = &event_exit_##sname,          
                .enter_fields   =LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), 
        };                                                      
        static structsyscall_metadata __used                   
          __attribute__((section("__syscalls_metadata")))       
         *__p_syscall_meta_##sname = &__syscall_meta_##sname;
#define __SYSCALL_DEFINEx(x, name, ...)                                         
        asmlinkage long __arm64_sys##name(const struct pt_regs *regs);          
        ALLOW_ERROR_INJECTION(__arm64_sys##name, ERRNO);                        
        static long__se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__));             
        static inline long__do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));      
        asmlinkage long __arm64_sys##name(const struct pt_regs *regs)           
        {                                                                       
                return__se_sys##name(SC_ARM64_REGS_TO_ARGS(x,__VA_ARGS__));    
        }                                                                       
        static long__se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))              
        {                                                                       
                long ret =__do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));      
                __MAP(x,__SC_TEST,__VA_ARGS__);                                 
                __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));               
                returnret;                                                     
        }                                                                       
        static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))

2.10.5 展开一下看看

SYSCALL_DEFINEx(2, _clock_settime,__VAARGS__)

-> SYSCALL_METADATA(_clock_settime,2,__VA_ARGS__)

__SYSCALL_DEFINEx(2, _clock_settime, __VA_ARGS__)

-> static const char *types__clock_settime[] = {

__MAP(2,__SC_STR_TDECL,__VA_ARGS__)            
           };                                                      
           static const char *args__clock_settime[] ={                   
                __MAP(2,__SC_STR_ADECL,__VA_ARGS__)            
           };                                                      
           SYSCALL_TRACE_ENTER_EVENT(_clock_settime);                       
           SYSCALL_TRACE_EXIT_EVENT(_clock_settime);                        
           static structsyscall_metadata __used                   
              __syscall_meta__clock_settime ={                            
                .name           = "sys_clock_settime",                  
                .syscall_nr     = -1,   /* Filled in at boot */.nb_args        =2,                           
                .types          = 2 ?types__clock_settime : NULL,    
                .args           = 2 ?args__clock_settime : NULL,     
                .enter_event    = &event_enter__clock_settime,         
                .exit_event     = &event_exit__clock_settime,          
                .enter_fields   =LIST_HEAD_INIT(__syscall_meta__clock_settime.enter_fields), 
           };                                                      
           static structsyscall_metadata __used                   
              __attribute__((section("__syscalls_metadata")))       
             *__p_syscall_meta__clock_settime = &__syscall_meta__clock_settime; 
asmlinkage long __arm64_sys_clock_settime(const struct pt_regs *regs);          
           ALLOW_ERROR_INJECTION(__arm64_sys_clock_settime, ERRNO);                        
           static long__se_sys_clock_settime(__MAP(x,__SC_LONG,__VA_ARGS__));             
           static inline long__do_sys_clock_settime(__MAP(x,__SC_DECL,__VA_ARGS__));      
           asmlinkage long __arm64_sys_clock_settime(const struct pt_regs *regs)           
           {                                                                       
                return__se_sys_clock_settime(SC_ARM64_REGS_TO_ARGS(x,__VA_ARGS__));    
           }                                                                       
           static long__se_sys_clock_settime(__MAP(x,__SC_LONG,__VA_ARGS__))              
           {                                                                       
                long ret =__do_sys_clock_settime(__MAP(x,__SC_CAST,__VA_ARGS__));      
                __MAP(x,__SC_TEST,__VA_ARGS__);                                 
                __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));               
                returnret;                                                     
           }                                                                       
           static inline long __do_sys_clock_settime(__MAP(x,__SC_DECL,__VA_ARGS__))
{
              const struct k_clock *kc =clockid_to_kclock(which_clock);
              structtimespec64 new_tp;
              if (!kc || !kc->clock_set)
                    return -EINVAL;
              if (get_timespec64(&new_tp, tp))
                    return -EFAULT;
              return kc->clock_set(which_clock, &new_tp);
        }
2.10.6 发现最后执行的是结构体kc中的clock_set函数,那么是哪个clock_set呢?
看一下kernel/time/posix-timers.c中的clock_set域
static const struct k_clock clock_realtime ={
        .clock_getres           =posix_get_hrtimer_res,
        .clock_get              =posix_clock_realtime_get,
        .clock_set              =posix_clock_realtime_set,
        .clock_adj              =posix_clock_realtime_adj,
        .nsleep                 =common_nsleep,
        .timer_create           =common_timer_create,
        .timer_set              =common_timer_set,
        .timer_get              =common_timer_get,
        .timer_del              =common_timer_del,
        .timer_rearm            =common_hrtimer_rearm,
        .timer_forward          =common_hrtimer_forward,
        .timer_remaining        =common_hrtimer_remaining,
        .timer_try_to_cancel    =common_hrtimer_try_to_cancel,
        .timer_arm              =common_hrtimer_arm,
};

那就看看posix_clock_realtime_get()      

static int posix_clock_realtime_set(constclockid_t which_clock,
                                    const struct timespec64 *tp)
{
        returndo_sys_settimeofday64(tp, NULL);
}

总结: date不论更新时间还是设置时间都未涉及到rtc硬件,只是读取或设置的墙上时间(软时间)        

三. 参考资料

请看这里 

免责声明:文章转载自《hwclock和date源码分析》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇ECharts xAxis.type='time'时间轴时卡顿问题死锁问题------------------------INSERT ... ON DUPLICATE KEY UPDATE*(转)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

第12章 DOM操作

目录 *1. 向DOM中注入HTML 1.1 将HTNL字符串转换成DOM 预处理HTML源字符串 包装HTML 1.2 将DOM元素插入到文档中 2. DOM的特性和属性通过DOM方法和属性访问特性值 3. 令人头疼的样式特性 3.1 样式在何处 3.2 样式属性命名一种访问样式的简单方法 3.3 获取计算后样式 3.4 测量元...

基于R语言股票市场收益的统计可视化分析

原文链接:http://tecdat.cn/?p=16453  金融市场上最重要的任务之一就是分析各种投资的历史收益。要执行此分析,我们需要资产的历史数据。数据提供者很多,有些是免费的,大多数是付费的。在本文中,我们将使用Yahoo金融网站上的数据。 在这篇文章中,我们将: 下载收盘价 计算收益率 计算收益的均值和标准差 让我们先加载库。   li...

Android-Native-Server 启动和注册详细分析

Android-Native-Server 启动和注册详细分析 以mediaService为实例来讲解: mediaService的启动入口 是一个 传统的 main()函数 源码位置E:src_androidandroid_4.1.1_r1android_4.1.1_r1frameworksavmediamediaservermain_mediaserv...

element日期时间段选择器的使用心得

使用时间段 <el-date-picker // control the different select suitation v-if="selectOne == false" v-model="inputDate" unlink-panels type="datera...

libpcap编程实例

1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <pcap.h> 4 #include <errno.h> 5 #include <sys/socket.h> 6 #include <netinet/in...

snmp学习笔记

snmp5.5 client 包含头文件 #include <net-snmp/net-snmp-config.h> #include <net-snmp/net-snmp-includes.h> 用到的函数有:初始化snmp库:void init_snmp(const char *); 用于初始化snmp库 netsnmp_ses...