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超时、网络协议等核心功能的基础。理解时间管理机制对于系统编程、性能分析和问题诊断都有重要意义。在实际开发中,我们需要根据精度需求和性能考虑,选择合适的时间函数和定时器类型。

878

被折叠的 条评论
为什么被折叠?



