當前位置:首頁 » 操作系統 » linux定時器中斷

linux定時器中斷

發布時間: 2022-10-06 17:29:58

『壹』 linux 時鍾中斷 哪個定時器

一. Linux的硬體時間
PC機中的時間有三種硬體時鍾實現,這三種都是基於晶振產生的方波信號輸入。這三種時鍾為:(1)實時時鍾RTC ( Real Time Clock) (2)可編程間隔器PIT(Programmable Interval Timer )(3)時間戳計數器TSC(Time Stamp Clock)
1. 實時時鍾 RTC
用於長時間存放系統時間的設備,即時關機後也可依靠主板CMOS電池繼續保持系統的計時,原理圖如下:

Note: Linux與RTC的關系是,當Linux啟動時從RTC讀取時間和日期的基準值,然後在Kernel運行期間便拋開RTC,以軟體的形式維護系統的時間日期,並在適當時機由Kernel將時間寫回RTC Register.
1.1 RTC Register
(1). 時鍾與日歷Register
共10個,地址:0x00-0x09,分別用於保存時間日歷的具體信息,詳情如下:
00 Current Second for RTC
01 Alarm Second
02 Current Minute
03 Alarm Minute
04 Current Hour
05 Alarm Hour
06 Current Day of Week(1=Sunday)
07 Current Date of Month
08 Current Month
09 Current Year
(2).狀態和控制Register
共四個,地址:0x0a-0x0d,控制RTC晶元的工作方式,並表示當前狀態。
l 狀態RegisterA , 0x0A 格式如下:
bit[7]——UIP標志(Update in Progress),為1表示RTC正在更新日歷寄存器組中的值,此時日歷寄存器組是不可訪問的(此時訪問它們將得到一個無意義的漸變值)。
bit[6:4]——這三位是用來定義RTC的操作頻率。各種可能的值如下:

DV2 DV1 DV0
0 0 0 4.194304 MHZ
0 0 1 1.048576 MHZ
0 1 0 32.769 KHZ
1 1 0/1 任何
PC機通常設置成「010」。
bit[3:0]——速率選擇位(Rate Selection bits),用於周期性或方波信號輸出。
RS3 RS2 RS1 RS0 周期性中斷 方波 周期性中斷 方波
0 0 0 0 None None None None
0 0 0 1 30.517μs 32.768 KHZ 3.90625ms 256 HZ
0 0 1 0 61.035μs 16.384 KHZ
0 0 1 1 122.070μs 8.192KHZ
0 1 0 0 244.141μs 4.096KHZ
0 1 0 1 488.281μs 2.048KHZ
0 1 1 0 976.562μs 1.024KHZ
0 1 1 1 1.953125ms 512HZ
1 0 0 0 3.90625ms 256HZ
1 0 0 1 7.8125ms 128HZ
1 0 1 0 15.625ms 64HZ
1 0 1 1 31.25ms 32HZ
1 1 0 0 62.5ms 16HZ
1 1 0 1 125ms 8HZ
1 1 1 0 250ms 4HZ
1 1 1 1 500ms 2HZ
PC機BIOS對其默認的設置值是「0110」
l 狀態Register B , 0x0B 格式如下:
bit[7]——SET標志。為1表示RTC的所有更新過程都將終止,用戶程序隨後馬上對日歷寄存器組中的值進行初始化設置。為0表示將允許更新過程繼續。
bit[6]——PIE標志,周期性中斷enable標志。
bit[5]——AIE標志,告警中斷enable標志。
bit[4]——UIE標志,更新結束中斷enable標志。
bit[3]——SQWE標志,方波信號enable標志。
bit[2]——DM標志,用來控制日歷寄存器組的數據模式,0=BCD,1=BINARY。BIOS總是將它設置為0。
bit[1]——24/12標志,用來控制hour寄存器,0表示12小時制,1表示24小時制。PC機BIOS總是將它設置為1。
bit[0]——DSE標志。BIOS總是將它設置為0。
l 狀態Register C,0x0C 格式如下:
bit[7]——IRQF標志,中斷請求標志,當該位為1時,說明寄存器B中斷請求 發生。
bit[6]——PF標志,周期性中斷標志,為1表示發生周期性中斷請求。
bit[5]——AF標志,告警中斷標志,為1表示發生告警中斷請求。
bit[4]——UF標志,更新結束中斷標志,為1表示發生更新結束中斷請求。
l 狀態Register D,0x0D 格式如下:
bit[7]——VRT標志(Valid RAM and Time),為1表示OK,為0表示RTC 已經掉電。
bit[6:0]——總是為0,未定義。
2.可編程間隔定時器 PIT
每個PC機中都有一個PIT,以通過IRQ0產生周期性的時鍾中斷信號,作為系統定時器 system timer。當前使用最普遍的是Intel 8254 PIT晶元,它的I/O埠地址是0x40~0x43。
Intel 8254 PIT有3個計時通道,每個通道都有其不同的用途:
(1) 通道0用來負責更新系統時鍾。每當一個時鍾滴答過去時,它就會通過IRQ0向 系統 產生一次時鍾中斷。
(2) 通道1通常用於控制DMAC對RAM的刷新。
(3) 通道2被連接到PC機的揚聲器,以產生方波信號。
每 個通道都有一個向下減小的計數器,8254 PIT的輸入時鍾信號的頻率是1.193181MHZ,也即一秒鍾輸入1193181個clock-cycle。每輸入一個clock-cycle其時間 通道的計數器就向下減1,一直減到0值。因此對於通道0而言,當他的計數器減到0時,PIT就向系統產生一次時鍾中斷,表示一個時鍾滴答已經過去了。計數 器為16bit,因此所能表示的最大值是65536,一秒內發生的滴答數是:1193181/65536=18.206482.
PIT的I/O埠:
0x40 通道0 計數器 Read/Write
0X41 通道1計數器 Read/Write
0X42 通道2計數器 Read/Write
0X43 控制字 Write Only
Note: 因PIT I/O埠是8位,而PIT相應計數器是16位,因此必須對PIT計數器進行兩次讀寫。
8254 PIT的控制寄存器(0X43)的格式如下:
bit[7:6] — 通道選擇位:00 ,通道0;01,通道1;10,通道2;11,read-back command,僅8254。
bit[5:4] – Read/Write/Latch鎖定位,00,鎖定當前計數器以便讀取計數值;01,只讀高位元組;10,只讀低位元組;11,先高後低。
bit[3:1] – 設定各通道的工作模式。
000 mode0 當通道處於count out 時產生中斷信號,可用於系統定時
001 mode1 Hardware retriggerable one-shot
010 mode2 Rate Generator。產生實時時鍾中斷,通道0通常工作在這個模式下
011 mode3 方波信號發生器
100 mode4 Software triggered strobe
101 mode5 Hardware triggered strobe
3. 時間戳計數器 TSC
從Pentium開始,所有的Intel 80x86 CPU就都包含一個64位的時間戳記數器(TSC)的寄存器。該寄存器實際上是一個不斷增加的計數器,它在CPU的每個時鍾信號到來時加1(也即每一個clock-cycle輸入CPU時,該計數器的值就加1)。
匯編指令rdtsc可以用於讀取TSC的值。利用CPU的TSC,操作系統通常可以得到更為精準的時間度量。假如clock-cycle的頻率是400MHZ,那麼TSC就將每2.5納秒增加一次。
二. Linux時鍾中斷處理程序
1. 幾個概念
(1)時鍾周期(clock cycle)的頻率:8253/8254 PIT的本質就是對由晶體振盪器產生的時鍾周期進行計數,晶體振盪器在1秒時間內產生的時鍾脈沖個數就是時鍾周期的頻率。Linux用宏 CLOCK_TICK_RATE來表示8254 PIT的輸入時鍾脈沖的頻率(在PC機中這個值通常是1193180HZ),該宏定義在include/asm-i386/timex.h頭文件中
#define CLOCK_TICK_RATE 1193180 kernel=2.4 &2.6

(2)時鍾滴答(clock tick):當PIT通道0的計數器減到0值時,它就在IRQ0上產生一次時鍾中斷,也即一次時鍾滴答。PIT通道0的計數器的初始值決定了要過多少時鍾周期才產生一次時鍾中斷,因此也就決定了一次時鍾滴答的時間間隔長度。
(3)時鍾滴答的頻率(HZ):1秒時間內PIT所產生的時鍾滴答次數。 這個值也由PIT通道0的計數器初值決定的.Linux內核用宏HZ來表示時鍾滴答的頻率,而且在不同的平台上HZ有不同的定義值。對於ALPHA和 IA62平台HZ的值是1024,對於SPARC、MIPS、ARM和i386等平台HZ的值都是100。該宏在i386平台上的定義如下 (include/asm-i386/param.h):
#define HZ 100 kernel=2.4
#define HZ CONFIG_HZ kernel=2.6

(4)宏LATCH:定義要寫到PIT通道0的計數器中的值,它表示PIT將隔多少個時鍾周期產生一次時鍾中斷。公式計算:
LATCH=(1秒之內的時鍾周期個數)÷(1秒之內的時鍾中斷次數)=(CLOCK_TICK_RATE)÷(HZ)
定義在<include/linux/timex.h>
#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ)
(5)全局變數jiffies:用於記錄系統自啟動以來產生的滴答總數。啟動時,kernel將該變數初始為0,每次時鍾中斷處理程序timer_interrupt()將該變數加1。因為一秒鍾內增加的時鍾中斷次數等於Hz,所以jiffies一秒內增加的值也是Hz。由此可得系統運行時間是jiffies/Hz 秒。
jiffies定義於<linux/jiffies.h>中:
extern unsigned long volatile jiffies;
Note:在kernel 2.4,jiffies是32位無符號數;kernel 2.6,jiffies是64位無符號數。
(6)全局變數xtime: 結構類型變數,用於表示當前時間距UNIX基準時間1970-01-01 00:00:00的相對秒數值。當系統啟動時,Kernel通過讀取RTC Register中的數據來初始化系統時間(wall_time),該時間存放在xtime中。
void __init time_init (void) {
... ...
xtime.tv_sec = get_cmos_time ();
xtime.tv_usec = 0;
... ... }
Note:實時時鍾RTC的最主要作用便是在系統啟動時用來初始化xtime變數。
2.Linux的時鍾中斷處理程序
Linux下時鍾中斷處理由time_interrupt() 函數實現,主要完成以下任務:
l 獲得xtime_lock鎖,以便對訪問的jiffies_64 (kernel2.6)和 xtime進行保護
l 需要時應答或重新設置系統時鍾。
l 周期性的使用系統時間(wall_time)更新實時時鍾RTC
l 調用體系結構無關的時鍾常式:do_timer()。
do_timer()主要完成以下任務:
l 更新jiffies;
l 更新系統時間(wall_time),該時間存放在xtime變數中
l 執行已經到期的動態定時器
l 計算平均負載值
void do_timer(unsigned long ticks)
{
jiffies_64 += ticks;
update_process_times(user_mode(regs));
update_times (ticks);
}
static inline void update_times(unsigned long ticks)
{
update_wall_time ();
calc_load (ticks);
}
time_interrupt ():

static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) {
int count;
write_lock (&xtime_lock); //獲得xtime_lock鎖

if(use_cyclone)
mark_timeoffset_cyclone();
else if (use_tsc) {
rdtscl(last_tsc_low); //讀TSC register到last_tsc_low
spin_lock (&i8253_lock); //對自旋鎖i8253_lock加鎖,對8254PIT訪問
outb_p (0x00, 0x43);

count = inb_p(0x40);
count |= inb(0x40) << 8;
if (count > LATCH) {
printk (KERN_WARNING "i8253 count too high! resetting../n");
outb_p (0x34, 0x43);
outb_p (LATCH & 0xff, 0x40);
outb(LATCH >> 8, 0x40);
count = LATCH - 1;
}
spin_unlock (&i8253_lock);

if (count = = LATCH) {
count- -;
}

count = ((LATCH-1) - count) * TICK_SIZE;
delay_at_last_interrupt = (count + LATCH/2) / LATCH;
} //end use_tsc
do_timer_interrupt (irq, NULL, regs);
write_unlock(&xtime_lock);
}//end time_interrupt

do_timer_interrupt():
static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
……
do_timer(regs);
if((time_status & STA_UNSYNC)= =0&&xtime.tv_sec> last_rtc_update + 660 && xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 && xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {
if (set_rtc_mmss(xtime.tv_sec) == 0)
last_rtc_update = xtime.tv_sec;
else
last_rtc_update = xtime.tv_sec - 600;
……
}
do_timer_interrupt()主要完成:調用do_timer()和判斷是否需要更新CMOS時鍾。更新CMOS時鍾的條件如下:三個須同時成立
1.系統全局時間狀態變數time_status中沒有設置STA_UNSYNC標志,即Linux沒有設置外部同步時鍾(如NTP)
2.自從上次CMOS時鍾更新已經過去11分鍾。全局變數last_rtc_update保存上次更新CMOS時鍾的時間.
3.由於RTC存在Update Cycle,因此應在一秒鍾間隔的中間500ms左右調用set_rtc_mmss()函數,將當前時間xtime.tv_sec寫回RTC中。
Note. Linux kernel 中定義了一個類似jiffies的變數wall_jiffies,用於記錄kernel上一次更新xtime時,jiffies的值。

Summary: Linux kernel在啟動時,通過讀取RTC里的時間日期初始化xtime,此後由kernel通過初始PIT來提供軟時鍾。
時鍾中斷處理過程可歸納為:系統時鍾system timer在IRQ0上產生中斷;kernel調用time_interrupt();time_interrupt()判斷系統是否使用TSC,若使用 則讀取TSC register;然後讀取PIT 通道0的計數值;調用do_time_interrupt(),實現系統時間更新.

『貳』 內核定時器 jiffies的時間是多少

首先,你這樣問,說明你不理解jiffies,jiffies應該說不是時間,jiffies的增加,是根據HZ的值變化而變化的。以時下linux kernel來說:1s=jiffies/HZ(即1秒=jiffies/HZ);在asm_i386中,HZ被定義為一個常,且為1000.一般在內核中定義超時是這樣用,如:xxx_timer.expires = jiffies+HZ/100;這個定義表示超時時間為10ms,如果超過個時間就處理中斷函數或者做你想做的事.當然HZ的分母你可以定為別的數。如HZ/1000等.

『叄』 Linux中斷與定時器

所謂中斷是指CPU在執行程序的過程中,出現了某些突發事件急待處理,CPU必須暫停當前程序的執行,轉去處理突發事件,處理完畢後又返回原程序被中斷的位置繼續執行。根據中斷的來源,中斷可分為內部中斷和外部中斷,內部中斷的中斷源來自CPU內部(軟體中斷指令、溢出、除法錯誤等,例如,操作系統從用戶態切換到內核態需藉助CPU內部的軟體中斷),外部中斷的中斷源來自CPU外部,由外設提出請求。根據中斷是否可以屏蔽,中斷可分為可屏蔽中斷與不可屏蔽中斷(NMI),可屏蔽中斷可以通過設置中斷控制器寄存器等方法被屏蔽,屏蔽後,該中斷不再得到響應,而不可屏蔽中斷不能被屏蔽。
根據中斷入口跳轉方法的不同,中斷可分為向量中斷和非向量中斷。採用向量中斷的CPU通常為不同的中斷分配不同的中斷號,當檢測到某中斷號的中斷到來後,就自動跳轉到與該中斷號對應的地址執行。不同中斷號的中斷有不同的入口地址。非向量中斷的多個中斷共享一個入口地址,進入該入口地址後,再通過軟體判斷中斷標志來識別具體是哪個中斷。也就是說,向量中斷由硬體提供中斷服務程序入口地址,非向量中斷由軟體提供中斷服務程序入口地址。
嵌入式系統以及x86PC中大多包含可編程中斷控制器(PIC),許多MCU內部就集成了PIC。如在80386中,PIC是兩片i8259A晶元的級聯。通過讀寫PIC的寄存器,程序員可以屏蔽/使能某中斷及獲得中斷狀態,前者一般通過中斷MASK寄存器完成,後者一般通過中斷PEND寄存器完成。定時器在硬體上也依賴中斷來實現,典型的嵌入式微處理器內可編程間隔定時器(PIT)的工作原理,它接收一個時鍾輸入,當時鍾脈沖到來時,將目前計數值增1並與預先設置的計數值(計數目標)比較,若相等,證明計數周期滿,並產生定時器中斷且復位目前計數值。

『肆』 調度演算法的linux進程調度演算法

linux內核的三種調度方法:
1. SCHED_OTHER 分時調度策略,
2. SCHED_FIFO實時調度策略,先到先服務
3. SCHED_RR實時調度策略,時間片輪轉
實時進程將得到優先調用,實時進程根據實時優先順序決定調度權值,分時進程則通過nice和counter值決
定權值,nice越小,counter越大,被調度的概率越大,也就是曾經使用了cpu最少的進程將會得到優先調
度。
SHCED_RR和SCHED_FIFO的不同:
當採用SHCED_RR策略的進程的時間片用完,系統將重新分配時間片,並置於就緒隊列尾。放在隊列
尾保證了所有具有相同優先順序的RR任務的調度公平。
SCHED_FIFO一旦佔用cpu則一直運行。一直運行直到有更高優先順序任務到達或自己放棄。
如果有相同優先順序的實時進程(根據優先順序計算的調度權值是一樣的)已經准備好,FIFO時必須等待該
進程主動放棄後才可以運行這個優先順序相同的任務。而RR可以讓每個任務都執行一段時間。
SHCED_RR和SCHED_FIFO的相同點:
SHCED_RR和SHCED_FIFO都只用於實時任務。
創建時優先順序大於0(1-99)。
按照可搶占優先順序調度演算法進行。
就緒態的實時任務立即搶占非實時任務。
所有任務都採用linux分時調度策略時。
1. 創建任務指定採用分時調度策略,並指定優先順序nice值(-20~19)。
2. 將根據每個任務的nice值確定在cpu上的執行時間(counter)。
3. 如果沒有等待資源,則將該任務加入到就緒隊列中。
4. 調度程序遍歷就緒隊列中的任務,通過對每個任務動態優先順序的計算(counter+20-nice)結果,選擇
計算結果最大的一個去運行,當這 個時間片用完後(counter減至0)或者主動放棄cpu時,該任務將被放在
就緒隊列末尾(時間片用完)或等待隊列(因等待資源而放棄cpu)中。
5. 此時調度程序重復上面計算過程,轉到第4步。
6. 當調度程序發現所有就緒任務計算所得的權值都為不大於0時,重復第2步。
所有任務都採用FIFO時:
1. 創建進程時指定採用FIFO,並設置實時優先順序rt_priority(1-99)。
2. 如果沒有等待資源,則將該任務加入到就緒隊列中。
3. 調度程序遍歷就緒隊列,根據實時優先順序計算調度權值(1000+rt_priority),選擇權值最高的任務使用
cpu,該FIFO任務將一直佔有cpu直到有優先順序更高的任務就緒(即使優先順序相同也不行)或者主動放棄(等
待資源)。
4. 調度程序發現有優先順序更高的任務到達(高優先順序任務可能被中斷或定時器任務喚醒,再或被當前運行
的任務喚醒,等等),則調度程序立即在當前任務 堆棧中保存當前cpu寄存器的所有數據,重新從高優先順序
任務的堆棧中載入寄存器數據到cpu,此時高優先順序的任務開始運行。重復第3步。
5. 如果當前任務因等待資源而主動放棄cpu使用權,則該任務將從就緒隊列中刪除,加入等待隊列,此時
重復第3步。
所有任務都採用RR調度策略時
1. 創建任務時指定調度參數為RR,並設置任務的實時優先順序和nice值(nice值將會轉換為該任務的時間片
的長度)。
2. 如果沒有等待資源,則將該任務加入到就緒隊列中。
3. 調度程序遍歷就緒隊列,根據實時優先順序計算調度權值(1000+rt_priority),選擇權值最高的任務使用
cpu。
4. 如果就緒隊列中的RR任務時間片為0,則會根據nice值設置該任務的時間片,同時將該任務放入就緒隊
列的末尾。重復步驟3。
5. 當前任務由於等待資源而主動退出cpu,則其加入等待隊列中。重復步驟3。
系統中既有分時調度,又有時間片輪轉調度和先進先出調度
1. RR調度和FIFO調度的進程屬於實時進程,以分時調度的進程是非實時進程。
2. 當實時進程准備就緒後,如果當前cpu正在運行非實時進程,則實時進程立即搶占非實時進程。
3. RR進程和FIFO進程都採用實時優先順序做為調度的權值標准,RR是FIFO的一個延伸。FIFO時,如果兩
個進程的優先順序一樣,則這兩個優先 級一樣的進程具體執行哪一個是由其在隊列中的未知決定的,這樣導
致一些不公正性(優先順序是一樣的,為什麼要讓你一直運行?),如果將兩個優先順序一樣的任務 的調度策略都
設為RR,則保證了這兩個任務可以循環執行,保證了公平。

『伍』 Linux編程itimerval計時器結構體問題

樓主的程序沒有用 signal 注冊 SIGPROC 對應函數,在 for 循環的時候可能已經發生了多次中斷和重置計時器。至於比1秒大,手冊中有解釋 Timers will never expire before the requested time, but may expire some (short) time afterward, which depends on the system timer resolution and on the system load; see time(7).


要在1秒間隔調用一個函數,需要加上 signal,比如

#include<signal.h>
#include<sys/time.h>
#include<stdio.h>
#include<time.h>

staticstructitimervala;

voidtimeover(intevent)
{
structitimervalb;
printf("timeoverat%ld ",time(NULL));
getitimer(ITIMER_PROF,&b);
printf("sec=%ld,usec=%ld ",b.it_value.tv_sec,b.it_value.tv_usec);
}

intmain()
{
signal(SIGPROF,timeover);

printf("beginat%ld ",time(NULL));

a.it_interval.tv_sec=1;
a.it_interval.tv_usec=0;
a.it_value.tv_sec=1;
a.it_value.tv_usec=0;

setitimer(ITIMER_PROF,&a,NULL);

while(1);

return0;
}

『陸』 linux中定義定時關機後不能操作嗎我按Ctrl+c就好像沒有定時效果了呢

可以操作的,不過Ctrl+C是信號中斷,跟windows上ctrl+shift換輸入法一個道理,都是一種信號,ctrl+c則是linux下的消息中斷,執行終止當前操作。

『柒』 linux網路編程,epoll_wait為什麼會被定時信號SIGALRM喚醒

這個函數被信號中斷就會返回-1的,系統調用約定就這樣,我man了一下,有這么一句:
EINTR
The
call
was
interrupted
by
a
signal
handler
before
any
of
the
requested
events
occurred
or
the
timeout
expired;
see
signal(7).
即調用被信號打斷,返回-1,errno被設置為EINTR

『捌』 Linux下的定時器,怎麼用

數為秒數,在經過指定秒數後,alarm會發出一個SIGALRM信號
singal函數用來綁定信號處理器函數,這里綁定的是timer,被綁定的函數必須固定為返回值void、參數int.
只需要alarm(時間)就設置了,可能由於getchar需要進入中斷導致信號被掛起所以沒反應,可以試試把getchar換成別的東西來延時看看。
關於更多Linux的學習,請查閱書籍《linux就該這么學》。

熱點內容
編程找點 發布:2025-05-15 20:43:10 瀏覽:586
php上傳臨時文件夾 發布:2025-05-15 20:43:00 瀏覽:656
impala資料庫 發布:2025-05-15 20:42:12 瀏覽:648
android安裝插件 發布:2025-05-15 20:41:31 瀏覽:241
神秘顧客訪問 發布:2025-05-15 20:33:39 瀏覽:298
安卓市場手機版從哪裡下載 發布:2025-05-15 20:17:28 瀏覽:815
幼兒速演算法 發布:2025-05-15 20:15:08 瀏覽:87
best把槍密碼多少 發布:2025-05-15 20:13:42 瀏覽:549
android安裝程序 發布:2025-05-15 20:13:20 瀏覽:560
c語言跳出死循環 發布:2025-05-15 20:06:04 瀏覽:825