hwclock和date源码分析

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

hwclock和date源码分析⼀. hwclock
1.1 hwclock源码在哪⾥?
util-linux 或者busybox
1.2 获取源码

git clone git:///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(_sec)) {
if (utc)
gmtime_r((time_t*)&_sec, &tm_time);
else
localtime_r((time_t*)&_sec, &tm_time);
} else {
time_t t = _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 获取源码

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 = _sec;
ts->tv_nsec = _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;
_sec = ts->tv_sec;
_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硬件,只是读取或设置的墙上时间(软时间)
三. 参考资料
请看 。

相关文档
最新文档