内核变量——Jiffies

本文深入探讨了Linux内核中jiffies变量的作用,包括如何计算系统运行时间、jiffies变量的转换方法以及与时间相关的宏用法。通过实际代码示例,解释了如何利用jiffies进行定时和时间差计算。

全局变量jiffies表示自系统启动以来系统产生的嘀嗒数。当启动时,内核初始化该变量为0。每次时钟中断就会增1,所以系统运行时间可以计算为:jiffies/HZ秒。

       jiffies变量定义如下:

extern unsigned long volatile jiffies;

jiffies转换为秒:(jiffies / HZ)。将秒换算为jiffies(seconds*HZ)

       jiffies比较相关的宏

#define time_after(unknown, known) ((long)(known) - (long)(unknown) < 0)

#define time_before(unknown, known) ((long)(unknown) - (long)(known) < 0)

#define time_after_eq(unknown, known) ((long)(unknown) - (long)(known) >= 0)

#define time_before_eq(unknown, known) ((long)(known) - (long)(unknown) >= 0)

使用例子:

unsigned long timeout = jiffies + HZ/2;

/* timeout in 0.5s */

/* ... */

 

if (time_before(jiffies, timeout)) {

 

/* we did not time out, good ... */

 

} else {

 

/* we timed out, error ... */

 

}

 

代码参考:

typedef struct {
    unsigned long jiffies;
}os_time_t;

static inline osal_result os_clock_get_time(os_time_t *time){
    time->jiffies = jiffies;
    return OSAL_SUCCESS;
}

static inline osal_result os_clock_get_time_diff_msecs( os_time_t *time,
                                                        unsigned long *msecs)
{
    *msecs = (jiffies - time->jiffies) * 1000 / HZ;
    return OSAL_SUCCESS;
}

static inline osal_result os_clock_get_time_diff_secs(  os_time_t *time,
                                                        unsigned long *secs)
{
    *secs = (jiffies - time->jiffies) / HZ;
    return OSAL_SUCCESS;
}


在 Linux 内核中,**全局变量**的定义与用户空间程序类似,但由于内核是单个地址空间运行的大型 C 程序(不是多个进程独立作用域),其“全局”含义更强调**跨文件共享、在整个内核中可访问**。因此,内核中定义全局变量需要遵循特定的规则和机制。 --- ### 一、基本语法:C 语言的 `extern` 和 `static` #### 1. 定义一个全局变量(存储在 `.data` 或 `.bss` 段) ```c // file: kernel/time/timer.c #include <linux/jiffies.h> unsigned long volatile jiffies; // 全局变量 jiffies 的实际定义 ``` 这个变量就是著名的 `jiffies` —— 它是一个 **全局可读写的变量**,被成千上万个内核函数使用。 > 注意:`volatile` 是必须的,因为它的值可能被中断上下文修改,编译器不能优化掉重复读取。 --- #### 2. 在其他文件中声明该变量(使用 `extern`) ```c // file: include/linux/jiffies.h #include <linux/types.h> extern unsigned long volatile jiffies; ``` 这样任何包含 `<linux/jiffies.h>` 的源文件都可以访问 `jiffies`。 --- ### 二、如何组织内核中的全局变量? #### ✅ 正确做法: - **在一个 .c 文件中定义一次** - **在头文件中用 `extern` 声明** - 所有想使用的模块 `#include` 这个头文件即可 示例结构: ```c // kernel/my_module.c int my_global_counter = 0; // 实际定义 struct task_struct *global_daemon; // 可能指向某个守护进程 ``` ```c // include/linux/my_module.h #ifndef _LINUX_MY_MODULE_H #define _LINUX_MY_MODULE_H #include <linux/sched.h> extern int my_global_counter; extern struct task_struct *global_daemon; #endif ``` ```c // another_file.c #include <linux/my_module.h> #include <linux/kernel.h> void some_function(void) { my_global_counter++; printk("Counter: %d\n", my_global_counter); } ``` --- ### 三、特殊类型的全局变量 #### 1. 每 CPU 变量(per-CPU variables) 避免竞争条件的一种方式是为每个 CPU 单独保存一份副本。 ```c // 定义 per-cpu 变量 DEFINE_PER_CPU(int, cpu_load); // 使用时: int load = __get_cpu_var(cpu_load); // 获取当前 CPU 上的值(旧接口) // 或者使用新接口: raw_cpu_write(cpu_load, 100); ``` 这类变量不会引起锁争用,适合频繁读写但无需全局同步的场景。 #### 2. 初始化段控制(使用 `__initdata`, `__read_mostly` 等修饰符) ```c // 只在初始化阶段使用的全局变量,之后释放内存 static int __initdata debug_init_only = 0; // 很少修改、主要只读的变量,放入专属缓存行以提高性能 static struct timerqueue_head timer_queue __read_mostly; ``` 这些是由链接器段(section)支持的特性,帮助优化内核布局。 --- ### 四、注意事项 | 要点 | 说明 | |------|------| | ❗只能定义一次 | 避免 multiple definition 错误(违反 ODR:One Definition Rule) | | ✅推荐放在 `.c` 文件 | 不要将变量定义写进头文件(除非是 `static inline` 函数内部) | | 🔐并发访问需保护 | 多个 CPU 或中断可能同时访问,需配合自旋锁、互斥体等机制 | | 🧠注意内存对齐和缓存行 | 频繁访问的变量应避免“伪共享”(false sharing) | 例如加锁保护: ```c static DEFINE_SPINLOCK(my_lock); static int shared_counter; void inc_counter(void) { spin_lock(&my_lock); shared_counter++; spin_unlock(&my_lock); } ``` --- ### 五、查看内核中真实例子 你可以查看以下文件了解真实全局变量定义: - `kernel/time/timer.c`: `jiffies`, `xtime`, `wall_to_monotonic` - `kernel/sched/core.c`: `init_task`(初始任务结构体) - `mm/vmalloc.c`: `vmlist`(虚拟内存链表) 这些都是典型的全局变量,在整个内核广泛使用。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值