1. 程式人生 > 其它 >第五章學習筆記

第五章學習筆記

第五章 定時器和時鐘服務

摘要:

本章討論了定時器和定時器服務;介紹了硬體定時器的原理和基於Intel x86的PC中的硬體定時器;講解了CPU操作和中斷處理;描述了Linux中與定時器相關的系統呼叫、庫函式和定時器服務命令;探討了程序間隔定時器、定時器生成的訊號,並通過示例演示了程序間隔定時器。程式設計專案的目的是要在一個多工處理系統中實現定時器、定時器中斷和間隔定時器、多工處理系統作為一個Linux程序執行,該系統是Linux程序內併發任務的一個虛擬CPU。Linux程序的實時模式間隔定時器被設計為定期生成SIGALRM訊號捕捉器作為定時器的中斷處理程式。

5.1硬體定時器

定時器是由時鐘源和可程式設計計數器組成的硬體裝置。時鐘源通常是一個晶體振盪器,會產生週期性電訊號,以精確的頻率驅動計數器

5.2個人計算機定時器

基於Intel x86額個人計算機有數個定時器(Bovet和Cesati 2005)

(1) 實時時鐘RTC (2) 可程式設計間隔定時器PIT (3) 多核CPU中的本地定時器 (4) 高解析度定時器

5.3CPU操作

每個CPU都有一個程式計數器(PC),也稱為指令指標(IP),以及一個標誌或狀態暫存器(SR)、一個堆疊指標(SP)和幾個通用暫存器,當PC指向記憶體中要執行的下一條指令時,SR包含CPU的當前狀態,如操作模式、中斷掩碼和條件碼,SP指向當前堆疊棧頂。堆疊是CPU用於特殊操作(如push、pop呼叫和返回等)的一個記憶體區域。CPU操作可通過無限迴圈進行建模。

由於無效地址、非法指令、越權等原因,可能會出現一個錯誤狀態,稱為異常或陷阱。當CPU遇到異常時,它會根據記憶體中預先安裝的指標來執行軟體中的異常處理程式。在每條指令執行結束時,CPU會檢查掛起的中斷。中斷是I/O裝置或協處理器傳送給CPU的外部訊號,請求CPU服務。如果有掛起的中斷請求,但是CPU未處於接受中斷的狀態,即它的狀態暫存器已經遮蔽了中斷,CPU會忽略中斷請求,繼續執行下一條命令。否則,它將直接執行中斷處理。

5.4關於中斷處理

外部裝置的中斷被饋送到中斷控制器的預定義輸入行,按優先順序對中斷輸入排序,並將具有最高優先順序的中斷作為中斷請求(IRQ)路由器到CPU。對於每個中斷,可以程式設計中斷控制器以生成一個唯一編號,叫作中斷向量,標識中斷源。

5.5時鐘服務函式

在幾乎所有的作業系統中,作業系統核心都會提供與時鐘相關的各種服務。時鐘服務可通過系統呼叫、庫函式和使用者級命令呼叫。下面介紹一些Linux的基本時鐘服務函式

1、gettimeofday-settimeofday

具體操作見程式設計實踐

2、time系統呼叫

輸出應列印開始時間、結束時間以及從開始到結束的秒數

3、times系統呼叫

以時鐘計時單元報告所有時間。這可以為分析某個正在執行的程序提供資訊,包括其子程序的時間

4、time和date命令

· date:列印或設定系統日期和時間
· time:報告程序在使用者模式和系統模式下的執行時間和總時間
· hwclock:查詢並設定硬體時鐘(RTC),也可以通過BIOS來完成

5.6間隔定時器

Linux為每個程序提供了三種不同型別的間隔計時器,可用作程序計時的虛擬時鐘。間隔定時器由settimer()系統呼叫建立。getitimer()系統呼叫返回間隔定時器的狀態。
int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
有三類間隔定時器,分別是:
(1)ITIMER_REAL: 實時減少,在到期時生成一個SIGALRM(14)訊號
(2)ITIMER_VIRTUAL: 僅當程序在使用者模式下執行時減少,在到期時生成一個SIGVTALRM(26)訊號
(3)ITIMER_PROF: 當程序正在使用者模式和系統模式下執行時減少。在到期時生成一個SIGPROF(27)訊號

5.7REAL模式間隔定時器

VIRTUAL和PROF模式下的間隔計時器僅在執行程序時才有效。這類定時器的資訊可儲存在各程序的PROC結構體中
REAL模式間隔定時器各不相同、因為無論程序是否正在執行,它們都必須由定時器中斷處理程式來更新

程式設計實踐

實現gettimeofday

原始碼如下:

#include<stdio.h>
#include<stdlib.h>
#include<sys/time.h>
#include<time.h>
struct timeval t;
int main()
{
        gettimeofday(&t, NULL);
        printf("sec=%ld usec=%d\n", t.tv_sec, t.tv_usec);
        printf((char *)ctime(&t.tv_sec));
}
星光盪開宇宙