jiffies 是 Linux 內核時間子系統的心跳計數器,定義為 unsigned long 類型,記錄系統啟動以來的時鐘中斷次數。理解其數據結構、轉換宏、64位擴展 jiffies_64、回繞處理機制,是內核開發者、驅動工程師掌握精準定時、延遲控制、超時判斷的核心技能。本文從底層定義到應用層最佳實踐,全景解析 jiffies 體系。

// include/linux/jiffies.h
extern u64 __jiffy_data jiffies_64; // 64 位完整計數器
extern unsigned long volatile __jiffy_data jiffies; // 32 位低位別名
jiffies / HZseconds * HZjiffies 必須用 unsigned long 存儲,任何有符號/浮點類型均錯誤| 架構 | jiffies_64 與 jiffies 關係 | get_jiffies_64() 實現 |
|---|---|---|
| 64 位 (x86_64, arm64) | 指向同一變量 | 直接返回 jiffies |
| 32 位 (i386, arm) | jiffies = jiffies_64 低 32 位 | 需在 xtime_lock 序列鎖保護下讀取完整 64 位值 |
// 32 位實現片段
u64 get_jiffies_64(void) {
unsigned long seq;
u64 ret;
do {
seq = read_seqbegin(&xtime_lock);
ret = jiffies_64;
} while (read_seqretry(&xtime_lock, seq));
return ret;
}
最佳實踐:統一使用 get_jiffies_64() 獲取完整計數,避免 32 位截斷導致長時間運行邏輯錯誤。
32 位 jiffies 最大值 2^32-1,對應運行時間:
超過週期將回繞歸零。內核提供四組有符號減法比較宏,正確處理回繞:
// include/linux/jiffies.h
#define time_after(a,b) ((long)(b) - (long)(a) < 0) // a 在 b 之後
#define time_before(a,b) time_after(b,a) // a 在 b 之前
#define time_after_eq(a,b) ((long)(a) - (long)(b) >= 0) // a 在 b 之後或相等
#define time_before_eq(a,b) time_after_eq(b,a) // a 在 b 之前或相等
// 64 位版本 (需配合 get_jiffies_64())
#define time_after64(a,b) ((s64)(b) - (s64)(a) < 0)
#define time_before64(a,b) time_after64(b,a)
#define time_after_eq64(a,b) ((s64)(a) - (s64)(b) >= 0)
#define time_before_eq64(a,b) time_after_eq64(b,a)
使用鐵律:所有涉及 jiffies 比較的邏輯,必須使用上述宏,禁止直接用 >/< 比較。
unsigned long timeout = jiffies + msecs_to_jiffies(5000); // 5 秒後超時
while (!condition_met) {
if (time_after(jiffies, timeout)) {
return -ETIMEDOUT;
}
cpu_relax(); // 或 schedule() 讓出 CPU
}
struct timer_list my_timer;
void my_callback(struct timer_list *t) {
// 處理邏輯
mod_timer(t, jiffies + msecs_to_jiffies(1000)); // 重新安排 1 秒後
}
timer_setup(&my_timer, my_callback, 0);
mod_timer(&my_timer, jiffies + msecs_to_jiffies(1000)); // 首次啟動
// 睡眠指定毫秒 (可被信號打斷)
msleep_interruptible(2000); // 2 秒
// 精確忙等待 (極短延遲 < 1ms)
udelay(500); // 500 微秒
ndelay(100); // 100 納秒
sysconf(_SC_CLK_TCK) 獲取用戶空間時鐘節拍 (通常 100)/proc/timer_stats (需內核配置) 可觀測定時器分布| 錯誤模式 | 後果 | 修正 |
|---|---|---|
直接比較 if (jiffies > timeout) | 回繞後邏輯永久失效 | 使用 time_after(jiffies, timeout) |
32 位系統長延遲用 jiffies 計算 | 49 天後溢出錯誤 | 用 get_jiffies_64() + time_after64 |
| 混用有符號/無符號變量存儲 | 負數轉大正數邏輯錯亂 | 統一 unsigned long / u64 |
| 在中斷上下文調用睡眠函數 | 內核崩潰 BUG: sleeping function called from invalid context | 改用 mdelay/udelay/ndelay 或 timer/workqueue |
jiffies 是內核時間的基石。掌握 類型鐵律 (unsigned long/u64)、轉換宏 (msecs_to_jiffies 等)、比較宏 (time_after 系列)、64 位擴展 (get_jiffies_64)、回繞安全邏輯 五大核心,即可在驅動開發、內核模塊、嵌入式系統中構建健壯的時間相關邏輯。記住:內核時間不倒流,但計數器會回繞;比較宏是唯一護身符。
Linux 禁止特定 IP 存取:hosts.allow / hosts.deny 與 tcpd 實戰配置
Linux VirtualBox 安裝 Windows 8.1 報錯 0x000000C4 解決:啟用 CMPXCHG16B CPU 指令支援
CentOS 5.8 手動編譯升級 Python 2.4.3 至 2.7.3 完整教學
Linux 檔案內容檢視指令大全:cat、tac、more、less、head、tail、nl、od 完整解析
Linux XFS 檔案系統線上擴容完整指南:xfs_growfs 實戰與最佳實務
Linux 序列埠 (Serial Port) 程式設計完整指南:termios 結構體配置、波特率、資料位、停止位、奇偶校驗、流控