ktime 访问器

设备驱动程序可以使用 ktime_get() 和 linux/timekeeping.h 中声明的许多相关函数读取当前时间。 根据经验,如果两者都同样适合特定的用例,则优先使用名称较短的访问器而不是名称较长的访问器。

基于基本 ktime_t 的接口

推荐的最简单形式返回一个不透明的 ktime_t,带有返回不同时钟参考时间的变体

ktime_t ktime_get(void)

CLOCK_MONOTONIC

用于可靠的时间戳和精确测量短时间间隔。 从系统启动时间开始,但在暂停期间停止。

ktime_t ktime_get_boottime(void)

CLOCK_BOOTTIME

ktime_get() 类似,但在暂停时不会停止。 这可以用于例如需要与暂停操作跨越的其他机器同步的密钥过期时间。

ktime_t ktime_get_real(void)

CLOCK_REALTIME

返回相对于 1970 年开始的 UNIX 纪元的时间,使用协调世界时 (UTC),与用户空间的 gettimeofday() 相同。 这用于所有需要在重启后保持不变的时间戳,例如 inode 时间,但应避免内部使用,因为它可能会由于闰秒更新、NTP 调整用户空间设置时间的操作而向后跳跃。

ktime_t ktime_get_clocktai(void)

CLOCK_TAI

ktime_get_real() 类似,但使用国际原子时 (TAI) 参考而不是 UTC,以避免在闰秒更新时跳跃。 这在内核中很少有用。

ktime_t ktime_get_raw(void)

CLOCK_MONOTONIC_RAW

ktime_get() 类似,但以与硬件时钟源相同的速率运行,没有时钟漂移的 (NTP) 调整。 这在内核中也很少需要。

纳秒、timespec64 和秒输出

对于以上所有内容,有变体可以根据用户的要求以不同的格式返回时间

u64 ktime_get_ns(void)
u64 ktime_get_boottime_ns(void)
u64 ktime_get_real_ns(void)
u64 ktime_get_clocktai_ns(void)
u64 ktime_get_raw_ns(void)

与普通的 ktime_get 函数相同,但在相应的时间参考中返回一个 u64 纳秒数,这可能对某些调用者更方便。

void ktime_get_ts64(struct timespec64*)
void ktime_get_boottime_ts64(struct timespec64*)
void ktime_get_real_ts64(struct timespec64*)
void ktime_get_clocktai_ts64(struct timespec64*)
void ktime_get_raw_ts64(struct timespec64*)

与以上相同,但将时间以“struct timespec64”返回,分为秒和纳秒。 这可以避免在打印时间时或在将其传递到需要“timespec”或“timeval”结构的外部接口时进行额外的除法。

time64_t ktime_get_seconds(void)
time64_t ktime_get_boottime_seconds(void)
time64_t ktime_get_real_seconds(void)
time64_t ktime_get_clocktai_seconds(void)
time64_t ktime_get_raw_seconds(void)

返回一个粗粒度的、标量 time64_t 类型的时间值。这避免了访问时钟硬件,并使用相应的参考将秒数向下舍入到最后一个定时器滴答的完整秒数。

粗粒度和快速纳秒级访问

对于更特殊的情况,还存在一些额外的变体

ktime_t ktime_get_coarse(void)
ktime_t ktime_get_coarse_boottime(void)
ktime_t ktime_get_coarse_real(void)
ktime_t ktime_get_coarse_clocktai(void)
u64 ktime_get_coarse_ns(void)
u64 ktime_get_coarse_boottime_ns(void)
u64 ktime_get_coarse_real_ns(void)
u64 ktime_get_coarse_clocktai_ns(void)
void ktime_get_coarse_ts64(struct timespec64*)
void ktime_get_coarse_boottime_ts64(struct timespec64*)
void ktime_get_coarse_real_ts64(struct timespec64*)
void ktime_get_coarse_clocktai_ts64(struct timespec64*)

这些函数比非粗粒度版本更快,但精度较低,对应于用户空间的 CLOCK_MONOTONIC_COARSE 和 CLOCK_REALTIME_COARSE,以及用户空间中不可用的等效启动时间/tai/原始时间基准。

此处返回的时间对应于最后一个定时器滴答,这可能发生在过去 10 毫秒(对于 CONFIG_HZ=100),与读取“jiffies”变量相同。这些函数仅在快速路径中调用时有用,并且仍然期望比秒精度更好,但不能轻易使用“jiffies”,例如用于 inode 时间戳。跳过硬件时钟访问可以在大多数具有可靠循环计数器的现代机器上节省大约 100 个 CPU 周期,但在具有外部时钟源的旧硬件上最多可以节省几微秒。

u64 ktime_get_mono_fast_ns(void)
u64 ktime_get_raw_fast_ns(void)
u64 ktime_get_boot_fast_ns(void)
u64 ktime_get_tai_fast_ns(void)
u64 ktime_get_real_fast_ns(void)

这些变体可以安全地从任何上下文调用,包括在时间管理器更新期间从不可屏蔽中断 (NMI) 调用,以及在我们关闭时钟源电源进入挂起状态时调用。这在某些跟踪或调试代码以及机器检查报告中很有用,但大多数驱动程序永远不应调用它们,因为在某些条件下允许时间跳跃。

已弃用的时间接口

较旧的内核使用了一些其他接口,这些接口现在正在逐步淘汰,但可能会出现在此处移植的第三方驱动程序中。特别是,所有返回“struct timeval”或“struct timespec”的接口都已被替换,因为 tv_sec 成员在 32 位架构上会在 2038 年溢出。这些是建议的替换方案

void ktime_get_ts(struct timespec*)

请改用 ktime_get()ktime_get_ts64()

void do_gettimeofday(struct timeval*)
void getnstimeofday(struct timespec*)
void getnstimeofday64(struct timespec64*)
void ktime_get_real_ts(struct timespec*)

ktime_get_real_ts64() 是直接替代方案,但请考虑使用单调时间 (ktime_get_ts64()) 和/或基于 ktime_t 的接口 (ktime_get()/ktime_get_real())。

struct timespec current_kernel_time(void)
struct timespec64 current_kernel_time64(void)
struct timespec get_monotonic_coarse(void)
struct timespec64 get_monotonic_coarse64(void)

这些已被 ktime_get_coarse_real_ts64()ktime_get_coarse_ts64() 取代。然而,许多需要粗粒度时间的代码可以使用简单的 ‘jiffies’ 来代替,而一些驱动程序现在可能实际上需要更高分辨率的访问器。

struct timespec getrawmonotonic(void)
struct timespec64 getrawmonotonic64(void)
struct timespec timekeeping_clocktai(void)
struct timespec64 timekeeping_clocktai64(void)
struct timespec get_monotonic_boottime(void)
struct timespec64 get_monotonic_boottime64(void)

这些已被 ktime_get_raw()/ktime_get_raw_ts64(), ktime_get_clocktai()/ktime_get_clocktai_ts64() 以及 ktime_get_boottime()/ktime_get_boottime_ts64() 取代。然而,如果对于用户而言,时钟源的特定选择并不重要,为了保持一致性,请考虑转换为 ktime_get()/ktime_get_ts64()