6.實際時間
當前實際時間(牆上時間)定義在檔案 kernel/timer.c 中:
struct timespec xtime;
timespec 資料結構定義在檔案<linux/time.h>中,形式如下:
struct timespec { time_t tv_sec; /* 秒 */ long tv_nsec; /* 納秒 */};
xtime.tv_sec 以秒為單位,存放著自 1970年7月1日(UTC)以來經過的時間。xtime.tv_nsec 記錄自上一秒開始經過的納秒數。
讀寫 xtime 變數需要使用 xtime_lock 鎖,該鎖是一個 seqlock 鎖。
7.定時器
定時器能夠使工作在指定時間點上執行。定時器由結構 time_list 表示,定義在檔案<linux/timer.h>中。
struct timer_list { struct list_head entry; /* 定時器鏈表的入口 */ unsigned long expires; /* 以 jiffies 為單位的定時值 */ spinlock_t lock; /* 保護定時器的鎖 */ void (*function)(unsigned long); /* 定時器處理函數 */ unsigned long data; /* 傳給處理函數的長整形參數 */ struct tvec_t_base_s *base; /* 定時器內部值,使用者不要使用 */};
使用定時器:
struct timer_list my_timer;init_timer( &my_timer ); /* 初始化定時器 */my_timer.expires = jiffies + delay; /* 定時器逾時時的節拍數 */my_timer.data = 0; /* 給定時器處理函數傳入 0 值 */ my_timer.function = my_function; /* 定時器逾時時調用的函數 */add_timer( &my_timer ); /* 啟用定時器 */
如果需要更改逾時時間,可以調用 mod_timer 函數:
mod_timer( &my_timer , jiffies + new_delay );
mod_timer 函數不管 my_timer 是否已被啟用,一旦從 mod_timer 返回,my_timer 都被啟用而且設定了新的定時值。如果調用時 my_timer 未被啟用,該函數返回 0,否則返回 1。
如果需要停止定時器,可以使用 del_timer 和 del_timer_sync 函數
del_timer( &my_timer );del_timer_sync( &my_timer );
被啟用或未被啟用的定時器都可以使用,如果定時器還未被啟用,該函數返回 0,否則返回 1。注意,不需要為已經逾時的定時器調用該函數,因為它們會自動被刪除。兩者區別在於 del_timer_sync 會等待其他處理器上啟動並執行定時器處理常式都退出才執行。所以 del_timer_sync 不能在中斷上下文中使用。但在安全性方面考慮,優先使用 del_timer_sync。
8.順延強制
1)忙等待
unsigned long delay = jiffies + 5 * HZ;while( time_before( jiffies, delay ) ) cond_resched();
cond_resched 函數將調度一個新程式投入運行,但它只有在設定完 need_resched 標誌後,才會生效。換句話說,該方法有效條件是系統中存在更重要的任務需要運行。注意因為該方法需要調用發送器,所以它只能在進程上下文中使用。
2)短延遲
void udelay( unsigned long usecs );void mdelay( unsigned long msecs );
前一個函數利用忙迴圈將任務延遲到指定的微秒數後運行,後者延遲指定的毫秒數。
3)schedule_timeout
該方法會讓需要順延強制的任務睡眠到指定的延遲時間耗盡後再重新運行,但不保證睡眠時間正好等於指定的延遲時間——只能盡量使睡眠時間接近指定的延遲時間。當指定的時間到期後,核心喚醒被延遲的任務並將其重新放回運行隊列。
/* 將任務設定為可中斷睡眠狀態 */set_current_state( TASK_INTERRUPTIBLE );/* 小睡一會兒,“s”秒後喚醒 */schedule_timeout( s * HZ);
唯一的參數是延遲的相對時間,單位為 jiffies,注意在調用 schedule_timeout 函數前必須首先將任務設定為 TASK_INTERRUPTIBLE 或 TASK_UNINTERRUPTIBLE 兩種狀態之一,否則任務不會睡眠。
4)設定逾時時間,在等待隊列上睡眠
可以將自己放入等待隊列,然後調用發送器去執行新任務。一旦事件發生後,核心調用 wake_up 函數喚醒在睡眠隊列上的任務,使其重新投入運行。