Linux内核中的时间管理详解

Linux内核中的时间管理详解

引言

时间管理是Linux内核中最基础且最重要的功能之一,它为系统提供了计时、调度、超时处理等核心能力。没有精确的时间管理,系统调度、IO操作、网络超时等都将无法正常工作。本文将深入探讨Linux内核中的时间管理机制,包括时间源、定时器、时间统计和时间相关系统调用等。

时间管理基础

1. jiffies

jiffies是Linux内核中的全局变量,记录系统启动以来的时钟滴答数。

#include <linux/jiffies.h>

extern unsigned long volatile jiffies;
extern u64 jiffies_64;

// 转换为毫秒
unsigned long jiffies_to_msecs(unsigned long j);

// 转换为微秒
unsigned long jiffies_to_usecs(unsigned long j);

// 毫秒转换为jiffies
unsigned long msecs_to_jiffies(unsigned int m);

// 微秒转换为jiffies
unsigned long usecs_to_jiffies(unsigned int u);

2. HZ

HZ是内核配置选项,表示每秒的时钟中断次数。

  • 常用值
    • HZ=100:服务器,节能
    • HZ=250:桌面系统
    • HZ=1000:实时系统,高精度

3. 时间源

Linux支持多种时间源硬件:

  • TSC (Time Stamp Counter):CPU内置高精度计数器
  • HPET (High Precision Event Timer):高精度事件定时器
  • ACPI PM Timer:ACPI电源管理定时器
  • RTC:实时时钟

定时器

1. 低分辨率定时器(Timer)

基于jiffies的定时器,精度受限但开销小。

#include <linux/timer.h>

struct timer_list {
    struct list_head entry;
    unsigned long expires;
    void (*function)(unsigned long);
    unsigned long data;
    u32 flags;
};

// 初始化定时器
void timer_setup(struct timer_list *timer, 
                 void (*function)(unsigned long), 
                 unsigned int flags);

// 设置超时时间
void mod_timer(struct timer_list *timer, unsigned long expires);

// 添加定时器
void add_timer(struct timer_list *timer);

// 删除定时器
int del_timer(struct timer_list *timer);

// 同步删除
int del_timer_sync(struct timer_list *timer);

2. 定时器示例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/timer.h>

static struct timer_list my_timer;
static int count = 0;

static void my_timer_callback(struct timer_list *timer) {
    count++;
    printk(KERN_INFO "Timer callback %d\n", count);
    
    // 重新调度
    mod_timer(&my_timer, jiffies + msecs_to_jiffies(1000));
}

static int __init timer_demo_init(void) {
    timer_setup(&my_timer, my_timer_callback, 0);
    mod_timer(&my_timer, jiffies + msecs_to_jiffies(1000));
    
    printk(KERN_INFO "Timer demo started\n");
    return 0;
}

static void __exit timer_demo_exit(void) {
    del_timer_sync(&my_timer);
    printk(KERN_INFO "Timer demo stopped, count=%d\n", count);
}

module_init(timer_timer_demo_init);
module_exit(timer_demo_exit);

MODULE_LICENSE("GPL");

3. 高分辨率定时器(hrtimer)

基于硬件定时器,提供纳秒级精度。

#include <linux/hrtimer.h>

struct hrtimer {
    struct timerqueue_node node;
    ktime_t _softexpires;
    enum hrtimer_restart (*function)(struct hrtimer *);
    struct hrtimer_clock_base *base;
    u8 state;
    u8 is_rel;
};

// 初始化hrtimer
void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, 
                  enum hrtimer_mode mode);

// 启动hrtimer
int hrtimer_start(struct hrtimer *timer, ktime_t time, 
                  enum hrtimer_mode mode);

// 取消hrtimer
int hrtimer_cancel(struct hrtimer *timer);

// 获取当前时间
ktime_t ktime_get(void);
ktime_t ktime_get_real(void);
ktime_t ktime_get_boot_fast(clockid_t clock_id, bool fast);

// 时间转换
ktime_t ns_to_ktime(u64 ns);
ktime_t ms_to_ktime(s64 ms);

4. hrtimer示例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/hrtimer.h>
#include <linux/ktime.h>

static struct hrtimer my_hrtimer;
static int count = 0;

static enum hrtimer_restart my_hrtimer_callback(struct hrtimer *timer) {
    count++;
    printk(KERN_INFO "hrtimer callback %d\n", count);
    
    // 重新调度,1秒后
    hrtimer_forward_now(timer, ms_to_ktime(1000));
    return HRTIMER_RESTART;
}

static int __init hrtimer_demo_init(void) {
    ktime_t ktime;
    
    ktime = ms_to_ktime(1000);  // 1秒
    hrtimer_init(&my_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
    my_hrtimer.function = my_hrtimer_callback;
    hrtimer_start(&my_hrtimer, ktime, HRTIMER_MODE_REL);
    
    printk(KERN_INFO "hrtimer demo started\n");
    return 0;
}

static void __exit hrtimer_demo_exit(void) {
    hrtimer_cancel(&my_hrtimer);
    printk(KERN_INFO "hrtimer demo stopped, count=%d\n", count);
}

module_init(hrtimer_demo_init);
module_exit(hrtimer_demo_exit);

MODULE_LICENSE("GPL");

时间获取

1. 内核时间函数

#include <linux/time.h>

// 获取当前时间(timespec格式)
struct timespec timespec_add(struct timespec a, struct timespec b);
struct timespec timespec_sub(struct timespec a, struct timespec b);

// 获取当前时间(timeval格式)
struct timeval {
    time_t      tv_sec;
    suseconds_t tv_usec;
};

2. 时间测量

#include <linux/ktime.h>

// 使用ktime
ktime_t start, end, diff;

start = ktime_get();
// 操作
end = ktime_get();
diff = ktime_sub(end, start);
s64 ns = ktime_to_ns(diff);

// 使用cycles
cycles_t start_cycles, end_cycles;
start_cycles = get_cycles();
// 操作
end_cycles = get_cycles();

3. 时间测量示例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ktime.h>

static int __init time_measure_demo_init(void) {
    ktime_t start, end;
    s64 ns;
    int i;
    int sum = 0;
    
    start = ktime_get();
    for (i = 0; i < 1000000; i++) {
        sum += i;
    }
    end = ktime_get();
    
    ns = ktime_to_ns(ktime_sub(end, start));
    printk(KERN_INFO "Loop time: %lld ns\n", ns);
    
    return 0;
}

static void __exit time_measure_demo_exit(void) {
    printk(KERN_INFO "Time measure demo exit\n");
}

module_init(time_measure_demo_init);
module_exit(time_measure_demo_exit);

MODULE_LICENSE("GPL");

延迟执行

1. 忙等待

#include <linux/delay.h>

// 毫秒级延迟(忙等待)
mdelay(unsigned long msecs);

// 微秒级延迟(忙等待)
udelay(unsigned long usecs);

// 纳秒级延迟(忙等待)
ndelay(unsigned long nsecs);

2. 睡眠延迟

#include <linux/delay.h>

// 毫秒级睡眠(可中断)
unsigned long msleep(unsigned int msecs);

// 毫秒级睡眠(不可中断)
void msleep_interruptible(unsigned int msecs);

// 微秒级睡眠
void usleep_range(unsigned long min, unsigned long max);

3. 调度延迟

#include <linux/sched.h>

// 延迟到指定时间
signed long schedule_timeout(signed long timeout);

// 延迟到可中断
signed long schedule_timeout_interruptible(signed long timeout);

// 延迟到不可中断
signed long schedule_timeout_uninterruptible(signed long timeout);

4. 延迟执行示例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>

static int __init delay_demo_init(void) {
    printk(KERN_INFO "Delay demo start\n");
    
    // 忙等待
    mdelay(100);  // 100ms
    printk(KERN_INFO "After mdelay(100)\n");
    
    // 睡眠
    msleep(100);  // 100ms,可中断
    printk(KERN_INFO "After msleep(100)\n");
    
    usleep_range(1000, 2000);  // 1-2ms
    printk(KERN_INFO "After usleep_range\n");
    
    return 0;
}

static void __exit delay_demo_exit(void) {
    printk(KERN_INFO "Delay demo exit\n");
}

module_init(delay_demo_init);
module_exit(delay_demo_exit);

MODULE_LICENSE("GPL");

POSIX定时器

1. 创建定时器

#include <signal.h>
#include <time.h>

timer_t timerid;
struct sigevent sev;

// 创建定时器
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGUSR1;
sev.sigev_value.sival_ptr = &timerid;

timer_create(CLOCK_MONOTONIC, &sev, &timerid);

2. 设置定时器

#include <time.h>

struct itimerspec {
    struct timespec it_value;    // 首次到期时间
    struct timespec it_interval; // 周期
};

struct itimerspec its;

its.it_value.tv_sec = 1;
its.it_value.tv_nsec = 0;
its.it_interval.tv_sec = 1;
its.it_interval.tv_nsec = 0;

timer_settime(timerid, 0, &its, NULL);

3. 删除定时器

#include <time.h>

timer_delete(timerid);

4. POSIX定时器示例

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>

static void timer_handler(union sigval sv) {
    printf("Timer fired!\n");
}

int main(void) {
    timer_t timerid;
    struct sigevent sev;
    struct itimerspec its;
    
    sev.sigev_notify = SIGEV_THREAD;
    sev.sigev_notify_function = timer_handler;
    sev.sigev_value.sival_ptr = &timerid;
    
    timer_create(CLOCK_REALTIME, &sev, &timerid);
    
    its.it_value.tv_sec = 1;
    its.it_value.tv_nsec = 0;
    its.it_interval.tv_sec = 1;
    its.it_interval.tv_nsec = 0;
    
    timer_settime(timerid, 0, &its, NULL);
    
    sleep(10);
    
    timer_delete(timerid);
    return 0;
}

时钟管理

1. 系统时钟

Linux维护多个时钟:

  • CLOCK_REALTIME:实时时钟,可被设置
  • CLOCK_MONOTONIC:单调递增时钟,不可被设置
  • CLOCK_MONOTONIC_RAW:原始单调时钟
  • CLOCK_BOOTTIME:包含休眠时间的单调时钟
  • CLOCK_PROCESS_CPUTIME_ID:进程CPU时间
  • CLOCK_THREAD_CPUTIME_ID:线程CPU时间

2. adjtimex

用于调整系统时钟。

#include <linux/timex.h>

struct timex {
    int modes;
    long offset;
    long freq;
    long maxerror;
    long esterror;
    // ...
};

int adjtimex(struct timex *buf);

3. settimeofday

设置系统时间。

#include <sys/time.h>

struct timeval {
    time_t      tv_sec;
    suseconds_t tv_usec;
};

int settimeofday(const struct timeval *tv, const struct timezone *tz);

时间管理应用

1. 超时处理

#include <linux/net.h>

// socket超时设置
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

2. 性能分析

#include <linux/ktime.h>

ktime_t start = ktime_get();
// 执行被测操作
ktime_t end = ktime_get();
u64 elapsed = ktime_to_ns(ktime_sub(end, start));
printk(KERN_INFO "Operation took %llu ns\n", elapsed);

3. 速率限制

#include <linux/ratelimit.h>

static DEFINE_RATELIMIT_STATE(rate_limit, DEFAULT_RATE_COMPUTE, 
                              DEFAULT_RATE_BURST);

if (__ratelimit(&rate_limit)) {
    printk(KERN_INFO "Message\n");
}

结论

Linux内核的时间管理系统为系统提供了精确的时间基准和定时能力,是内核调度、IO超时、网络协议等核心功能的基础。理解时间管理机制对于系统编程、性能分析和问题诊断都有重要意义。在实际开发中,我们需要根据精度需求和性能考虑,选择合适的时间函数和定时器类型。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值