zoukankan      html  css  js  c++  java
  • hwclock和date源码分析

    一. hwclock

      1.1 hwclock源码在哪里?

        util-linux 或者busybox

      1.2 获取源码

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

        或

        git clone git://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, int utc)
    {
    #if 1
        struct timeval tv;
        struct tm tm_time;
        int rtc;
    
        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 clone https://github.com/coreutils/coreutils.git

        或

        wget https://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
      struct timeval 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)
          return r;
      }
    #endif
    
    #if HAVE_SETTIMEOFDAY
      {
        struct timeval 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, const clockid_t, which_clock,
                    const struct __kernel_timespec __user *, tp)
    {
            const struct k_clock *kc = clockid_to_kclock(which_clock);
            struct timespec64 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 struct syscall_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 struct syscall_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__));               
                    return ret;                                                     
            }                                                                       
            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 struct syscall_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 struct syscall_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__));               
                    return ret;                                                     
               }                                                                       
               static inline long __do_sys_clock_settime(__MAP(x,__SC_DECL,__VA_ARGS__))
            {
                  const struct k_clock *kc = clockid_to_kclock(which_clock);
                  struct timespec64 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(const clockid_t which_clock,
                                        const struct timespec64 *tp)
    {
            return do_sys_settimeofday64(tp, NULL);
    }

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

     

    三. 参考资料

      请看这里 

        

  • 相关阅读:
    OJ 之 FATE
    hdu 1701 (Binary Tree Traversals)(二叉树前序中序推后序)
    POJ 1789 Truck History
    数据结构之 普利姆算法总结
    HDU OJ 2159 FATE
    The Great Pan
    2014年的暑假ACM之旅!
    0-1背包问题
    中国剩余定理的解释!
    POJ 1183 反正切函数的应用
  • 原文地址:https://www.cnblogs.com/dakewei/p/11346895.html
Copyright © 2011-2022 走看看