linux 中斷處理 tasklet workqueue
linux中註冊中斷歷程用request_irq,isr原型為: irqreturn_t *(int irq, void* dev_id, struct pt_reg* regs)
為了使中斷關閉的時間儘可能的短,linux提出了中斷上半部和下半部。上半部為request_irq註冊的ISR,要求時間儘可能的短,而將盡可能的工作推遲到下半部去做。下半部由上半部排程,並在安全的時間內執行,此時中斷已經打開了。linux有兩種機制可以實現下半部:tasket和workqueue。
tasklet為軟中斷的一種。linux核心有HI_SOFTIRQ, TIMER, NET_TX, NET_RX, BLOCK, TASKLET, SCHED, HRTIMER, RCU 等軟中斷, 在系統初始化時呼叫open_softirq註冊。在isr中宣告tasklet,然後函式tasklet_schedule()呼叫raise_softirq(TASKLET_IRQ),然後系統在合適的時間排程tasklet執行。
workqueue本質為核心執行緒。
create_workqueue -> create_workqueue_thread
|| |->kthread_create(worker_thread) // worker_thread 檢查work_list,如果非空則依次執行起func
|| |->設定kthread_create_list,然後喚醒kthreadd_task(負責檢查kthread_create_list,如果非空則呼叫kernel_thread建立核心執行緒)
|| -> start_workqueue_thread
||-> wake_up_process(kthread_create返回的worker_thread) //通過設定task->state=RUNNING使得下次可以排程到。
schedule_work = queue_work(eventd_wq, work) // eventd_wq 為系統初始化時建立的workqueue。使用者可以用create_workqueue建立自己的workqueue。
tasklet中不允許休眠,而workqueue允許。tasklet呼叫時為中斷上下文,workque為程序上下文(僅有核心程式碼)。
linux 中的timer 即採用了中斷和softirq的機制實現的。在時鐘中斷例程 timer_interrupt中呼叫do_timer_interrupt,更新jiffies,檢查程序時間片,設定TIMER_SOFTIRQ並呼叫timer的軟中斷(在這裡處理與timer有關的tvec_base),最後統計資訊。