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 调整或用户空间的 settimeofday() 操作而向后跳变。

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。这避免了访问时钟硬件,并将秒数向下舍入到上次计时器滴答的完整秒数,使用相应的参考。

粗粒度和 fast_ns 访问

存在一些额外的变体,适用于更专业的用例

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,以及用户空间中不可用的等效 boottime/tai/raw 时间基准。

这里返回的时间对应于上一个计时器滴答,可能最长达 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' 的接口都已被替换,因为在 32 位架构上,tv_sec 成员在 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()