中斷是指裝置在需要服務時產生的非同步事件。 例如,當序列埠有可用資料時,就會產生中斷情形。 或是乙太網路封包送達 「中斷」可讓驅動程式庫在事件發生時立刻得知消息 但無法讓驅動程式庫花時間輪詢 (主動等待)。
使用中斷的驅動程式庫一般架構是 中斷處理執行緒 (IHT) 會在驅動程式庫啟動 / 繫結期間建立 作業。 此執行緒會等待中斷事件,並在中斷時執行 也就是採取的策略
以序列埠驅動程式庫為例。 系統可能會因為以下任一事件而中斷服務:
- 一或多個字元已送達
- 就可以傳送一或多個字元
- 控制線 (例如
DTR
) 已變更狀態。
幹擾值會喚醒 IHT。 IHT 會判斷事件的原因,通常是透過讀取某些狀態暫存器。 然後,它會執行適當的服務函式來處理事件。 完成後,IHT 就會回到休眠狀態,等待下一個中斷情形。
例如,假設角色抵達,IHT 會喚醒,並讀取狀態暫存器 會指出「有可用的資料」接著呼叫會排除所有可用的 從序列埠 FIFO 傳入驅動程式庫的緩衝區。
不需要核心層級程式碼
您可能熟悉其他採用「中斷」功能的作業系統 服務日常安排 (ISR)。 這些是在特權模式下執行的核心層級處理常式,以及使用 中斷控制器硬體
在 Fuchsia 中,核心會處理中斷中具有特殊權限的部分 ,並提供執行緒層級的函式供驅動程式庫使用。
差別在於 IHT 是在執行緒層級執行,ISR 則是 並存在於核心層級相當有限 (有時可能很脆弱) 主要優點是當 IHT 當機時,只會擷取 而失敗的 ISR 可能會佔用整個作業系統。
附加到中斷時
目前,唯一提供幹擾的公車是 PCI 匯流排。 支援兩種類型:舊版和郵件信號中斷 (MSI)。
因此,為了在 PCI 上使用中斷式:
- 判斷您的裝置支援的裝置類型 (舊版或 MSI),
- 將中斷模式設為相符
- 取得裝置的中斷向量 (通常是一個,但也可能有多個)
- 啟動 IHT 背景執行緒
- 安排 IHT 執行緒等待中斷 (在步驟 3 的控制代碼上)。
步驟 1
和 2
是由 `Pci::ConfigureInterruptMode 輔助函式處理:
// Configure interrupt mode.
uint32_t irq_cnt = 1;
fuchsia_hardware_pci::InterruptMode mode;
zx_status_t status = pci.ConfigureInterruptMode(irq_cnt, &mode);
if (status != ZX_OK) {
// handle error
}
Pci::ConfigureInterruptMode() 需要兩個引數:
#include <lib/device-protocol/pci.h>
zx_status_t Pci::ConfigureInterruptMode(uint32_t requested_irq_count,
fpci::InterruptMode* out_mode);
第一個引數 requested_irq_count
是您想要的中斷次數。
第二個引數是裝置支援的中斷模式的退出參數。
設定中斷式支援後,您可以呼叫 Pci::MapInterrupt() 建立所選中斷情形的控制代碼。請注意, Pci::MapInterrupt() 具有下列原型:
#include <lib/device-protocol/pci.h>
zx_status_t Pci::MapInterrupt(uint32_t which_irq, zx::interrupt* out_interrupt);
第一個引數:which_irq
表示您需要的裝置相關的中斷號碼,而第二個引數
指向已建立的中斷物件的指標。
您現在有一個中斷控點。
請注意,大多數裝置只有一個幹擾,因此只需傳遞
which_irq
的「0
」屬於正常值。 如果裝置造成多次中斷,常見的做法是for
迴圈中的 pci::MapInterrupt() 函式 以及將控點繫結至每次中斷情形
正在等待中斷
在 IHT 中,您可以呼叫 zx::interrupt::wait() 等待中斷情形 適用的原型如下:
zx_status_t zx::interrupt::wait(zx::time* out_timestamp);
第一個參數可以是 nullptr
(一般),也可以是時間的指標
戳記,指出中斷情形的觸發時間 (以奈秒表示
相對於使用擷取的單調時針來源
zx_clock_get_monotonic()
)。
因此,典型的 IHT 形狀如下:
int MyDevice::IrqThread() {
for (;;) {
zx_status_t status = dev->irq_.wait(nullptr);
// do stuff
}
}
裝置類別中有成員 (這裡 irq_
) 是您取得的物件
Pci::MapInterrupt()。
邊緣與等級中斷模式
中斷硬體可在兩種模式中運作;「邊緣」或「level」
在邊緣模式下,在主動式邊緣 (當硬體故障時) 信號會從閒置狀態轉為啟用中) 且可做為一次性測試。 也就是說,信號必須改回停用狀態,系統才能再次辨識該信號。
在層級模式下,當硬體訊號處於 啟用狀態
一般而言,在中斷的情況下,系統會使用邊緣模式,而水平模式為 由多部裝置共用中斷時使用 (因為因為需要 直到所有裝置移除要求線為止)。
Zircon 核心可視情況自動遮蓋及解除乾擾狀態。 對於層級觸發的硬體中斷 zx::interrupt::wait() 在傳回之前將中斷情況遮蓋,並在下次呼叫時將其解除遮罩。 針對邊緣觸發的中斷,中斷情形會保持解除遮罩。
IHT 不應執行任何長時間執行的工作。 對於執行長時間工作的驅動程式,請使用背景工作執行緒。
關閉使用中斷的驅動程式庫
若要徹底關閉使用中斷的驅動程式庫,您可以使用 zx::interrupt::destroy() 取消 zx::interrupt::wait() 呼叫。
概念是,當前景執行緒判定驅動程式庫應該要 關閉,只會刪除中斷控點,導致 IHT 關閉:
void MyDevice::DdkRelease() {
// destroy the handle, this will cause zx_interrupt_wait() to pop
irq_.destroy();
irq_thread_.join();
...
}
int MyDevice::IrqThread() {
...
for(;;) {
zx_status_t status = irq_.wait(nullptr);
if (status == ZX_ERR_CANCELED) {
// we are being shut down, do any cleanups required
...
break;
}
...
}
}
主執行緒在要求關閉時,會刪除中斷控點。
這會導致 IHT 的
zx::interrupt::wait()
呼叫來喚醒應用程式。
IHT 會查看錯誤代碼 (在本例中為 ZX_ERR_CANCELED
),然後
最終決定結束
與此同時,主要執行緒正在等待加入 IHT 通話
thread::join()。
IHT 離開後,thread::join() 傳回,以及
執行緒可以完成處理程序
進階閱讀器已受邀查看其他中斷情形 可用的函式: