3.3.1.關於時間的概念
3.3.1.一、GMT時間
(1)GMT是格林尼治時間,也就是格林尼治地區的當地之間。
(2)GMT時間的意義?【用格林尼治的當地時間做爲全球國際時間】,用以描述全球性的事件的時間,方便你們記憶
(3)通常爲了方便,一個國家都統一使用一個當地時間。
3.3.1.二、UTC時間
(1)GMT時間是之前使用的,使用天文來測試的,近些年來愈來愈多的使用UTC原子鐘時間。
(2)關於北京時間,能夠參考:http://www.cnblogs.com/qiuyi21/archive/2008/03/04/1089456.html
3.3.1.三、計算機中與時間有關的部件
(1)點時間和段時間。段時間=點時間-點時間
(2)定時器和實時時鐘。定時器(timer)定的時間就是段時間,實時時鐘(RTC)就是和點時間有關的一個器件。
3.3.2.linux系統中的時間
3.3.2.一、jiffies的引入
(1)jiffies是linux內核中的一個全局變量,這個變量用來記錄以【內核的節拍時間】爲單位時間長度的一個數值。
(2)內核配置的時候定義了一個節拍時間,實際上linux內核的調度系統工做時就是以這個節拍時間爲時間片的。
(3)jiffies變量開機時有一個基準值,而後內核每過一個節拍時間jiffies就會加1,而後到了系統的任意一個時間咱們當前時間就被jiffies這個變量所標註。
3.3.2.二、linux系統如何記錄時間
(1)內核在開機啓動的時候會讀取RTC硬件獲取一個時間做爲初始基準時間,這個基準時間對應一個jiffies值(這個基準時間換算成jiffies值的方法是:用這個時間減去1970-01-01 00:00:00 +0000(UTC),而後把這個時間段換算成jiffies數值),這個jiffies值做爲咱們開機時的基準jiffies值存在。而後系統運行時每一個時鐘節拍的末尾都會給jiffies這個全局變量加1,所以操做系統就使用jiffies這個全局變量記錄了下來當前的時間。當咱們須要當前時間點時,就用jiffies這個時間點去計算(計算方法就是先把這個jiffies值對應的時間段算出來,而後加上1970-01-01 00:00:00 +0000(UTC)便可獲得這個時間點)
(2)其實操做系統只在開機時讀一次RTC,整個系統運行過程當中RTC是無做用的。RTC的真正做用實際上是在OS的2次開機之間進行時間的保存。
(3)理解時必定要點時間和段時間結合起來理解。jiffies這個變量記錄的實際上是段時間(其實就是當前時間和1970-01-01 00:00:00 +0000(UTC)這個時間的差值)
(4)一個時間節拍的時間取決於操做系統的配置,現代linux系統通常是10ms或者1ms。這個時間其實就是調度時間,在內核中用HZ來記錄和表示。若是HZ定義成1000難麼時鐘節拍就是1/HZ,也就是1ms。這些在學習驅動時會用到。
3.3.2.三、linux中時間相關的系統調用
(1)經常使用的時間相關的API和C庫函數有9個:time/ctime/localtime/gmtime/mktime/asctime/strftime/gettimeofday/settimeofday有9個:time/ctime/localtime/gmtime/mktime/asctime/strftime/gettimeofday/settimeofday
(2)time系統調用返回當前時間以秒爲單位的距離1970-01-01 00:00:00 +0000(UTC)過去的秒數。這個time內部就是用jiffies換算獲得的秒數。其餘函數基本都是圍繞着time來工做的。
(3)gmtime和localtime會把time獲得的秒數變成一個struct tm結構體表示的時間。區別是gmtime獲得的是國際時間,而localtime獲得的是本地(指的是你運行localtime函數的程序所在的計算機所設置的時區對應的本地時間)時間。mktime用來完成相反方向的轉換(struct tm到time_t)
(4)若是從struct tm出發想獲得字符串格式的時間,能夠用asctime或者strftime均可以。(若是從time_t出發想獲得字符串格式的時間用ctime便可)
(5)gettimeofday返回的時間是由struct timeval和struct timezone這兩個結構體來共同表示的,其中timeval表示時間,而timezone表示時區。settimeofday是用來設置當前的時間和時區的。
(6)總結:無論用哪一個系統調用,最終獲得的時間本質上都是一個時間(這個時間最終都是從kernel中記錄的jiffies中計算得來的),只不過不一樣的函數返回的時間的格式不一樣,精度不一樣。
3.3.3.時間相關API實戰1
3.3.3.一、time
(1)time能獲得一個當前時間距離標準起點時間1970-01-01 00:00:00 +0000(UTC)過去了多少秒
3.3.3.二、ctime
(1)ctime能夠從time_t出發獲得一個容易觀察的字符串格式的當前時間。
(2)ctime好處是很簡單好用,能夠直接獲得當前時間的字符串格式,直接打印來看。壞處是ctime的打印時間格式是固定的,無法按照咱們的想法去變。
(3)實驗結果能夠看出ctime函數獲得的時間是考慮了計算機中的本地時間的(計算機中的時區設置)
3.3.3.三、gmtime和localtime
(1)gmtime獲取的時間中:年份是以1970爲基準的差值,月份是0表示1月,小時數是以UTC時間的0時區爲標準的小時數(北京是東8區,所以北京時間比這個時間大8)
(2)猜想localtime和gmtime的惟一區別就是localtime以當前計算機中設置的時區爲小時的時間基準,其他同樣。實踐證實咱們的猜想是正確的。
3.3.4.時間相關API實戰2
3.3.4.一、mktime
(1)從OS中讀取時間時用不到mktime的,這個mktime是用來向操做系統設置時間時用的。
3.3.4.二、asctime
(1)asctime獲得一個固定格式的字符串格式的當前時間,效果上和ctime同樣的。區別是ctime從time_t出發,而asctime從struct tm出發。
3.3.4.三、strftime
(1)asctime和ctime獲得的時間字符串都是固定格式的,無法用戶自定義格式
(2)若是須要用戶自定義時間的格式,則須要用strftime。
3.3.4.四、gettimeofday和settimeofday
(1)前面講到的基於time函數的那個系列都是以秒爲單位來獲取時間的,沒有比秒更精確的時間。
(2)有時候咱們程序但願獲得很是精確的時間(譬如以us爲單位),這時候就只能經過gettimeofday來實現了。
3.3.5.linux中使用隨機數
3.3.5.一、隨機數和僞隨機數
(1)隨機數是隨機出現,沒有任何規律的一組數列。
(2)真正的徹底隨機的數列是不存在的,只是一種理想狀況。咱們平時要用到隨機數時通常只能經過一些算法獲得一個僞隨機數序列。
(3)咱們平時說到隨機數,基本都指的是僞隨機數。
3.3.5.二、linux中隨機數相關API
(1)連續屢次調用rand函數能夠返回一個僞隨機數序列
#include <stdlib.h>
int rand(void);
(2)srand函數用來設置rand獲取的僞隨機序列的種子
3.3.5.三、實戰演示
(1)單純使用rand重複調用n次,就會獲得一個0-RAND_MAX之間的僞隨機數,若是須要調整範圍,能夠獲得隨機數序列後再進行計算。
(2)單純使用rand來獲得僞隨機數序列有缺陷,每次執行程序獲得的僞隨機序列是同一個序列,無法獲得其餘序列
(3)緣由是由於rand內部的算法實際上是經過一個種子(seed,其實就是一個原始參數,int類型),rand內部默認是使用1做爲seed的,種子必定的算法也是必定的,那麼每次獲得的僞隨機序列確定是同一個。
(4)因此要想每次執行這個程序獲取的僞隨機序列不一樣,則每次都要給不一樣的種子。用srand函數來設置種子。
3.3.5.四、總結和說明
(1)在每次執行程序時,先用srand設置一個不一樣的種子,而後再屢次調用rand獲取一個僞隨機序列,這樣就能夠每次都獲得一個不一樣的僞隨機序列。
(2)通常常規作法是用time函數的返回值來作srand的參數。
3.3.5.五、在linux系統中獲取真正的隨機數
(1)linux系統收集系統中的一些隨機發生的事件的時間(譬若有人動鼠標,譬如觸摸屏的操做和座標等)做爲隨機種子去生成隨機數序列。
代碼示例:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
int i = 0, val = 0;
if (argc != 2)
{
printf("usage: %s num\n", argv[0]);
return -1;
}
printf("RAND_MAX = %d.\n", RAND_MAX); // 2147483647
srand(atoi(argv[1])); //經過外界傳遞初始化種子
//srand((unsigned)time(NULL)); //經過srand來給rand函數以不斷變化的種子
for (i=0; i<20 ;i++) //設定產生隨機數的個數
{
val = rand();
printf("%d ", (val % 10000)); //生成0到1000之間的隨機數
}
printf("\n");
return 0;
}
3.3.6.proc文件系統介紹
3.3.6.一、操做系統級別的調試
(1)簡單程序單步調試
(2)複雜程序printf打印信息調試
(3)框架體系日誌記錄信息調試
(4)內核調試的困境
3.3.6.二、proc虛擬文件系統的工做原理
(1)linux內核是一個很是龐大、很是複雜的一個單獨的程序,對於這樣的一個程序來講調試是很是複雜的。
(2)像kernel這樣龐大的項目,給裏面添加/更改一個功能是很是麻煩的,由於你這添加的一個功能可能會影響其餘已經有的。
(3)早期內核版本中儘管調試很麻煩,可是高手們還能夠憑藉我的超凡脫俗的能力去駕馭。可是到了2.4左右的版本的時候,這個難度已經很是大了。
(4)爲了下降內核調試和學習的難度,內核開發者們在內核中添加了一些屬性專門用於調試內核,proc文件系統就是一個嘗試。
(5)proc文件系統的思路是:在內核中構建一個虛擬文件系統/proc,內核運行時將內核中一些關鍵的數據結構以文件的方式呈如今/proc目錄中的一些特定文件中,這樣至關於將不可見的內核中的數據結構以可視化的方式呈現給內核的開發者。
(6)proc文件系統給了開發者一種調試內核的方法:咱們經過實時的觀察/proc/xxx文件,來觀看內核中特定數據結構的值。在咱們添加一個新功能的先後來對比,就能夠知道這個新功能產生的影響對仍是不對。
(7)proc目錄下的文件大小都是0,由於這些文件自己並不存在於硬盤中,他也不是一個真實文件,他只是一個接口,當咱們去讀取這個文件時,其實內核並非去硬盤上找這個文件,而是映射爲內核內部一個數據結構被讀取而且格式化成字符串返回給咱們。因此儘管咱們看到的仍是一個文件內容字符串,和普通文件同樣的;可是實際上咱們知道這個內容是實時的從內核中數據結構來的,而不是硬盤中來的。
3.3.6.三、經常使用proc中的文件介紹
(1)/proc/cmdline
(2)/proc/cpuinfo
(3)/proc/devices
(4)/proc/interrupts
3.3.7.proc文件系統的使用
3.3.7.一、cat以手工查看
3.3.7.二、程序中能夠文件IO訪問
3.3.7.三、在shell程序中用cat命令結合正則表達式來獲取並處理內核信息
3.3.7.三、擴展:sys文件系統
(1)sys文件系統本質上和proc文件系統是同樣的,都是虛擬文件系統,都在根目錄下有個目錄(一個是/proc目錄,另外一個是/sys目錄),所以都不是硬盤中的文件,【都是內核中的數據結構的可視化接口。】
(2)不一樣的是/proc中的文件只能讀,可是/sys中的文件能夠讀寫。讀/sys中的文件就是獲取內核中數據結構的值,而寫入/sys中的文件就是設置內核中的數據結構的元素的值。
(3)歷史上剛開始先有/proc文件系統,人們但願經過這種技術來調試內核。實際作出來後確實頗有用,因此不少內核開發者都去內核調價代碼向/proc目錄中寫文件,並且剛開始的時候內核管理者對proc目錄的使用也沒有什麼經驗也沒什麼統一規劃,後來的結果就是proc裏面的東西又多又雜亂。
(4)後來以爲proc中的內容太多太亂缺少統一規劃,因而乎又添加了sys目錄。sys文件系統一開始就作了很好的規劃和約定,因此後來使用sys目錄時有了規矩。
補充:
sysfs是用來向用戶空間導出內核對象的一種文件系統,經過它,用戶空間程序能夠查看、甚至修改內核數據結構。該文件系統是基於內核數據結構kobject創建起來的,同時該文件系統的目錄結構反映了相關內核數據結構的層次結構。因爲kobject是組成設備模型的基本結構,所以sysfs也包括了系統中設備的信息,它提供了系統硬件的拓撲信息。
因爲sysfs提供了訪問、修改內核數據結構的一種手段,於是內核模塊也能夠經過該文件系統向用戶空間導出接口用於訪問、修改模塊的參數。
在引入sysfs後,內核向用戶處處接口的方式有/proc文件系統,sysfs文件系統,ioctl命令。
雖然sysfs的信息來自於kobject,可是kobject和sysfs的關聯不是自動創建的,必須經過kobject_add才能把一個kobject添加到sysfs中。
因爲內核中使用kobject的主要部件是硬件相關的部分,於是sysfs包含的最主要的內容就是硬件相關的內容,包括總線、設備、驅動程序等。Sysfs掛載點爲/sys