我有一个 Linux 系统,我需要定期对系统时间进行小幅调整以跟踪外部时间源,但我想避免日期/时间跳跃。
我想过使用 adjtimex()
内核函数(参见:adjtimex(2)、adjtimex(8)),但我有一些疑问:
- offset 和 singleshot 模式之间到底有什么区别?
- 可接受的参数范围是多少?我问是因为:
- adjtimex(8)提到
--offset
的参数必须在 -512000...512000 范围内(因此它只能校正 +/- 0.5s),并且没有提及任何值--singleshot
- adjtimex(2)提到范围 -131071..+131071 显然适用于两种模式
- 在我的测试中(使用
adjtimex
命令行实用程序)这些限制似乎都不适用
- adjtimex(8)提到
感谢任何帮助。
最佳答案
(请参阅 Linux 手册页的 Linux man-pages project。它们很可能是最新的。注释表明实现的逻辑应遵循 RFC 1305。)
有关实现细节,只需浏览 Linux 内核源代码即可。 adjtimex()
系统调用在 kernel/time.c 中定义;寻找 SYSCALL_DEFINE.*(adjtimex,
。
adjtimex()
本身调用在 kernel/time/timekeeping.c 中定义的 do_adjtimex()
.基本范围检查在 kernel/time/ntp.c 中定义的 ntp_validate_timex()
中完成.
关于您的具体问题:
如果您使用
ADJ_OFFSET_SINGLESHOT
,adjtimex()
的行为与adjtime()
相同,您只能使用.offset
字段。根据调整的大小和符号,NTP 时钟会在短时间内加快或减慢,直到达到所需的偏移量;然后 NTP 时钟速率恢复到原来的状态。您不能将任何其他模式标志与它一起使用。ADJ_SETOFFSET
添加.time
到当前时间;立即将时钟拨快。ADJ_OFFSET
还会调整 NTP 时钟速率以在合理的时间内实现所需的偏移量,因此效果应该与单次模式相同。但是,您也可以在同一调用中使用其他ADJ_
模式标志。根据 Grodriguez 的评论进行编辑:
ADJ_OFFSET
只有在偏移被认为是好的情况下才会起作用,即时钟状态是锁相的,STA_PLL
。通常,如果采样间隔很长,或者 NTP 守护进程的样本不好,NTP 守护进程会将状态更改为频率锁定 (STA_FLL
)。要使用
ADJ_OFFSET
,您的程序可能应该使用模式modeADJ_OFFSET|ADJ_STATUS
,并设置.status=STA_PLL
。这会导致当前时间被设置为引用时间,以便相对于当前系统时间计算偏移量,并启用时钟偏移量调整。在内核源代码中,
MAXPHASE
常量(在 include/linux/timex.h 中)定义了偏移限制。目前以纳秒为单位,指定半秒;较大的值(幅度)被安静地限制在半秒内,没有任何错误。在 2.6.26 之前的 Linux 内核中,限制更小 (±131071µs)。在 May 2008 中添加了新限制.
(限制的更改已传达给 Linux 手册页维护者 Michael Kerrisk,in June 2009 但显然 adjtimex(2) 手册页从未更新以反射(reflect)此更改。我不认为建议的措辞是不过,足够清楚了。)
关于c - 使用 adjtimex 进行小的时间调整,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21732321/