# Interrupts and Interrupt Handlers
這個連結超讚
https://0xax.gitbooks.io/linux-insides/content/Interrupts/linux-interrupts-1.html
幾乎所有的外設跟devices都是用interrupt來跟CPU溝通的
kernel就是cpu的代理人
* hard drives
* blu-ray discs
* keyboards
* mice
* 3D processors
* wireless radios
* network devices
Hardware devices generate interrupts asynchronously(跟cpu clock比起來(software interrupt(由cpu執行指令時自己產生的interrupt)))
# interrupt Basics




# interrupt-descriptor table (IDT)
https://0xax.gitbooks.io/linux-insides/content/KernelStructures/linux-kernelstructure-1.html
# interrupt handler 可以被 priority更高的interrupt搶斷,但一般情況下ISR會執行完
https://stackoverflow.com/questions/24128926/what-happens-when-an-isr-is-running-and-another-interrupt-happens


# Interrupt Handlers
interrupt handler or interrupt service routine(ISR)
* Each device that generates interrupts has an associated interrupt handler
* The interrupt handler for a device is part of the device’s driver (driver開發者要自己maintain Interrupt CPU流程跟功能)
* **In linux,ISR是C function,但你在run ISR的時候,你跟kernel function有個重大區別,就是你會進interrupt context而不是process context,又稱為atomic context因為這裡面的code是不能被block的,不能sleep,進去就必須做完**。
* 後面會說interrupt handler又可稱為top half,硬體處理東西要花許多時間的必須被放在bottom half,ex: 網路卡
> For example, consider the interrupt handler
for a network device. On top of responding to the hardware, the interrupt handler needs to copy networking packets from the hardware into memory, process them, and push the packets down to the appropriate protocol stack or application. Obviously, this can be a lot of work, especially with today’s gigabit and 10-gigabit Ethernet cards
# Top Halves vs Bottom Halves
**Top Halves**
* run time-critical things
* acknowledging receipt of interrupt
* resetting hardware
**Bottom Halves**
* 不需要放在top halves的放這
* bottom half can runs in the future,at a more convenient time, with all interrupts enabled.
**ex: Network card**
* 當網路卡收到網路封包時,需要立即通知kernel,如果這個過程很慢就會掉封包,且為了優化network throughput and latency and avoid timeouts.,所以他會立馬發送interrupt 給kernel
* kernel需要立即把網路卡送來的data存進記憶體裡,因為buffer是ring結構的,處理不來會有覆蓋問題,這些需要立即處理的問題放在top half。bottom half下一章會討論
# Registering an Interrupt Handler
interrupt handler怎麼處理是寫driver的人的責任,管好你的hardware
跟kernel註冊irq

* 一些經典的device是hard-coded的如timer, keyboard,如果你是新增一個你自己的device可能是動態決定的
* handler指向實際的ISR
* flags:
* IRQF_DISABLED
* When set, this flag instructs the kernel to disable all interrupts when executing this interrupt handler留給需要real time的device用的,不要隨便亂用ex: NASA火箭
* IRQF_SAMPLE_RANDOM
* IRQF_TIMER
* IRQF_SHARED
* This flag specifies that the interrupt line can be shared among multiple interrupt handlers. Each handler registered on a given line must specify this
flag; otherwise, only one handler can exist per line. More information on shared
handlers is provided in a following section
* name: device name
* dev: shared interrupt lines用來認得該被移除的interrupt handler在哪個interrupt line上,(多人共用一條線,總要認得該踢誰出門),沒有要share的interrupt line就傳NULL
* request_irq()成功回傳0,非0有error,常見錯誤有 -EBUSY,代表此刻這條線被占用。
* request_irq()還沒進interrupt context,可以sleep。絕對不能在進入ISR後call request_irq()
* 註冊成功後會在/proc/irq看到,proc_mkdir() creates new procfs entries. proc_create()
# Freeing an Interrupt Handler
rmmod driver modules時,要unregister你的interrupt handler and potentially disable the interrupt line.

要注意你這跟interrupt line有沒有跟其他device shared,有shared的話你幹掉,這跟interrupt line也不會幹掉,透過dev
# Writing an Interrupt Handler

# Interrupt context
when executing an interrupt handler, the kernel is in **interrupt context**
回憶: 什麼時候在process context?
* kernel executing a system call
* kernel running a kernel thread
* 只有在process context ***current*** macro才有用
* 因為process跟kernel是綁在process context的,process context還可以sleep或invoke scheduler.
interrupt context:
* 跟process沒任何關係
* current沒有關聯(但好像有指向被interrupt的process)
* 你不能call帶有睡覺性質的function
* 設計方向永遠要記得 quick and simple(因為你占用的是別的process的cpu時間,還有可能你Interrupt的對象是別的interrupt handler on a different line!)
* 越快越好越快越好越快越好
* 下一章會講,總是會有需要時間的運算,該怎麼辦? 答案是拖到bottom half去解決,interrupt handling這種工作always丟給top half解決
* 有沒有自己的stack,各版本不一樣,老版本有,新版本無的樣子
*
# ret_from_intr()
interrupt handler結束後要回到之前被interrupt的環境,可能是
* userspace process (就要call schedule())
* kernel自己 (只會在preempt_count是零時call schedule(),不然is not safe to preempt the kernel)
* 回復之前的registers狀態
# /proc/interrupts

profs code: fs/proc
function name: show_interrupts()
# Status of interrupt system

in_interrupt()
> 在interrupt handling or bottom half都return nonzero代表在interrupt context,return 0代表kernel在process context。
>
in_irq()
> 只有在interrupt handling階段return nonzero,bottom half無作用
>
**Q: 為什麼區分你在process context or interrupt context很重要??!!**
**A: 因為process context你才能sleep,你在interrupt context sleep你就完蛋**
Q: What happens when an ISR is running and another interrupt happens?
A:https://stackoverflow.com/questions/24128926/what-happens-when-an-isr-is-running-and-another-interrupt-happens