 linux中斷(duan)編程、中斷(duan)編程詳解(jie)
							時間:2018-07-27      來源:未知
							linux中斷(duan)編程、中斷(duan)編程詳解(jie)
							時間:2018-07-27      來源:未知 
							Linux中斷(duan)處理驅(qu)動程序(xu)編寫
中斷處(chu)(chu)理是(shi)操(cao)作(zuo)系統必須具(ju)備的上(shang)要功能之(zhi)一(yi),下(xia)面我(wo)們(men)一(yi)起來探討一(yi)下(xia)Linux中的中斷處(chu)(chu)理。
1. 什(shen)么是中斷(duan)
中(zhong)斷(duan)就是(shi)CPU正常運行(xing)期間,由于內、外(wai)部事件引起的(de)CPU暫時停止正在(zai)運行(xing)的(de)程序(xu),去執(zhi)行(xing)該(gai)內部事件或外(wai)部事件的(de)引起的(de)服務中(zhong)去,服務執(zhi)行(xing)完畢(bi)后(hou)再(zai)返回斷(duan)點處繼續執(zhi)行(xing)的(de)情形(xing)。這樣(yang)的(de)中(zhong)斷(duan)機制極大(da)的(de)提高了CPU運行(xing)效率。
1.1. 中(zhong)斷的分類:
1) 根據中(zhong)斷(duan)(duan)的(de)來(lai)源(yuan)可分(fen)為(wei)內(nei)(nei)(nei)部(bu)中(zhong)斷(duan)(duan)和(he)外部(bu)中(zhong)斷(duan)(duan),內(nei)(nei)(nei)部(bu)中(zhong)斷(duan)(duan)的(de)中(zhong)斷(duan)(duan)源(yuan)來(lai)自(zi)于(yu)CPU內(nei)(nei)(nei)部(bu)(軟件(jian)中(zhong)斷(duan)(duan)指令、溢出、除(chu)法(fa)錯誤等),例如(ru)操(cao)作(zuo)系(xi)統從用戶態切換到內(nei)(nei)(nei)核態需要借助CPU內(nei)(nei)(nei)部(bu)的(de)軟件(jian)中(zhong)斷(duan)(duan),外部(bu)中(zhong)斷(duan)(duan)的(de)中(zhong)斷(duan)(duan)源(yuan)來(lai)自(zi)于(yu)CPU外部(bu),由(you)外設觸發。
2) 根據中斷(duan)是否(fou)可(ke)(ke)(ke)以(yi)被屏(ping)蔽,中斷(duan)可(ke)(ke)(ke)分為(wei)可(ke)(ke)(ke)屏(ping)蔽中斷(duan)和不(bu)可(ke)(ke)(ke)屏(ping)蔽中斷(duan),可(ke)(ke)(ke)屏(ping)蔽中斷(duan)可(ke)(ke)(ke)以(yi)通過設(she)置中斷(duan)控(kong)制器(qi)寄存器(qi)等方法被屏(ping)蔽,屏(ping)蔽后,該中斷(duan)不(bu)再得(de)到響應(ying),而不(bu)可(ke)(ke)(ke)屏(ping)蔽中斷(duan)不(bu)能(neng)被屏(ping)蔽。
3) 根據(ju)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)入(ru)(ru)(ru)(ru)(ru)口(kou)跳(tiao)(tiao)轉方(fang)式的(de)(de)不(bu)同,中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)可(ke)分(fen)為(wei)向(xiang)量(liang)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)和非向(xiang)量(liang)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)。采用向(xiang)量(liang)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)的(de)(de)CPU通常為(wei)不(bu)同的(de)(de)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)分(fen)配不(bu)同的(de)(de)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)號(hao),當檢(jian)測到中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)的(de)(de)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)號(hao)到來(lai)時,就自動跳(tiao)(tiao)轉到該中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)對應的(de)(de)地址(zhi)處(chu)去(qu)執(zhi)行(xing)程(cheng)(cheng)序(xu)。不(bu)同的(de)(de)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)號(hao)對應不(bu)同的(de)(de)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)入(ru)(ru)(ru)(ru)(ru)口(kou)地址(zhi)。非向(xiang)量(liang)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)的(de)(de)多個(ge)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)共(gong)享一個(ge)入(ru)(ru)(ru)(ru)(ru)口(kou)程(cheng)(cheng)序(xu)處(chu)理(li)入(ru)(ru)(ru)(ru)(ru)口(kou)地址(zhi),中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)程(cheng)(cheng)序(xu)跳(tiao)(tiao)轉到該入(ru)(ru)(ru)(ru)(ru)口(kou)地址(zhi)執(zhi)行(xing)時,再通過中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)程(cheng)(cheng)序(xu)來(lai)判斷(duan)(duan)(duan)(duan)(duan)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)標志來(lai)識別具體是哪一個(ge)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan),也(ye)就是說向(xiang)量(liang)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)由硬件提(ti)供(gong)(gong)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)服務(wu)程(cheng)(cheng)序(xu)入(ru)(ru)(ru)(ru)(ru)口(kou)地址(zhi),非向(xiang)量(liang)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)由軟(ruan)件提(ti)供(gong)(gong)中(zhong)(zhong)(zhong)(zhong)(zhong)斷(duan)(duan)(duan)(duan)(duan)服務(wu)程(cheng)(cheng)序(xu)入(ru)(ru)(ru)(ru)(ru)口(kou)地址(zhi)。
4) 非向量中斷(duan)處理流程:
/*典型(xing)的(de)(de)非向量中(zhong)斷(duan)(duan)(duan)首先會判(pan)斷(duan)(duan)(duan)中(zhong)斷(duan)(duan)(duan)源,然后調用不(bu)同中(zhong)斷(duan)(duan)(duan)源的(de)(de)中(zhong)斷(duan)(duan)(duan)處(chu)理程序*/
irq_handler()
{
...
int int_src = read_int_status();/*讀硬件的(de)中斷相關(guan)寄存器*/
switch(int_src)
{
//判斷中斷標志
case DEV_A:
dev_a_handler();
break;
case DEV_B:
dev_b_handler();
break;
...
default:
break;
}
...
}
2. linux中斷頂部、底部概念
為保證系(xi)(xi)統(tong)實時性,中斷服務(wu)(wu)(wu)程(cheng)(cheng)序(xu)必須(xu)(xu)足(zu)夠簡短,但實際應(ying)用中某(mou)些時候發生中斷時必須(xu)(xu)處理大量的工作,這(zhe)時候如果都在中斷服務(wu)(wu)(wu)程(cheng)(cheng)序(xu)中完成,則會嚴(yan)重(zhong)降(jiang)低中斷的實時性,基(ji)于這(zhe)個原因,linux系(xi)(xi)統(tong)提出了一個概(gai)念:把(ba)中斷服務(wu)(wu)(wu)程(cheng)(cheng)序(xu)分為兩部(bu)分:頂半部(bu)、底半部(bu)。
2.1. 頂(ding)半部(bu)
完成盡(jin)可(ke)能少(shao)的(de)(de)比較急的(de)(de)功能,它往往只是(shi)(shi)簡單的(de)(de)讀(du)取寄存器的(de)(de)中斷(duan)狀(zhuang)態,并(bing)清除中斷(duan)標(biao)志后就(jiu)進(jin)行(xing)“中斷(duan)標(biao)記”(也(ye)就(jiu)是(shi)(shi)把底半部(bu)處理程序掛到(dao)設(she)備的(de)(de)底半部(bu)執行(xing)隊列中)的(de)(de)工作。特點(dian)是(shi)(shi)響應速度快。
2.2. 底半部
中(zhong)斷(duan)(duan)處理的大部(bu)(bu)分工(gong)作(zuo)都在底半部(bu)(bu),它幾乎做了(le)中(zhong)斷(duan)(duan)處理程序的所有事(shi)(shi)情。 特點:處理相對(dui)來說不(bu)是非常(chang)緊急的事(shi)(shi)件 ,底半部(bu)(bu)機制主要有:tasklet、工(gong)作(zuo)隊列和軟(ruan)中(zhong)斷(duan)(duan)。
Linux中(zhong)查看/proc/interrupts文件可以獲(huo)得系統(tong)中(zhong)斷(duan)的(de)統(tong)計信息(xi):
 
3. Linux中斷編程
3.1. 申請(qing)和釋(shi)放中斷
3.1.1. 申請(qing)中斷:
int request_irq(unsigned int irq,irq_handler_t handler,unsigned long irqflags,const char *devname,void *dev_id);
參數介紹:irq是要申(shen)請的硬件中斷號(hao)。
Handler:是(shi)向(xiang)系(xi)統(tong)登記的中(zhong)斷(duan)處理(li)程(cheng)序(xu)(頂半部),是(shi)一個回(hui)調(diao)函數,中(zhong)斷(duan)發生(sheng)時,系(xi)統(tong)調(diao)用(yong)它,將(jiang)dev_id參(can)數傳遞給它。
irqflags:是中(zhong)斷(duan)處(chu)理的屬(shu)性(xing),可以指定中(zhong)斷(duan)的觸發方式(shi)和處(chu)理方式(shi):
觸(chu)發(fa)方(fang)式:IRQF_TRIGGER_RISING、IRQF_TRIGGER_FALLING、IRQF_TRIGGER_HIGH、IRQF_TRIGGER_LOW,處(chu)(chu)理(li)(li)方(fang)式:IRQF_DISABLE表(biao)明中(zhong)(zhong)斷(duan)(duan)處(chu)(chu)理(li)(li)程序是快速處(chu)(chu)理(li)(li)程序,快速處(chu)(chu)理(li)(li)程序被調用時屏蔽所有中(zhong)(zhong)斷(duan)(duan),IRQF_SHARED表(biao)示多個設備(bei)共(gong)享中(zhong)(zhong)斷(duan)(duan),dev_id在(zai)中(zhong)(zhong)斷(duan)(duan)共(gong)享時會用到,一般設置為NULL。
返回值:為0表示成功(gong),返回-EINVAL表示中斷(duan)號無效,返回-EBUSY表示中斷(duan)已經被占用(yong),且(qie)不(bu)能共享。
頂半部(bu)的handler的類型irq_handler_t定義(yi)為:
typedef irqreturn_t (*irq_handler_t)(int,void*);
typedef int irqreturn_t;
3.1.2. 釋放IRQ
有請(qing)求當然(ran)就有釋放(fang)。中斷(duan)的釋放(fang)函數為:
void free_irq(unsigned int irq,void *dev_id);
參(can)數定義(yi)與request_irq類(lei)似。
3.1.3. 中斷的使能和屏蔽
void disable_irq(int irq);//等待目(mu)前中斷處理完成(最好別在頂板部(bu)使(shi)用,你(ni)懂得)
void disable_irq_nosync(int irq);//立即返回
void enable_irq(int irq);//
3.1.4. 屏蔽(bi)本CPU內所有中斷:
#define local_irq_save(flags)...//禁止中斷并(bing)保存(cun)狀態。
void local_irq_disable(void); //禁止中斷,不保(bao)存(cun)狀態。
下(xia)(xia)面(mian)來分(fen)別(bie)介紹一下(xia)(xia)頂(ding)半(ban)部(bu)和底半(ban)部(bu)的實現機制(zhi)
3.1.5. 底半(ban)部機(ji)制(zhi):
簡介:底半部機制(zhi)主(zhu)要(yao)有tasklet、工作隊列和(he)軟(ruan)中(zhong)斷(duan)
3.1.5.1. 底半部(bu)實現方法之(zhi)一(yi)tasklet
(1) 我們需(xu)要定(ding)義tasklet機(ji)器處理器并將兩者關(guan)聯,例如:
void my_tasklet_func(unsigned long);/*定義一個處理函數*/
DECLARE_TASKLET(my_tasklet,my_tasklet_func,data);
/*上述代(dai)碼(ma)定義了名為my_tasklet的tasklet并(bing)將(jiang)其與(yu)my_tasklet_func()函數綁定,傳入(ru)的參(can)數為data*/
(2)調度
tasklet_schedule(&my_tasklet);
//使用此(ci)函數就能(neng)在(zai)是(shi)當的時候(hou)進行調度(du)運行
(3)tasklet使用模板:
/*定義(yi)tasklet和底半部函數并關聯*/
void xxx_do_tasklet(unsigned long);
DECLARE_TASKLET(xxx_tasklet, xxx_do_tasklet,0);
/*中斷處理底半部*/
void xxx_do_tasklet(unsigned long)
{
...
}
/*中斷處(chu)理頂(ding)半部*/
irqreturn_t xxx_interrupt(int irq,void *dev_id)
{
...
tasklet_schedule(&xxx_tasklet);//調(diao)度(du)地半部
...
}
/*設(she)備驅動模塊加載(zai)函數*/
int __init xxx_init(void)
{
...
/*申請中斷*/
result = request_irq(xxx_irq,xxx_interrupt, IRQF_DISABLED,"xxx",NULL);
...
return IRQ_HANDLED;
}
/*設(she)備驅動模塊(kuai)卸(xie)載(zai)函(han)數(shu)*/
void __exit xxx_exit(void)
{
...
/*釋(shi)放中(zhong)斷*/
free_irq(xxx_irq,xxx_interrupt);
...
}
3.1.5.2. 底半部(bu)實現(xian)方(fang)法(fa)之(zhi)二---工(gong)作隊列
使用方(fang)法和(he)tasklet類似,相關操作(zuo):
struct work_struct my_wq;/*定義一個工作隊列*/
void my_wq_func(unsigned long);/*定義一個處理函(han)數*/
通過INIT_WORK()可以(yi)初(chu)始化這個(ge)工(gong)作隊(dui)列(lie)(lie)并(bing)將(jiang)工(gong)作隊(dui)列(lie)(lie)與處理函(han)數綁定(ding)INIT_WORK(&my_wq,(void (*)(void *))my_wq_func,NULL);/*初(chu)始化工(gong)作隊(dui)列(lie)(lie)并(bing)將(jiang)其與處理函(han)數綁定(ding)*/
schedule_work(&my_wq);/*調度工作隊(dui)列執(zhi)行*/
/*工作隊列(lie)使用模板(ban)*/
/*定義工作隊列和關聯函數*/
struct work_struct(unsigned long);
void xxx_do_work(unsigned long);
/*中斷處(chu)理底半部*/
void xxx_do_work(unsigned long)
{
...
}
/*中斷處理頂(ding)半(ban)部(bu)*/
irqreturn_t xxx_interrupt(int irq,void *dev_id)
{
...
schedule_work(&my_wq);//調度底半部
...
return IRQ_HANDLED;
}
/*設備驅動模塊(kuai)加載函數*/
int xxx_init(void)
{
...
/*申請中斷*/
result = request_irq(xxx_irq,xxx_interrupt,IRQF_DISABLED,"xxx",NULL);
...
/*初始化工作(zuo)隊(dui)列*/
INIT_WORK(&my_wq,(void (*)(void *))xxx_do_work,NULL);
}
/*設(she)備(bei)驅(qu)動模塊卸載函(han)數*/
void xxx_exit(void)
{
...
/*釋放中(zhong)斷(duan)*/
free_irq(xxx_irq,xxx_interrupt);
...
}
4. 中斷共享(xiang)
中(zhong)(zhong)斷(duan)共享是(shi)指(zhi)多個設(she)備共享一根(gen)中(zhong)(zhong)斷(duan)線的情況,中(zhong)(zhong)斷(duan)共享的使用方法:
(1).在申請中斷時,使(shi)用(yong)IRQF_SHARED標識;
(2).在中(zhong)(zhong)斷到(dao)來時,會(hui)遍歷(li)共享此中(zhong)(zhong)斷的(de)所(suo)有中(zhong)(zhong)斷處理程序(xu),直到(dao)某一(yi)個函(han)數返(fan)回(hui)IRQ_HANDLED,在中(zhong)(zhong)斷處理程序(xu)頂半部中(zhong)(zhong),應迅速根據硬(ying)件寄存器中(zhong)(zhong)的(de)信息參照(zhao)dev_id參數判斷是否為本設備的(de)中(zhong)(zhong)斷,若不是立即返(fan)回(hui)IR1_NONE
/*共享中斷編程模(mo)板*/
irqreturn_t xxx_interrupt(int irq,void *dev_id,struct pt_regs *regs)
{
...
int status = read_int_status();/*獲知(zhi)中斷源*/
if(!is_myint(dev_id,status))/*判斷是否為本設備(bei)中斷*/
return IRQ_NONE;/*不是(shi)本設備中斷,立(li)即返回*/
/*是本(ben)設備中斷,進行(xing)處理*/
...
return IRQ_HANDLED;/*返(fan)回IRQ_HANDLER表(biao)明中斷已經(jing)被(bei)處理*/
}
/*設備模塊加載函數*/
int xxx_init(void)
{
...
/*申請共享(xiang)中斷*/
result = request_irq(sh_irq,xxx_interrupt,IRQF_SHARE,"xxx",xxx_dev);
...
}
/*設備(bei)驅(qu)動(dong)模塊卸載函數*/
void xxx_exit()
{
...
/*釋放(fang)中斷*/
free_irq(xxx_irq,xxx_interrupt);
...
}
5. 內核定時(shi)器
內(nei)核定時器(qi)編程:
簡介:軟件(jian)(jian)意義(yi)上(shang)的定(ding)時(shi)器(qi)最終(zhong)是(shi)依賴于硬件(jian)(jian)定(ding)時(shi)器(qi)實現的,內核在時(shi)鐘中斷(duan)發生后(hou)檢測(ce)各(ge)定(ding)時(shi)器(qi)是(shi)否到(dao)期,到(dao)期后(hou)定(ding)時(shi)器(qi)處(chu)理函數作為軟中斷(duan)在底半部執行。
Linux內(nei)核定時(shi)器操(cao)作:
5.1. timer_list結構體
每一(yi)個timer_list對應一(yi)個定時(shi)器
struct timer_list{
struct list_head entry;/*定時器列表*/
unsigned long expires;/*定(ding)時器到(dao)期時間(jian)*/
void (*function)(unsigned long);/*定(ding)時器(qi)處理函(han)數(shu)*/
unsigned long data;/*作為參數被(bei)傳遞給(gei)定時(shi)器(qi)處(chu)理函(han)數*/
struct timer_base_s *base;
...
};
當定(ding)時器滿的時候,定(ding)時器處(chu)理函數將被執行
5.2. 初(chu)始化定(ding)時器
void init_timer(struct timer_list * timer);
//初始化timer_list的(de)entry的(de)next為NULL,并(bing)給base指針賦值。
TIMER_INITIALIZER(_function,_expires,_data);//此宏(hong)用來
//賦值定時器(qi)結構(gou)體的function、expires、data和base成員
#define TIMER_INITIALIZER(function,_expires,_data)
{
.entry = {.prev = TIMER_ENTRY_STATIC},\
.function= (_function), \
.expires = (_expire), \
.data = (_data), \
.base = &boot_tvec_bases,\
}
DEFINE_TIMER(_name,_function,_expires,_data)//定義一個定時(shi)器結(jie)構(gou)體變量//并為此變量取名(ming)_name
//還有一(yi)個setup_timer()函數也可以用(yong)于定時器結構體的初始化。
5.3. 增加定時器
void add_timer(struct timer_list * timer);//注冊內核(he)(he)定時(shi)器(qi),也就是將定時(shi)器(qi)加入到內核(he)(he)動態定時(shi)器(qi)鏈表當(dang)中(zhong)。
5.4. 刪除定時器(qi)
del_timer(struct timer_list *timer);
del_timer_sync()//在刪除(chu)一個定(ding)時器時等待刪除(chu)操作(zuo)被處理完(不能(neng)用于中斷上下文中)
5.5. 修改定(ding)時器expires
int mod_timer(struct timer_list * timer,unsigned long expires);//修改定時器的到期時間
/*內(nei)核定(ding)時器使(shi)用模板*/
/*xxx設備結(jie)構體*/
struct xxx_dev
{
struct cdev cdev;
...
timer_list xxx_timer;/*設備要使用的定時器*/
};
/*xxx驅動中的某函(han)數*/
xxx_funcl(...)
{
struct xxx_dev *dev = filp->private_data;
...
/*初始化(hua)定時器*/
init_timer(&dev->xxx_timer);
dev->xxx_timer.function = &xxx_do_timer;
dev->xxx_timer.data = (unsigned long)dev;
/*設備結構體(ti)指針作為定時器處理函數參(can)數*/
dev->xxx_timer.expires = jiffes + delays;
/*添加(注冊)定時器*/
add_timer(&dev->xxx_timer);
...
}
/*xxx驅(qu)動中的某函數*/
xxx_func2(...)
{
...
/*刪除定(ding)時器*/
del_timer(&dev->xxx_timer);
...
}
/*定(ding)時器處理函數*/
static void xxx_do_timer(unsigned long arg)
{
struct xxx_device *dev = (struct xxx_device *)(arg);
...
/*調度定時器再執行(xing)*/
dev->xxx_timer.expires = jiffes + delay;
add_timer(&dev -> xxx_timer);
...
}
//定時(shi)器到期時(shi)間(jian)往往是在jiffies的基礎上添加一個(ge)時(shi)延(yan),若(ruo)為(wei)HZ則表示(shi)延(yan)遲(chi)一秒
5.6. 內(nei)核(he)中(zhong)的(de)延遲(chi)工(gong)作:
簡介:對(dui)于這(zhe)種周期性的(de)工作(zuo),Linux提供了一套(tao)封裝好的(de)快捷機制,本質上(shang)利用工作(zuo)隊列和定(ding)時(shi)器實現(xian),這(zhe)其(qi)中用到兩個(ge)結構(gou)體:
(1)struct delayed_work
{
struct work_struct work;
struct timer_list timer;
};
(2) struct work_struct
{
atomic_long_t data;
...
}
相關操作:
int schedule_delay_work(struct delayed_work *work,unsigned long delay);//當指定(ding)的delay到來時delay_work中的work成員的work_func_t類(lei)(lei)型成員func()會被執行work_func_t類(lei)(lei)型定(ding)義如下(xia):
typedef void (*work_func_t)(struct work_struct *work);//delay參數(shu)的單位是jiffes
mescs_to_jiffies(unsigned long mesc);//將毫秒轉化成jiffes單位
int cancel_delayed_work(struct delayed_work *work);
int cancel_delayed_work_sync(struct delayed_work *work);//等待直到刪(shan)除(不(bu)能用于(yu)中(zhong)斷上下文(wen))
內核(he)延遲的相關函數:
短延遲:
Linux內(nei)核提供(gong)了如下(xia)三個函數分別進行納秒、微妙和毫(hao)秒延遲:
void ndelay(unsigned long nsecs);
void udelay(unsigned long usecs);
void mdelay(unsigned long msecs);
機制(zhi):根據CPU頻率進行一(yi)定(ding)次數的循環(huan)(忙等(deng)待)
注意:在Linux內核中(zhong)最好不要使用毫(hao)秒(miao)級的延時,因為這樣會(hui)無謂消耗CPU的資源。
對于毫秒以上(shang)的延時,Linux提供如下函數:
void msleep(unsigned int millisecs);
unsigned long msleep_interruptible(unsigned int millisecs);//可(ke)以被(bei)打斷(duan)
void ssleep(unsigned int seconds);
//上述函數使得調(diao)用它的進程睡眠(mian)指定的時間(jian)
長延遲:
機制:設置(zhi)當(dang)前(qian)jiffies加上時間間隔的jiffies,直到未(wei)來的jiffies達到目標(biao)jiffires
/*實例:先延(yan)(yan)遲100個jiffies再延(yan)(yan)遲2s*/
unsigned long delay = jiffies + 100;
while(time_before(jiffies,delay));
/*再延遲(chi)2s*/
unsigned long delay = jiffies + 2*Hz;
while(time_before(jiffies,delay));//循環直到(dao)到(dao)達(da)指定的時間與timer_before()相(xiang)對應的還有一個time_after
睡著延遲:
睡著(zhu)延遲是比忙等(deng)待更(geng)好的一種(zhong)方法
機制:在等(deng)待的時間到來之(zhi)前(qian)進程處于睡眠狀態,CPU資(zi)源被(bei)其他進程使用(yong),實現函數有:
schedule_timeout()
schedule_timeout_uninterruptible()
其(qi)實(shi)在短延(yan)遲中(zhong)的msleep() msleep_interruptible()
本質上(shang)都是(shi)依(yi)賴于此函(han)(han)數(shu)實現(xian)的,下(xia)面兩個函(han)(han)數(shu)可以讓當(dang)前(qian)進程(cheng)(cheng)加入到(dao)等(deng)待隊列(lie)中,從而在(zai)等(deng)待隊列(lie)上(shang)睡眠,當(dang)超時發生時,進程(cheng)(cheng)被喚醒
sleep_on_timeout(wait_queue_head_t *q,unsigned long timeout);
interruptible_sleep_on_timeout(wait_queue_head_t *q,unsigned long timeout);