c#获取当前时间 毫秒_《Linux设备驱动程序》(十二)——时间操作(一)
之前我們學會了如何編寫一個字符設備,并對其中的一些重要操作進行了說明。對于一個完整的設備而已,可能還有許多工作要做。
本節我們將要說一下內核中是如何對時間問題進行操作的。
本節主要涉及到以下內容:
- 內核中的時間描述;
- 如何獲取當前時間;
- 如何進行延時操作;
內核中的時間描述
在內核中,系統定時硬件以周期性的間隔產生中斷,內核通過這個中斷來跟蹤時間流。
在內核中,上面的中斷間隔是由HZ常數來決定的,該常數是與體系結構相關的,定義在中(或者在其中的某個子文件中)。HZ的含義是一秒內產生的中斷數。如果需要,用戶可以修改這個變量,修改完后需要重新編譯整個內核以及模塊,不過,不建議用戶對該常數進行修改。
內核中使用一個變量來作為中斷計數器,系統啟動時,該計數器清零;上面的中斷發生時,計數器的值加1,因此這個計數器記錄了系統啟動以來的中斷數(也稱為時鐘滴答數)。這個變量稱為jiffies_64,是一個64位的變量(即使在32位系統中也是64位的),而我們在編寫驅動過程中,常用的變量名稱為jiffies,該變量是一個unsigned long型變量,其值要么就是jiffies_64,要么就是jiffies_64的低32位。以上計數器變量及其相關操作定義在文件中。
通過以上jiffies變量和HZ常數,就可以知道或定義一些時間:
#include unsigned long j = jiffies;unsigned long stamp_1 = j + HZ; /* 未來1秒 */unsigned long stamp_half = j + HZ / 2; /* 未來半秒 */unsigned long stamp_n = j + n * HZ / 1000; /* 未來n毫秒 */上面對于jiffies可以直接讀取,但對于jiffies_64變量讀取是非原子的,是不可靠的,如果需要使用jiffies_64變量,我們可以使用以下輔助函數:
#include u64 get_jiffies_64(void);如果兩個unsigned long變量表示獲取到的jiffies時間,則我們可以通過比較其大小來判斷時間先后(較大時間靠后),但我們還需要考慮時間過長而溢出問題(概率很低),因此,我們最好使用內核提供的宏來進行比較:
#include int time_after(unsigned long a, unsigned log b); /* 判斷a時間是否比b時間靠后 */int time_before(unsigned long a, unsigned log b); /* 判斷a時間是否比b時間靠前 */int time_after_eq(unsigned long a, unsigned log b); /* 判斷a時間是否比b時間靠后或相等 */int time_before_eq(unsigned long a, unsigned log b); /* 判斷a時間是否比b時間靠前或相等 */上面說了內核空間的時間描述。
在用戶空間中,用于描述時間的變量是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(unsgined long jiffies, struct timeval *value);上面的函數看名字和變量就知道其含義和使用方法,這里就不再描述了。
獲取當前時間
通過讀取jiffies變量,我們就可以獲取當前時間(系統啟動后經歷的時間)。
但有時候我們也需要處理絕對時間戳,因此,內核中導出了以下兩個函數來獲取絕對時間:
#include void do_gettimeofday(struct timeval *tv);struct timespec current_kernel_time(void);延遲執行
設備驅動程序中經常在執行某個操作后需要等待一段時間,讓硬件做后某些任務后再繼續執行。
對于時間較長的延時(大于一個滴答時鐘),可以使用等待隊列的方式實現,等待隊列的使用可以查看《Linux設備驅動程序》(九)——休眠與喚醒 :
wait_queue_head_t wait;init_waitqueue_head(&wait);wait_event_interrupt_timeout(wait, 0, delay);上面的condition設為0,因為我們并不是在等待某個特定的事件;delay是超時的時間(為jiffies數量,而不是絕對時間)。因此,上面的代碼會進入休眠,等待指定的jiffies數量后繼續執行。
為了使用超時功能而定義了等待隊里頭,這是多余的,因為我們并不需要他。為了避免定義多余的變量,內核提供了以下方法實現延時:
#include set_current_state(TASK_INTERRUPTIBLE);schedule_timeout(delay);通過set_current_state來設置當前進程的狀態(如果是不可中斷的設置為TASK_UNINTERRUPTIBLE),這樣調度器超時后將其設置為TASK_RUNNING,該進程才會繼續執行;如果沒有設置進程狀態,則進程狀態一直都是TASK_RUNNING,此時后面執行schedule_timeout時,其效果等效于schedule,延時不會起作用。
對于短延遲,內核提供了以下幾個函數來完成:
#include void ndelay(unsigned long nscs); /* 延遲指定的納秒 */void udelay(unsigned long usecs); /* 延遲指定的微秒 */void mdelay(unsigned long msecs); /* 延遲指定的毫秒 */這些函數的實現是與具體架構相關的,所有的架構都實現了udelay,其他函數可能沒有定義,會在udelay的基礎上提供默認的未定義的其他函數。
需要知道的是,以上延遲并不是說精確延時指定的時間,而是至少延遲指定的時間,可能會更長。
雖然輸入的參數均為unsigned long類型的,但一般性的規則是只用在其指定的量級上,即上千納秒應該使用udelay,而上千微秒則應使用mdelay,而不是輸入一個很大的值。
以上的延遲都是忙等待函數,因此在延遲期間不能執行其他任務。
對于毫秒級以上的延遲,內核還提供了一種非忙等待的實現:
#include void msleep(unsigned int millisecs); /* 延時等地指定毫秒 */unsigned long msleep_interruptible(unsgined int millisecs); /* 返回剩余毫秒數,一般為0 */void ssleep(unsgined int seconds); /* 延時等待指定秒 */以上介紹了內核時間的概念、如何獲取內核時間以及在當前線程中的延時操作。下一節繼續說如何進行異步延時操作。
總結
以上是生活随笔為你收集整理的c#获取当前时间 毫秒_《Linux设备驱动程序》(十二)——时间操作(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2万也买?库克称苹果或将继续上调iPho
- 下一篇: 快手账号冻结在哪里看