一. 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 = ;
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 * ;
#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 == || errno == EPERM)
return r;
}
#endif #if HAVE_SETTIMEOFDAY
{
struct timeval tv; tv.tv_sec = ts->tv_sec;
tv.tv_usec = ts->tv_nsec / ;
return settimeofday (&tv, );
}
#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 -;
#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 = -, /* 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硬件,只是读取或设置的墙上时间(软时间)        

 

三. 参考资料

  请看这里 

    

hwclock和date源码分析的更多相关文章

  1. cstore_fdw的安装使用以及源码分析

    一.cstore_fdw的简介 https://github.com/citusdata/cstore_fdw,此外部表扩展是由citusdata公司开发,使用RC_file格式对数据进行列式存储. ...

  2. 【JUC】JDK1.8源码分析之AbstractQueuedSynchronizer(二)

    一.前言 在锁框架中,AbstractQueuedSynchronizer抽象类可以毫不夸张的说,占据着核心地位,它提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.所以很有必 ...

  3. jQuery-1.9.1源码分析系列(一)整体架构续

    这一节主要是jQuery中最基础的几个东东 2.    jQuery的几个基础属性和函数 a. jQuery.noConflict函数详解 在jQuery初始化的时候保存了外部的$和jQuery _j ...

  4. jQuery-1.9.1源码分析系列(十六)ajax——响应数据处理和api整理

    ajax在得到请求响应后主要会做两个处理:获取响应数据和使用类型转化器转化数据 a.获取响应数据 获取响应数据是调用ajaxHandleResponses函数来处理. ajaxHandleRespon ...

  5. angular源码分析:angular中脏活累活承担者之$parse

    我们在上一期中讲 $rootscope时,看到$rootscope是依赖$prase,其实不止是$rootscope,翻看angular的源码随便翻翻就可以发现很多地方是依赖于$parse的.而$pa ...

  6. YARN DistributedShell源码分析与修改

    YARN DistributedShell源码分析与修改 YARN版本:2.6.0 转载请注明出处:http://www.cnblogs.com/BYRans/ 1 概述 2 YARN Distrib ...

  7. spring源码分析(二)Aop

    创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...

  8. angular源码分析:angular中各种常用函数,比较省代码的各种小技巧

    angular的工具函数 在angular的API文档中,在最前面就是讲的就是angular的工具函数,下面列出来 angular.bind //用户将函数和对象绑定在一起,返回一个新的函数 angu ...

  9. angular源码分析:angular中的依赖注入式如何实现的

    一.准备 angular的源码一份,我这里使用的是v1.4.7.源码的获取,请参考我另一篇博文:angular源码分析:angular源代码的获取与编译环境安装 二.什么是依赖注入 据我所知,依赖注入 ...

随机推荐

  1. c# 接口使用

  2. linux运维之路配置网络

    前言裸机上装操作系统,想和物理机通信需要设置IP 开机以后: 第一步:setup命令  ——>  NetWork configguation  ---->Device configurat ...

  3. 为0LTP选择RDMBS时,你都需要考虑哪些?

    我们经常需要为自己的OLTP(事务/运营)数据库选择适合的RDBMS(关系型数据库管理系统).虽然通过编写可移植的SQL可以暂时避免进行这样的选择,但迟早要做出这样的选择,至少需要进行这样的尝试(比如 ...

  4. Vue 中的Vue Router一级路由,二级路由,三级路由以及跳转

    今天编写了一下Vue中的路由 先用命令行新建一个空的项目,并且我知道要用路由,就下载了路由的相关依赖 vue init webpack demo5 完毕之后进入所在的项目 cd demo5 之后用vs ...

  5. 5.Kafka消费者-从Kafka读取数据(转)

    http://www.dengshenyu.com/%E5%88%86%E5%B8%83%E5%BC%8F%E7%B3%BB%E7%BB%9F/2017/11/14/kafka-consumer.ht ...

  6. Git----拉取远程分支,git pull,git rebase,git pull --rebase的区别

    git pull 相当于自动的 fetch 和 merge 操作,会试图自动将远程库合并入本地库,在有冲突时再要求手动合并. git rebase 可以确保生产分支commit是一个线性结构,方便ro ...

  7. STM32的指令周期

    在keil中编程时,写了一行代码,然后就想知道,执行这句C代码需要多长时间. 时钟周期在这就不解释了,频率的倒数. 指令周期,个人理解就是cpu执行一条汇编指令所需要的时间. 我们知道cm3使用的三级 ...

  8. 发布一个在Web下输入密码时提示大写锁定键的Jquery插件

    功能介绍:在Web下输入密码时提示大写锁定键,封装成jq插件方便有需要的同学!使用:$("#txtPWD").capsLockTip();截图预览:代码(2012-05-03 10 ...

  9. 011——C#创建ecxel文件(附教程)

    (一)参考文献:[C#]创建表格(.xlsx)的典型方法 (二)视频教程:https://v.qq.com/x/page/t30068qfex5.html (三)下载地址:https://downlo ...

  10. 学到了林海峰,武沛齐讲的Day26 反射 组合的方式完成授

    class BlackMedium: feature='Ugly' def __init__(self,name,addr): self.name=name self.addr=addr def se ...