linux驅動之時間管理

2021-07-05 02:19:51 字數 4178 閱讀 1694

系統的時鐘頻率 時鐘頻率詳解和程式設計   ,一般系統都會有個預設的時鐘頻率hz,其實就是1秒內系統時鐘發生多少次中斷。假如:系統的hz為1000,則表示1秒內系統會產生1000次時鐘中斷;

滴答數:  系統核心會有個統計時鐘中斷發生的次數的計數器,該計數器從系統啟動引導被初始化為0後,只要發生一次時鐘中斷,該計數器就自增1;所以該計數器就是表示從開機起發生多少次中斷。該計數器是個64位的變數(不管你系統或者cpu架構   是32位還是64位,該變數都是64位的),稱為 jiffies_64。但我們一般使用的就是unsigned  long  jiffies變數,在64位平台上jiffies和jiffies_64應該是相同的(不過還是以各個平台為標準);在32位的平台上jiffies 就是 jiffies_64的低32位。為什麼會有兩個滴答計數器?是因為並不是在所有平台對jiffies_64訪問都是原子的,而且我們一般用它的低32位就能達到所需要的精度了(如果執意要用jiffies_64,那麼可以用 u64 get_jiffies_64(void)來原子的獲取到jiffies_64)。

jiffies和jiffies_64都應該看成是唯讀變數,因為他們的值都是核心來修改的。下面看下使用:

#include

unsigned long j,  stamp_1s, stamp_halfs,  stamp_nn;

j = jiffies; //當前值

stamp_1s = jiffies + hz; //1秒後

stamp_halfs = jiffies + hz / 2; //版秒後

stamp_nn  = jiffies + n * hz / 1000;  // n公釐後

再說個溢位問題,假設hz值為1000,則1秒jiffies就要增加1000,  而jiffies是unsigned long型別;那麼, sizeof(unsigned long)  /  (24 * 60 * 60 * 100)  大概就是50天左右。

jiffies操作函式:

#include

int time_after(unsigned long a,  unsigned long b);  // a > b ? 1:0

int time_before(unsigned long a,  unsigned long b); // a < b ? 1:0

int time_after_eq(unsigned long a,  unsigned long b);   // a >= b ? 1:0

int time_before_eq(unsigned long a,  unsigned long b); // a =< b ? 1:0

其實上面的函式基本是通過: diff = (long)a  - (long)b;

jiffies和使用者空間的時間轉換

struct    timeval ;

struct   timespec;

#include

unsigned long timespec_to_jiffies(struct timespec  *value);

void  jiffies_to_timespec(unsigned long jiffies,  struct timespec  *value);

unsigned  long  timeval_to_jiffies(struct  timeval *value);

void  jiffies_to_timeval(unsigned  long jiffies,  struct timeval  *value);

還有個轉換函式我們應該會經常使用到,就是將我們日常使用的牆鐘時間轉換為jiffies:

unsigned  long mktime (unsigned  int year,  unsigned int mon,  unsigned int day, unsigned int hour, unsigned min, unsinged int sec);

延時可以分為幾種:1、使用系統時鐘的延時,這種延時大於時鐘滴答;2、以時鐘滴答的延時,比如延時5個時鐘滴答;3、延時的單位比滴答數還小,一般是ns為單位活在更短,一般就用軟體方式實現忙等待就能達到效果;這裡談論後面2種延時;

最簡單的就是忙等待:while ( time_before(jiffies, j1) )nop;  忙等待到jiffies為j1;這種方法很多漏洞,比如忙等待浪費cpu資源,如果忙等待時禁止了中斷,那系統就會死掉。。。總之,這種方式在發行的軟體中是不能使用的(自己測試的可以簡單下)

while ( time_before(jiffies, ji)){

schedule();

當時間沒有到時,系統會通過schedule()函式來排程其他程序來執行,但呼叫schedule()程序會被放入到就緒佇列,只要有機會該程序就會再次被呼叫執行;所以如果系統在空閒狀態(只有乙個程序),那麼呼叫schedule()就會無效了。這裡涉及到idle狀態,該狀態下類似休眠,如果就緒佇列中沒有程序在排隊那麼就會進入idle狀態。很顯然這裡不會進入idle狀態,而是放棄cpu然後又被排程,然後放棄cpu,然後又被排程....

讓出處理器的延時還有個問題,就是不一定能按時被再次排程。因為程序的排程涉及到各種因素,比如優先順序,時間片等。其實這種方法很有可能是超時後再排程回來,那究竟超時多久就不得而知了。

更好的延時方法:

set_current_state(task_uninterruptible);

schedule_timeout(jiffies + hz);

首先是設定當前程序狀態為不可中斷,這時候系統就會把該程序放到不可中斷睡眠佇列中,所以可以解決上面提到的排程--放棄--排程--放棄的迴圈中;這裡會呼叫schedule_timeout(jiffies + hz)函式,只有到了預定的時間後才會把該程序從不可中斷的睡眠佇列中移到就緒佇列中。但是這還是沒有解決何時排程該程序的問題,當到了時間後,該程序雖然被排程到就緒佇列中,但什麼時候排程該程序去執行卻是不能由我們決定的。

上面的方法和: set_current_state(task_uninterruptible);  schedule();  並不是一樣的,這是因為schedule_timeout()函式會在時間到期時把程序從睡眠狀態排程到就緒狀態 ,而schedule()函式不負責喚醒睡眠程序;

這裡有兩個類似的函式:

#include

long wait_event_timeout(wait_queue_head_t  q,  condition,  long timeout);

long  wait_event_interruptible_timeout(wait_queue_head_t  q,  condition,  long timeout);

上面的兩個函式和schedule_timeout()類似,只是schedule_timeout()函式沒有等待條件。上面的兩個函式如果被其他事物喚醒,就是等待的條件已經滿足。那麼返回的是到預定時間為止還剩下的時間。

上面的延時方法其實還沒有解決精確度的問題,如果一定要精確的話,那麼可以試試這種方法:假設延時5s,那麼可以先用:set_current_state(task_uninterruptible),  schedule_timeout(4s);  這樣一定是4s後該程序被再次呼叫,那麼比較下jiffies,看看是否到5s了,如果還差點那麼可以用忙等待來處理。如果還有比較長時間,那麼可以再次呼叫schedule_timeout(xx),這就可以自己設定了。

短延時一般是硬體延時,數量級都是毫秒和納秒級的,所以不能用jiffies,不過核心提供了幾個函式:

#include

void  ndelay(unsigned  long  nsecs);

void  udelay(unsigned  long  usecs);

void  mdelay(unsigned  long   msecs);

這些延時都是忙等待實現的;

下面延時方法不用忙等待實現:

void  msleep(unsigned  int millisecs);

unsigned long msleep_interruptible(unsigned  int millisecs);

void  ssleep(unsigned int seconds);

前兩個函式將呼叫程序休眠以給定的millisecs,msleep的呼叫是不可中斷的。可以確定程序將至少睡眠給定的毫秒數。如果驅動程式正在某個等待佇列上等待,而又希望其他程序能夠打斷這個休眠,則可以使用 msleep_interruptible(), 該函式在程序被打斷喚醒時會返回剩餘的睡眠時間。ssleep函式是以秒計算的不可中斷休眠。

驅動學習之時間管理

通常情況下,jiffies在linux系統啟動引導階段初始化為0,當系統完成了對時鐘中斷的初始化之後,在每個時鐘中斷處理例程中,該值都會被 1,因此該值儲存了系統自最近一次啟動以來的時鐘滴答數。除了時鐘中斷程式對該值有修改的權利,其它任何模組都只有讀的權利。這裡再介紹乙個概念hz,該值在核心原始碼根...

ucos iii學習之時間管理

與時間服務相關的api總結 任務呼叫這個函式後就會被掛起直到期滿。這個函式可以有三種模式 相對延時模式,週期性延時模式,絕對定時模式。1 相對延時模式 任務每次執行時都會被延時大約2毫秒。當任務在時基中斷將要到來時被掛起,那麼實際的延時時基會少乙個時基。2 週期性延時 任務設定匹配值決定了任務被喚醒...

超越的時間管理之時間盒子

簡單地說,時間盒是我所知道的最有效的時間管理方式。即使在某種程度上你已經知道如何使用它,但通過下面的策略你肯定會做得更好!對於新手來,簡單地說,時間盒就是把時間段分配到乙個或一組任務。在特定的時間去完成任務而不是直到它已經完成了才去做它。但不要讓這個簡單的概念欺騙你 它可比你眼中的要更有用。許多人已...