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源代码的获取与编译环境安装 二.什么是依赖注入 据我所知,依赖注入 ...
随机推荐
- Python 渗透测试编程技术方法与实践 ------全书整理
1.整个渗透测试的工作阶段 ( 1 )前期与客户的交流阶段.( 2 )情报的收集阶段.( 3 )威胁建模阶段.( 4 )漏洞分析阶段.( 5 )漏洞利用阶段.( 6 )后渗透攻击阶段.( 7 )报告阶 ...
- js基础知识2
DOM Document Object Model 文档 对象 模型 对象: 属性和方法 属性:获取值和赋值 方法:赋值方法和条用方法 DOM树 document hea ...
- 配置ubuntu18.04
关于Ubuntu18.04的配置: 首先在装好系统后需要配置VMware Tools,这个会在虚拟机退出全屏的时候给一个帮助链接,在帮助链接中有详细的教程. 教程链接:https://docs.vmw ...
- 前端学习笔记--CSS3
本本记录了css3的样式:浏览器支持度.圆角边框.阴影.文字与文本.过渡.动画.2d旋转.3d旋转 浏览器支持度: 1.圆角边框 例:只要确定了x.y值,就能知道弧度 画一个圆形:长=宽,border ...
- java中的深拷贝与浅拷贝
Java中对象的创建 clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象.那 ...
- Linux下干净卸载mysql
1.首先查看mysql的安装情况 rpm -qa|grep -i mysql 显示之前安装了: MySQL-client-5.5.25a-1.rhel5 MySQL-server-5.5.25a-1. ...
- CSP模拟赛 Lost My Music(二分,可回退化栈)
题面 题解 发现是斜率的形式,答案的相反数可以看做一条直线的斜率.那么我们要答案最小,斜率最大.维护下凸壳就行了. 考试时写了直接dfsdfsdfs+暴力弹栈拿了808080分(还以为自己是O(n)正 ...
- HTML 文字垂直剧中
HTML 有个使文字垂直剧中的代码 line-height: line-height:使用时 总高多少 后边就输入多少PX 剧中前展示 剧中后展示
- 重载new和delete运算符
内存管理运算符 new.new[].delete 和 delete[] 也可以进行重载,其重载形式既可以是类的成员函数,也可以是全局函数.一般情况下,内建的内存管理运算符就够用了,只有在需要自己管理内 ...
- Django系列(二):Django的路由层,视图层和模板层
1.Django的路由层 URL配置(URLconf)就像Django所支撑网站的目录.它的本质是URL与要为该URL调用的视图函数之间的映射表:我们就是以这种方式告诉Django,对于客户端发来的某 ...