一、linux系統下包含兩個時間:系統時間(剛啟動時讀取的是rtc時間)和RTC時間。
一般情況下都會選擇芯片上最高精度的定時器作為系統時間的定時基准,
以避免在系統運行較長時間后出現大的時間偏移。特點是掉電后不保存。
所以一旦你重啟機器后,那么系統需要重新從RTC上重新獲取時間,保存到系統內核文件中。
RTC(real_time clock)驅動程序,可以在E:\linux內核\linux-2.6.0\linux-2.6.0\drivers\char\rtc.c中找到。
設備接口就是 /dev/rtc, 他負責跟rtc打交道,並讀取rtc中維護的時間.
它是一個從系統定時器中獨立出來的虛擬設備,用於設置系統時鍾,提供報警器或周期性的定時器. 那么系統時間一直運行嗎? 顯然在操作系統關閉或重啟期間,服務器宕機期間,整個服務器的時間就依賴於RTC芯片。 從這我們看出linux系統時間和RTC時間是兩套獨立的計時體系,但它們之間又是相互依存的: 1)剛安裝操作系統后,若在安裝過程不設置系統時間,那么默認的系統時間就是從服務器的RTC芯片中獲取當前的硬件時間; 2)在linux操作系統中,一旦修改系統時間后,又重啟或關閉Linux系統,則OS通常會將系統時間更新到RTC; 3)在操作系統再次啟動的時候,Linux OS則會再次從RTC中獲取當前的時間。 服務器異常下電后,待操作系統重新啟動后,發現系統時間發生了跳變? 其原因通常是:修改了操作系統時間,在服務器異常下電后,操作系統並未及時將修改后的時間更新到RTC,導致操作系統重新啟動后, 就會從RTC芯片中加載了之前“老”的時間,從而在操作系統層面體現為“時間跳變”
二、關於jiffies
一次中斷時間間隔叫一個tick,即每個觸發周期的時間叫做tick, 一秒內時鍾中斷的次數(每個時間間隔就是一次)等於Hz hz別名就是tick rate(HZ) linux系統查看hz: [root@k3master ~]# cat /boot/config-`uname -r` | grep 'CONFIG_HZ=' CONFIG_HZ=1000 1hz就是每秒1000次中斷 每次時鍾中斷處理程序即每發生一次tick都會增加jiffies該變量的值, jiffies一秒內增加的值也就是Hz(頻率),比如:linux下默認是 1000次時鍾中斷次數/秒 系統運行時間以秒為單位,換算方法等於jiffies/Hz。 jiffies是linux內核中的一個全局變量,記錄內核節拍時間的數值,內核在開機啟動的時候會讀取RTC獲取一個時間作為基准值, 這個基准時間對應一個jiffies,RTC時間,只在開機時候讀取一次,時鍾節拍的時間取決於操作系統的配置, [root@k3master ~]# cat /boot/config-`uname -r` | grep 'CONFIG_HZ=' CONFIG_HZ=1000 內核中記錄用HZ來記錄和表示,1000hz對應就是1/hz,也就是1ms。 jiffies是內核中的一個全局變量,用來記錄自系統啟動一來產生的節拍數。譬如,如果計算系統運行了多長時間,可以用 jiffies/tick rate 來計算。
三、jiffies內核源碼
E:\linux內核\linux-2.6.0\linux-2.6.0\include\linux\jiffies.h
#ifndef _LINUX_JIFFIES_H
#define _LINUX_JIFFIES_H
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/seqlock.h>
#include <asm/system.h>
#include <asm/param.h> /* for HZ */
/*
* The 64-bit value is not volatile - you MUST NOT read it
* without holding read_lock_irq(&xtime_lock).
* get_jiffies_64() will do this for you as appropriate.
*/
extern u64 jiffies_64;
extern unsigned long volatile jiffies;
#if (BITS_PER_LONG < 64)
u64 get_jiffies_64(void);
#else
static inline u64 get_jiffies_64(void)
{
return (u64)jiffies;
}
#endif
/*
* These inlines deal with timer wrapping correctly. You are
* strongly encouraged to use them
* 1. Because people otherwise forget
* 2. Because if the timer wrap changes in future you won't have to
* alter your driver code.
*
* time_after(a,b) returns true if the time a is after time b.
*
* Do this with "<0" and ">=0" to only test the sign of the result. A
* good compiler would generate better code (and a really good compiler
* wouldn't care). Gcc is currently neither.
*/
#define time_after(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)(b) - (long)(a) < 0))
#define time_before(a,b) time_after(b,a)
#define time_after_eq(a,b) \
(typecheck(unsigned long, a) && \
typecheck(unsigned long, b) && \
((long)(a) - (long)(b) >= 0))
#define time_before_eq(a,b) time_after_eq(b,a)
#endif
注意:date -s 2007-08-03 命令設置時間只會影響系統時間,不會設置RTC時間,
如果需要把當前系統時間同步設置到RTC中,需要額外調用hwclock命令。
四、我們在看看date相關源碼
E:\linux內核\linux-2.6.0\linux-2.6.0\drivers\char\rtc.c E:\linux內核\linux-2.6.0\linux-2.6.0\kernel\time.c
//開放給用戶空間的
E:\linux內核\linux-2.6.0\linux-2.6.0\arch\x86_64\kernel\time.c
1、我們在看看rtc時鍾驅動
linux-2.6.0\linux-2.6.0\drivers\char\rtc.c //的部分內容
* This driver allows use of the real time clock (built into * nearly all computers) from user space. It exports the /dev/rtc * interface supporting various ioctl() and also the * /proc/driver/rtc pseudo-file for status information. * The /dev/rtc interface will block on reads until an interrupt * has been received. If a RTC interrupt has already happened, * it will output an unsigned long and then block. The output value * contains the interrupt status in the low byte and the number of * interrupts since the last read in the remaining high bytes. The * /dev/rtc interface can also be used with the select(2) call.
2、RTC時間:
是指系統中包含的RTC芯片內部所維護的時間。RTC芯片都有電池+系統電源的雙重供電機制,
在系統正常工作時由系統供電,在系統掉電后由電池進行供電。因此系統電源掉電后RTC時間仍然能夠正常運行。
從工作原理來說,RTC實時時鍾芯片大多采用精度較高的晶體振盪器作為時鍾源,對該時鍾源脈沖進行計數。主要靠晶振來保障准確性。
每次Linux系統啟動后在啟動過程中會檢測和掛載RTC驅動,在掛載后會自動從RTC芯片中讀取時間並設置到系統時間中去。
此后如果沒有顯式的通過命令去控制RTC的讀寫操作,系統將不會再從RTC中去獲取或者同步設置時間。
hwclock 命令使用
//讀取RTC時間(cmos時間)並設置到系統時間中去,hwclock -s 讀取RTC時間(cmos時間)並設置到系統時間中去,我們看得很清楚了,時間上和我之前的系統時間不一樣了
[root@k3master ~]# hwclock -r Mon 07 Mar 2022 10:48:18 PM CST -0.598781 seconds [root@k3master ~]# hwclock -s [root@k3master ~]# date Mon Mar 7 22:48:55 CST 2022 //把當前的系統時間設置到RTC中 [root@k3master ~]# date Mon Mar 7 22:52:20 CST 2022 [root@k3master ~]# hwclock -w [root@k3master ~]# hwclock -r Mon 07 Mar 2022 10:52:45 PM CST -0.614313 seconds
//如果你想啟動時自動執行RTC時間同步到系統時間,可以把
hwclock -s加入到rc.local文件中。
3、RTC芯片舉例:
4、看一下RTC芯片工作的驅動模型
E:\linux內核\linux-2.6.0\linux-2.6.0\kernel\time.c