中斷#
中斷分 向量中斷 和 非向量中斷##
- 向量中斷由硬件提供中斷服務(wù)程序入口地址
- 非向量中斷由軟件提供中斷服務(wù)程序入口地址
程序架構(gòu)##
- top half: 緊急的硬件操作(調(diào)度 bottom half),不可中斷
- bottom half: 延緩的耗時操作囤攀,可響應(yīng)新的中斷
request & free##
flags若設(shè)置 IRQF_SHARED 善镰,則表示多個設(shè)備共享中斷
使能和屏蔽中斷##
disable_irq_nosync() 與 disable_irq() 的區(qū)別在于前者立即返回翰萨,而后者等待目前的中斷處理完成诊胞。由于 disable_irq() 會等待指定的中斷號被處理完,因此如果在n號中斷頂半部調(diào)用 disable_irq(n) 创南,會引起系統(tǒng)死鎖
底半部##
- tasklet
- 工作隊(duì)列
- 軟中斷
- 線程化irq
tasklet###
執(zhí)行上下文是軟中斷
void xxx_do_tasklet(unsigned long);
DECLEAR_TASKLET(xxx_tasklet, xxx_do_tasklet, NULL);
void xxx_do_tasklet(unsigned long)
{
...
}
irqreturn_t xxx_interrupt(int irq, void *dev_id)
{
...
tasklet_schedule(&xxx_tasklet);
...
}
int __init xxx_init(void)
{
...
result = request_irq(xxx_irq, xxx_interrupt, 0, "xxx", NULL);
...
return IRQ_HANDLED;
}
void __exit xxx_exit(void)
{
...
free_irq(xxx_irq, xxx_interrupt);
...
}
工作隊(duì)列###
執(zhí)行上下文是內(nèi)核線程浓恶,可以調(diào)度和睡眠
struct work_struct xxx_wq;
void xxx_do_work(struct work_struct *work);
void xxx_do_work(struct work_struct *work)
{
...
}
irqreturn_t irqreturn_t xxx_interrupt(int irq, void *dev_id)
{
...
schedule_work(&xxx_wq);
...
return IRQ_HANDLED;
}
int __init xxx_init(void)
{
...
result = request_irq(xxx_irq, xxx_interrupt, 0, "xxx", NULL);
INIT_WORK(&xxx_wq, xxx_do_work);
...
return IRQ_HANDLED;
}
void __exit xxx_exit(void)
{
...
free_irq(xxx_irq, xxx_interrupt);
...
}
軟中斷###
- 執(zhí)行上下文是軟中斷
- 內(nèi)核采用 softirq 的地方包括:
HI_SOFTIRQ TIMER_SOFTIRQ NET_RX_SOFTIRQ NET_TX_SOFTIRQ SCSI_SOFTIRQ TASKLET_SOFTIRQ
硬件中斷 軟中斷 信號 的區(qū)別
硬中斷是外部設(shè)備對CPU的中斷
軟中斷是中斷底半部的一種處理機(jī)制
信號是由內(nèi)核(或其他進(jìn)程)對某個進(jìn)程的中斷
中斷優(yōu)先級高于軟中斷莺债,軟中斷又高于任何一個線程紧憾。故軟中斷適度線程化到千,可以緩解高負(fù)載下系統(tǒng)的響應(yīng)。
threaded_irq###
- request_threaded_irq() 參數(shù)handler對應(yīng)的函數(shù)執(zhí)行于中斷上下文赴穗,thread_fn對應(yīng)的函數(shù)執(zhí)行于內(nèi)核線程
- 如果handler結(jié)束時憔四,返回值是 IRQ_WAKE_THREAD ,內(nèi)核會調(diào)度對應(yīng)線程執(zhí)行thread_fn
中斷共享##
- 共享中斷 IRQF_SHARED 申請成功的前提是望抽,該中斷未被申請加矛,或該中斷雖然被申請履婉,但之前也以 IRQF_SHARED 標(biāo)志申請
- request_irq() 參數(shù)dev_id以設(shè)備結(jié)構(gòu)體指針最佳
- 在中斷到來時煤篙,會遍歷執(zhí)行共享此中斷的所有中斷處理程序,直到某一個程序返回 IRQ_HANDLED 毁腿;故在中斷處理函數(shù)中辑奈,應(yīng)根據(jù)硬件寄存器的信息比對dev_id參數(shù),迅速判斷是否為本設(shè)備中斷已烤,若不是鸠窗,返回 IRQ_NONE
irqreturn_t xxx_interrupt(int irq, void *dev_id)
{
int status = read_int_status(); /* 獲知中斷源 */
if (!is_myint(dev_id, status))
return IRQ_NONE;
...
return IRQ_HANDLED;
}
int xxx_init(void)
{
result = request_irq(sh_irq, xxx_interrupt, IRQF_SHARED, "xxx", xxx_dev);
...
}
void xxx_exit(void)
{
free_irq(xxx_irq, xxx_interrupt);
...
}
內(nèi)核定時器##
- timer_list
內(nèi)核定時器
struct xxx_dev {
struct cdev cdev;
...
timer_list xxx_timer;
};
xxx_func1(...)
{
struct xxx_dev *dev = filp->private;
...
init_timer(&dev->xxx_timer);
dev->xxx_timer.function = &xxx_do_timer;
dev->xxx_timer.data = (unsigned long)dev;
dev->xxx_timer.expires = jiffies + delay;
add_timer(&dev->xxx_timer);
...
}
xxx_func2(...)
{
del_timer(&dev->xxx_timer);
...
}
static void xxx_do_timer(unsigned long arg)
{
struct xxx_device *dev = (struct xxx_device *)arg;
dev->xxx_timer.expires = jiffies + delay;
add_timer(&dev->xxx_timer);
...
}
- delayed_work
對于周期性任務(wù),除了定時器以外胯究, delayed_work 利用工作隊(duì)列和定時器實(shí)現(xiàn)
內(nèi)核延時##
短延時###
實(shí)現(xiàn)原理本質(zhì)上是忙等待
- ndelay()
- udelay()
- mdelay()
引起進(jìn)程睡眠稍计,類似函數(shù)的精度受系統(tǒng)HZ以及進(jìn)程調(diào)度的影響(實(shí)質(zhì)調(diào)用 schedule_timeout())
- msleep()
- msleep_interruptible()
- ssleep()
長延時###
time_before() & time_after() 判斷調(diào)用時的jiffies和傳入的jiffies之前或之后
防止jiffies被編譯器優(yōu)化,內(nèi)核將其定義為volatile裕循,避免讀合并
睡著延遲###
msleep() 實(shí)質(zhì)調(diào)用 schedule_out() 臣嚣,實(shí)現(xiàn)原理是向系統(tǒng)添加一個定時器净刮,在定時器處理函數(shù) process_timeout() 中喚醒與參數(shù)對應(yīng)的進(jìn)程
sleep_on_timeout() & interruptible_sleep_on_timeout() 將當(dāng)前進(jìn)程添加到等待隊(duì)列,超時發(fā)生時硅则,進(jìn)程喚醒