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 = ;
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源码分析的更多相关文章
- cstore_fdw的安装使用以及源码分析
一.cstore_fdw的简介 https://github.com/citusdata/cstore_fdw,此外部表扩展是由citusdata公司开发,使用RC_file格式对数据进行列式存储. ...
- 【JUC】JDK1.8源码分析之AbstractQueuedSynchronizer(二)
一.前言 在锁框架中,AbstractQueuedSynchronizer抽象类可以毫不夸张的说,占据着核心地位,它提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.所以很有必 ...
- jQuery-1.9.1源码分析系列(一)整体架构续
这一节主要是jQuery中最基础的几个东东 2. jQuery的几个基础属性和函数 a. jQuery.noConflict函数详解 在jQuery初始化的时候保存了外部的$和jQuery _j ...
- jQuery-1.9.1源码分析系列(十六)ajax——响应数据处理和api整理
ajax在得到请求响应后主要会做两个处理:获取响应数据和使用类型转化器转化数据 a.获取响应数据 获取响应数据是调用ajaxHandleResponses函数来处理. ajaxHandleRespon ...
- angular源码分析:angular中脏活累活承担者之$parse
我们在上一期中讲 $rootscope时,看到$rootscope是依赖$prase,其实不止是$rootscope,翻看angular的源码随便翻翻就可以发现很多地方是依赖于$parse的.而$pa ...
- YARN DistributedShell源码分析与修改
YARN DistributedShell源码分析与修改 YARN版本:2.6.0 转载请注明出处:http://www.cnblogs.com/BYRans/ 1 概述 2 YARN Distrib ...
- spring源码分析(二)Aop
创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...
- angular源码分析:angular中各种常用函数,比较省代码的各种小技巧
angular的工具函数 在angular的API文档中,在最前面就是讲的就是angular的工具函数,下面列出来 angular.bind //用户将函数和对象绑定在一起,返回一个新的函数 angu ...
- angular源码分析:angular中的依赖注入式如何实现的
一.准备 angular的源码一份,我这里使用的是v1.4.7.源码的获取,请参考我另一篇博文:angular源码分析:angular源代码的获取与编译环境安装 二.什么是依赖注入 据我所知,依赖注入 ...
随机推荐
- <转> Android LayoutInflater详解
在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById().不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例 ...
- unittest 运行slenium(四)---通过指定用例的形式运行用例
一: 说明 跟数据驱动唯一的区别为用例数据获取时,及运行方式不同. 其它都基本相同,可参考https://www.cnblogs.com/xiaodingdong/p/11753220.html 二: ...
- 读书笔记——《redis入门指南(第2版)》第七章 持久化
7 持久化 在一些情况下,我们会希望Redis 在重启后能够保证数据不丢失,例如: 1·将Redis 作为数据库使用时. 2·将Redis 作为缓存服务器,有可能出现的缓存雪崩会使服务无法响应. 这时 ...
- Tensorflow&CNN:验证集预测与模型评价
版权声明:本文为博主原创文章,转载 请注明出处:https://blog.csdn.net/sc2079/article/details/90480140 - 写在前面 本科毕业设计终于告一段落了.特 ...
- 科大讯飞语音识别Demo创建
1.下载官方SDK https://www.xfyun.cn/sdk/dispatcher 2.打开AS,选择import project 3.导入mscV5PlusDemo 4.解决ERROR: ...
- IDEA实用教程(二)
2. 基础设置 1) 进入全局设置 2) 更改主题 3) 修改主题字体 4) 修改代码编辑区字体 5) 修改控制台字体 图中3处修改控制台字体 图中4处修改控制台字体 6) 文件编码的设置 图中4处建 ...
- datatable修改每页默认显示的数量
datatable修改每页默认显示的数量 一.总结 一句话总结: iDisplayLength属性:'iDisplayLength':50 1.datatable默认每页显示50个? iDisplay ...
- MyBatis3_[tp_41-42-43]-_动态sql_trim_自定义字符串截取_choose分支选择_update的set与if-trim 结合的动态更新
笔记要点出错分析与总结 /** 笔记: * 查询的时候,如果某些条件,没带可能SQL拼装会有问题; * 1.-->给where 后面加上 1=1, 以后的条件都and XXX * 2. < ...
- jQuery实现点击复制效果
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" ...
- CSP模拟赛 Matrix(DP)
题面 求出满足以下条件的 n*m 的 01 矩阵个数: (1)第 i 行第 1~li 列恰好有 1 个 1. (2)第 i 行第 ri~m 列恰好有 1 个 1. (3)每列至多有 1 个 1. n, ...