驅動程式調度和執行緒

調度器可讓驅動程式在驅動程式代管程序的可用執行緒上安排非同步工作。這些共用執行緒由驅動程式執行階段管理,可提升驅動程式代管程序中驅動程式的整體效能和執行緒安全性。強烈建議驅動程式不要產生自己的執行緒。

Fuchsia 的驅動程式架構提供 fdf::Dispatcher,建議搭配 Fuchsia 驅動程式使用這個調度器。這項驅動程式庫調度員支援下列功能:

調度員作業

指派給驅動程式庫的調度員會協調及執行驅動程式庫的非同步作業。驅動程式代管程序中的所有調度器 (因此位於相同程序中),都會由驅動程式庫執行階段管理的共用執行緒集區提供支援。調度器只能在驅動程式庫執行階段環境中運作,例如驅動程式代管程序或驅動程式庫測試架構。

調度器主要處理兩項工作:在驅動程式代管程序的執行緒中排定要執行的非同步工作 (回應驅動程式庫或驅動程式代管程序建立的回呼),以及代表驅動程式庫在這些執行緒上實際執行工作 (或「呼叫驅動程式庫」)。

在下列常見情況中,調度員可能會撥打電話給驅動程式庫:

  • 執行驅動程式庫掛鉤 (請參閱「預設調度器」)。
  • 系統會執行先前註冊的非同步作業回呼。
    • 已張貼工作。
    • 已發出等待信號。
    • 收到 FIDL 要求或回應。
  • 調度器正在關閉 (請參閱「關閉調度器」)。

執行緒模型

驅動程式代管程序中的調度器可能會使用不同選項建立,以設定自己的執行緒模型,適用於:

已同步和未同步

使用 FDF_DISPATCHER_OPTION_SYNCHRONIZED 選項建立的同步調度器絕不會平行呼叫驅動程式。這可以視為單一執行緒的調度工具,但請注意,調度工具無法保證每次都會從相同執行緒呼叫驅動程式庫 (請參閱「執行緒本機儲存空間」)。

使用 FDF_DISPATCHER_OPTION_UNSYNCHRONIZED 選項建立的非同步調度器可能會平行呼叫驅動程式。不過,使用這個選項時,系統不會保證排序,所有狀態同步作業都由驅動程式庫負責。因此,建議盡可能使用同步調度器,避免這類複雜情況。

執行緒模型

圖 1. 由同步和非同步調度器排定的回呼時間軸。

如圖 1 所示,同步調度器不會顯示並行回呼,而非同步調度器則會顯示多個並行回呼。

同步作業

一般而言,不建議驅動程式發出同步呼叫,因為這可能會阻礙其他工作執行。不過,如有需要,驅動程式庫可以使用 FDF_DISPATCHER_OPTION_ALLOW_SYNC_CALLS 選項建立調度員,但這項功能僅支援同步調度員。

建立調度器時,這個選項會在執行緒集區中產生額外執行緒。這有助於驅動程式庫執行階段,降低驅動程式庫導入的同步呼叫作業,導致相同驅動程式庫主機中的其他驅動程式遭到封鎖的機率。

封鎖工作

圖 2. 時間軸:由同步調度員排定的回呼,包括使用 FDF_DISPATCHER_OPTION_ALLOW_SYNC_CALLS 選項和未使用該選項的情況。

在圖 2 中,左側的方塊 (工作 A1 和工作 A2) 代表非封鎖工作,右側的方塊 (工作 B1 和工作 B2) 則代表封鎖工作。驅動程式代管程序中的調度器會共用執行緒 1 和 2,以執行封鎖和非封鎖工作。工作 B1 正在執行同步呼叫,導致其他工作無法在執行緒 1 上排定。不過,當執行緒 1 正在使用中時,驅動程式庫執行階段可在執行緒 2 上排定非同步工作。

執行緒本機儲存空間

調度員可以從驅動程式庫執行階段管理的任何共用執行緒呼叫驅動程式庫。不過,驅動程式庫執行階段無法保證每次呼叫都會使用相同的執行緒。因此,驅動程式不應使用任何執行緒局部儲存空間 (例如在 C++ 中使用 thread_local 關鍵字),因為這類儲存空間會將變數的生命週期繫結至不同的執行緒。

重入保證

調度器絕不會對驅動程式庫進行重入呼叫。如果驅動程式庫先前在同一個呼叫堆疊中收到來自調度器的呼叫,該呼叫就會視為重入呼叫。如果呼叫會重新進入,調度器會排定在調度器迴圈的未來疊代中發生。

調度員的生命週期

驅動程式代管程序管理驅動程式庫的預設調度器生命週期。驅動程式代管程序會保證在驅動程式庫停止前,不會毀損這個調度器。

預設調度器

在 DFv2 中,系統會將調度器提供給驅動程式庫,做為驅動程式啟動掛鉤 (也就是驅動程式程式碼中的 Start() 函式) 的一部分。這會成為驅動程式庫的預設調度器。如要擷取這個調度器,驅動程式庫可以在驅動程式庫掛鉤期間呼叫 fdf::Dispatcher::GetCurrent() 函式,例如 Start()、PrepareStop() 和 Stop()。

關閉調派程式

在 DFv2 中,驅動程式代管程序會在呼叫驅動程式的 Stop() 勾點之前,自動關閉驅動程式庫的所有調度器。如果驅動程式庫希望在關機前收到通知,可以實作 PrepareStop() hook。

調度器關閉時,會以 ZX_ERR_CANCELED 狀態調度所有待處理的回呼,並呼叫提供給 fdf::Dispatcher::Create() 的關閉處理常式。

建立其他調度工具

驅動程式只能在調度器回呼期間建立額外的調度器,也就是調度器呼叫驅動程式庫時 (如需發生這種情況的範例,請參閱「調度器作業」)。與預設的調度器不同,驅動程式庫擁有並管理這些額外調度器的生命週期。

在 DFv2 中,驅動程式代管程序會在驅動程式庫關閉期間,自動關閉驅動程式的其他調度器。如果是 C++ 驅動程式,這會在 DriverBase::PrepareStop() 之後,但會在 DriverBase::Stop() 之前發生。如果是 Rust 驅動程式,這會在 Driver::stop() 後發生。