檢視原始碼 erl_ddll (kernel v10.2)
動態驅動程式載入器和連結器。
此模組提供一個介面,用於在執行階段載入和卸載Erlang 連結式驅動程式。
注意
這是一份大型參考文件。對於此模組的隨意使用,以及大多數實際應用,函式
load/2
和unload/1
的描述就足以開始使用。
驅動程式將以動態連結程式庫的形式提供,其物件程式碼格式特定於所使用的平台,也就是說,大多數 Unix 系統上的 .so
檔案和 Windows 上的 .ddl
檔案。Erlang 連結式驅動程式必須為模擬器提供特定的介面,因此此模組並非設計用於載入任意動態程式庫。有關 Erlang 驅動程式的更多資訊,請參閱 erl_driver
。
當描述一組在處理序中執行並想要使用 ddll 驅動程式的函式(即模組、模組的一部分或應用程式)時,我們使用術語使用者。一個處理序可以有多個使用者(需要相同驅動程式的不同模組),而且許多處理序可以執行相同的程式碼,形成驅動程式的許多使用者。
在基本情境中,每個使用者會在開始使用驅動程式之前載入它,並在完成後卸載驅動程式。參考計數會追蹤處理序和每個處理序載入的次數。這樣一來,只有當沒有人需要它(沒有使用者)時,才會卸載驅動程式。驅動程式也會追蹤開啟到它的埠。這使得可以延遲卸載,直到所有埠關閉,或者在卸載時關閉使用該驅動程式的所有埠。
介面支援載入和卸載的兩種基本情境。每個情境也可以選擇在卸載驅動程式時關閉埠,或者等待埠自行關閉。情境如下:
「需要時」載入和卸載 - 這個(最常見的)情境僅支援驅動程式的每個 使用者 在需要時載入它,並在不再需要時卸載它。驅動程式始終會進行參考計數,而且只要保持驅動程式載入的處理序仍然存在,驅動程式就會存在於系統中。
驅動程式的每個 使用者 在要求載入時,完全使用相同的驅動程式路徑名稱,但是 使用者 不會關心是否已經從檔案系統載入驅動程式,或者是否必須從檔案系統載入物件程式碼。
以下兩對函式支援此情境:
load/2 和 unload/1 - 當使用
load/unload
介面時,只有在關閉使用驅動程式的最後一個埠時,才會卸載驅動程式。函式unload/1
可以立即返回,因為 使用者 對何時發生卸載沒有興趣。當沒有人再需要它時,就會卸載驅動程式。如果載入驅動程式的處理序終止,其效果與完成卸載相同。
載入時,當存在驅動程式的任何實例時,函式
load/2
會傳回ok
。因此,如果驅動程式正在等待卸載(由於開啟的埠),它只會將狀態變更為不再需要卸載。load_driver/2 和 unload_driver/1 - 這些介面旨在用於當埠開啟到沒有 使用者 載入的驅動程式時,視為錯誤的情況。當最後一個 使用者 呼叫
unload_driver/1
或當載入驅動程式的最後一個處理序終止時,仍然開啟的埠會被以driver_unloaded
的原因終止。函式名稱
load_driver
和unload_driver
會保留以實現回溯相容性。
用於程式碼更換的載入和重新載入 - 如果驅動程式程式碼需要在 Erlang 模擬器運作期間更換,可能會發生此情境。實作驅動程式程式碼更換比 Beam 程式碼更換稍微繁瑣,因為一個驅動程式不能以「舊」和「新」程式碼同時載入。驅動程式的所有 使用者 都必須關閉它(沒有開啟的埠),才能卸載舊程式碼並載入新程式碼。
卸載/載入會作為一個原子操作執行,在執行期間阻止系統中的所有處理序使用有問題的驅動程式。
執行驅動程式程式碼更換的較佳方法是讓一個單一處理序追蹤驅動程式。當處理序啟動時,會載入驅動程式。當需要更換時,會重新載入驅動程式。卸載可能永遠不會完成,或者在處理序結束時完成。如果當要求程式碼更換時,有多個 使用者 載入驅動程式,則在最後一個「其他」使用者 卸載驅動程式之前,無法進行更換。
當重新載入已在進行中時,要求重新載入始終會是錯誤。使用高階函式時,當有多個 使用者 載入驅動程式時,要求重新載入也是錯誤。
為了簡化驅動程式更換,請避免設計您的系統,使得有多個 使用者 載入驅動程式。
用於重新載入驅動程式的兩個函式將與對應的載入函式一起使用,以支援有關開啟埠的兩種不同行為:
load/2 和 reload/2 - 當在關閉驅動程式的最後一個開啟埠之後執行重新載入時,會使用這對函式。
由於
reload/2
會等待重新載入發生,因此行為不當的處理序會保持驅動程式的埠開啟(或保持驅動程式載入),可能會導致無限等待重新載入。逾時必須在要求重新載入的處理序之外提供,或者透過搭配驅動程式監視器使用低階介面try_load/3
來提供。load_driver/2 和 reload_driver/2 - 當驅動程式的開啟埠被以
driver_unloaded
的原因終止,以允許載入新的驅動程式程式碼時,會使用這對函式。然而,如果另一個處理序載入驅動程式,則呼叫
reload_driver
會傳回錯誤碼pending_process
。如先前所述,建議的設計是不允許「驅動程式重新載入器」以外的其他 使用者 要求載入有問題的驅動程式。
另請參閱
摘要
函式
移除驅動程式監視器的方式與 ERTS 中 erlang:demonitor/1
移除處理序監視器的方式大致相同。
接受由載入、卸載或重新載入函式傳回的 ErrorDesc
,並傳回描述錯誤或警告的字串。
傳回元組清單 {Tag, Value}
,其中 Tag
是資訊項目,而 Value
是使用此驅動程式名稱和此標籤呼叫 info/2
的結果。結果是一個包含所有關於驅動程式可用資訊的元組清單。
傳回有關驅動程式一個特定方面的資訊。參數 Tag
指定要取得資訊的方面。傳回值 Value
在不同標籤之間有所不同
載入並連結動態驅動程式 Name
。Path
是包含驅動程式之目錄的檔案路徑。Name
必須是可共享的物件/動態程式庫。兩個具有不同 Path
參數的驅動程式不能以相同的名稱載入。Name
是包含至少一個字元的字串或原子。
基本上與 load/2
的運作方式相同,但會以其他選項載入驅動程式。當要卸載驅動程式時,會以 driver_unloaded
的原因終止使用該驅動程式的所有埠。
傳回所有可用的驅動程式清單,包括(靜態)連結式和動態載入的驅動程式。
建立驅動程式監視器,其運作方式在許多方面與 ERTS 中的 erlang:monitor/2
對處理序所做的運作方式相同。當驅動程式變更狀態時,監視器會產生一個監視器訊息,該訊息會傳送到呼叫處理序。此函式傳回的 MonitorRef
會包含在傳送的訊息中。
從可能與先前使用的 Path
不同的 Path
重新載入名為 Name
的驅動程式。此函式用於簡介中描述的程式碼變更 情境
。
其運作方式與 reload/2
完全相同,但適用於使用 load_driver/2
介面載入的驅動程式。
提供的控制能力比 load/2
/reload/2
和 load_driver/2
/reload_driver/2
介面更強。它從不等待其他與驅動程式相關的操作完成,而是立即返回驅動程式的狀態,其狀態為下列其中之一:
這是卸載(或遞減驅動程式參考計數)的底層函數。它可以像驅動程式選項 kill_ports
隱式執行一樣,用於強制終止埠。此外,它還可以觸發監控器,原因可能是其他 使用者 仍然載入著驅動程式,或因為開啟的埠正在使用該驅動程式。
卸載,或至少解除對名為 Name
的驅動程式的引用。如果呼叫者是驅動程式的最後一位 使用者,則所有剩餘的、使用該驅動程式的開啟埠都會以 driver_unloaded
的原因被終止,並且驅動程式最終會被卸載。
類型
函數
-spec demonitor(MonitorRef) -> ok when MonitorRef :: reference().
移除驅動程式監視器的方式與 ERTS 中 erlang:demonitor/1
移除處理序監視器的方式大致相同。
有關如何建立驅動程式監控器的詳細資訊,請參閱 monitor/2
、try_load/3
和 try_unload/2
。
如果參數不是 reference/0
,則該函數會拋出 badarg
異常。
接受由載入、卸載或重新載入函式傳回的 ErrorDesc
,並傳回描述錯誤或警告的字串。
注意
由於不同平台上的動態載入介面存在特殊性,因此只有在產生錯誤的 Erlang 虛擬機的同一個實例中(表示在同一個作業系統進程中)呼叫 format_error/1 時,才能保證返回的字串描述正確的錯誤。
-spec info() -> AllInfoList when AllInfoList :: [DriverInfo], DriverInfo :: {DriverName, InfoList}, DriverName :: string(), InfoList :: [InfoItem], InfoItem :: {Tag :: atom(), Value :: term()}.
傳回元組清單 {DriverName, InfoList}
,其中 InfoList
是呼叫該 DriverName
的 info/1
結果。清單中僅包含動態連結式驅動程式。
-spec info(Name) -> InfoList when Name :: driver(), InfoList :: [InfoItem, ...], InfoItem :: {Tag :: atom(), Value :: term()}.
傳回元組清單 {Tag, Value}
,其中 Tag
是資訊項目,而 Value
是使用此驅動程式名稱和此標籤呼叫 info/2
的結果。結果是一個包含所有關於驅動程式可用資訊的元組清單。
以下標籤會出現在列表中:
processes
driver_options
port_count
linked_in_driver
permanent
awaiting_load
awaiting_unload
有關每個值的詳細說明,請參閱 info/2
。
如果系統中不存在該驅動程式,則該函數會拋出 badarg
異常。
-spec info(Name, Tag) -> Value when Name :: driver(), Tag :: processes | driver_options | port_count | linked_in_driver | permanent | awaiting_load | awaiting_unload, Value :: term().
傳回有關驅動程式一個特定方面的資訊。參數 Tag
指定要取得資訊的方面。傳回值 Value
在不同標籤之間有所不同
processes
- 返回所有包含特定驅動程式的 使用者 的進程,以元組列表{pid(),integer() >= 0}
的形式呈現,其中integer/0
表示進程pid/0
中的使用者數量。driver_options
- 返回載入時提供的驅動程式選項列表,以及驅動程式在初始化期間設定的任何選項。唯一有效的選項是kill_ports
。port_count
- 返回使用驅動程式的埠數量(integer() >= 0
)。linked_in_driver
- 返回一個boolean/0
,如果驅動程式是靜態連結的驅動程式,則為true
,否則為false
。permanent
- 返回一個boolean/0
,如果驅動程式已將自己設為永久(並且不是靜態連結的驅動程式),則為true
,否則為false
。awaiting_load
- 返回所有具有loading
監控器啟用的進程列表。每個進程都以{pid(),integer() >= 0}
的形式返回,其中integer/0
是進程pid/0
持有的監控器數量。awaiting_unload
- 返回所有具有unloading
監控器啟用的進程列表。每個進程都以{pid(),integer() >= 0}
的形式返回,其中integer/0
是進程pid/0
持有的監控器數量。
如果選項 linked_in_driver
或 permanent
返回 true
,則所有其他選項分別返回 linked_in_driver
或 permanent
。
如果系統中不存在該驅動程式或不支援該標籤,則該函數會拋出 badarg
異常。
-spec load(Path, Name) -> ok | {error, ErrorDesc} when Path :: path(), Name :: driver(), ErrorDesc :: term().
載入並連結動態驅動程式 Name
。Path
是包含驅動程式之目錄的檔案路徑。Name
必須是可共享的物件/動態程式庫。兩個具有不同 Path
參數的驅動程式不能以相同的名稱載入。Name
是包含至少一個字元的字串或原子。
指定的 Name
必須對應於動態載入物件檔案的檔案名稱,該檔案位於指定為 Path
的目錄中,但不包含副檔名(即 .so
)。驅動程式初始化常式中提供的驅動程式名稱必須與檔案名稱對應,這與 Erlang 模組名稱與 .beam
檔案名稱對應的方式非常相似。
如果驅動程式先前已卸載,但由於仍有開啟的埠連線到它而仍然存在,則呼叫 load/2
會停止卸載並保留該驅動程式(只要 Path
相同),並且會返回 ok
。如果您確實希望重新載入物件程式碼,請改用 reload/2
或底層介面 try_load/3
。另請參閱導論中關於 不同情境
的載入/卸載描述。
如果有多個進程嘗試使用相同的 Path
載入已載入的驅動程式,或者如果同一進程嘗試多次載入,則該函數會返回 ok
。模擬器會追蹤 load/2
呼叫,因此必須從同一進程執行相應數量的 unload/2
呼叫,驅動程式才會被卸載。因此,應用程式可以在需要時安全地載入在進程或應用程式之間共用的驅動程式。它可以安全地被卸載,而不會給系統的其他部分帶來麻煩。
不允許載入具有相同名稱但具有不同 Path
參數的多個驅動程式。
注意
Path
會被逐字解釋,因此同一驅動程式的所有載入器都必須指定相同的字面Path
字串,儘管不同的路徑可能在檔案系統中指向相同的目錄(因為使用了相對路徑和連結)。
成功時,該函數會返回 ok
。失敗時,傳回值為 {error,ErrorDesc}
,其中 ErrorDesc
是一個不透明的詞,由函數 format_error/1
轉換為人類可讀的形式。
為了更好地控制錯誤處理,請改用 try_load/3
介面。
如果未按照此處所述指定參數,則該函數會拋出 badarg
異常。
-spec load_driver(Path, Name) -> ok | {error, ErrorDesc} when Path :: path(), Name :: driver(), ErrorDesc :: term().
基本上與 load/2
的運作方式相同,但會以其他選項載入驅動程式。當要卸載驅動程式時,會以 driver_unloaded
的原因終止使用該驅動程式的所有埠。
不同 使用者 的載入和卸載次數會影響驅動程式檔案的載入和卸載。因此,只有當最後一位 使用者 卸載驅動程式,或者當最後一個載入驅動程式的進程退出時,才會發生埠終止。
此介面(或至少函數名稱)保留為向後相容。在選項列表中使用 {driver_options,[kill_ports]}
的 try_load/3
會產生相同的埠終止效果。
如果未按照此處所述指定參數,則該函數會拋出 badarg
異常。
-spec loaded_drivers() -> {ok, Drivers} when Drivers :: [Driver], Driver :: string().
傳回所有可用的驅動程式清單,包括(靜態)連結式和動態載入的驅動程式。
出於歷史原因,驅動程式名稱以字串列表而不是原子列表的形式返回。
有關驅動程式的更多資訊,請參閱 info
。
-spec monitor(Tag, Item) -> MonitorRef when Tag :: driver, Item :: {Name, When}, Name :: driver(), When :: loaded | unloaded | unloaded_only, MonitorRef :: reference().
建立驅動程式監視器,其運作方式在許多方面與 ERTS 中的 erlang:monitor/2
對處理序所做的運作方式相同。當驅動程式變更狀態時,監視器會產生一個監視器訊息,該訊息會傳送到呼叫處理序。此函式傳回的 MonitorRef
會包含在傳送的訊息中。
與進程監控器一樣,每個驅動程式監控器集僅產生單一訊息。訊息傳送後,監控器會被「銷毀」,因此無需呼叫 demonitor/1
。
MonitorRef
也可用於後續呼叫 demonitor/1
,以移除監控器。
該函數接受以下參數:
Tag
- 監控器標籤始終為driver
,因為此函數只能用於建立驅動程式監控器。將來,驅動程式監控器將與進程監控器整合,因此必須為了保持一致性而指定此參數。Item
- 參數Item
指定要監控的驅動程式(驅動程式名稱)以及要監控的狀態變更。該參數是一個二元組,其第一個元素是驅動程式名稱,第二個元素是以下其中之一:loaded
- 在重新載入驅動程式時(或如果正在載入則在載入時)通知。僅監控正在載入或重新載入的驅動程式才有意義。無法監控未來用於載入的驅動程式名稱。那只會導致立即傳送DOWN
訊息。因此,當函數try_load/3
觸發監控時,監控載入最有用,因為該驅動程式處於這種暫止狀態。為
loading
設定驅動程式監控器最終會導致傳送以下訊息之一:{'UP', reference(), driver, Name, loaded}
- 如果驅動程式已載入且沒有待處理的重新載入,則立即傳送此訊息,或者如果正在等待重新載入,則在執行重新載入時傳送此訊息。在為載入建立監控器之前,使用者 應該知道是否需要重新載入。
{'UP', reference(), driver, Name, permanent}
- 如果預期要重新載入,但 (舊) 驅動程式在重新載入前將自身設定為永久性,則會傳送此訊息。如果驅動程式在嘗試建立監視器時是永久性的或靜態連結的,也會傳送此訊息。{'DOWN', reference(), driver, Name, load_cancelled}
- 如果重新載入正在進行中,但請求的使用者因為死亡或在重新載入之前再次呼叫try_unload/2
(或unload/1
/unload_driver/1
) 而取消了重新載入,則會收到此訊息。{'DOWN', reference(), driver, Name, {load_failure, Failure}}
- 如果重新載入正在進行中,但由於某些原因載入失敗,則會收到此訊息。Failure
詞彙是可從try_load/3
傳回的錯誤之一。 可以將錯誤詞彙傳遞給format_error/1
以轉換為人類可讀的形式。 請注意,翻譯必須在與偵測到錯誤的相同 Erlang 虛擬機器中完成。
unloaded
- 監視驅動程式何時被卸載。如果監視系統中不存在的驅動程式,則會立即收到驅動程式已卸載的通知。無法保證驅動程式曾經載入過。卸載的驅動程式監視器最終會導致傳送以下其中一個訊息
{'DOWN', reference(), driver, Name, unloaded}
- 受監視的驅動程式實例現在已卸載。由於卸載可能是reload/2
請求的結果,因此當收到此訊息時,驅動程式可以再次被載入。{'UP', reference(), driver, Name, unload_cancelled}
- 如果預期要卸載,但在驅動程式等待所有埠關閉時,出現了新的驅動程式使用者,並且取消了卸載,則會傳送此訊息。如果針對驅動程式的最後一個使用者從
try_unload/2
傳回了{ok, pending_driver}
,然後從對try_load/3
的呼叫傳回了{ok, already_loaded}
,則會出現此訊息。如果真的想要監視驅動程式何時被卸載,則此訊息會扭曲事實,因為沒有進行卸載。選項
unloaded_only
會建立類似於unloaded
監視器的監視器,但永遠不會產生此訊息。{'UP', reference(), driver, Name, permanent}
- 如果預期要卸載,但驅動程式在卸載之前將自身設定為永久性,則會傳送此訊息。如果嘗試監視永久性或靜態連結的驅動程式,也會傳送此訊息。
unloaded_only
- 以unloaded_only
建立的監視器與以unloaded
建立的監視器行為完全相同,只是永遠不會傳送{'UP', reference(), driver, Name, unload_cancelled}
訊息,但監視器會持續存在直到驅動程式真的被卸載。
如果未按照此處所述指定參數,則該函數會拋出 badarg
異常。
-spec reload(Path, Name) -> ok | {error, ErrorDesc} when Path :: path(), Name :: driver(), ErrorDesc :: pending_process | OpaqueError, OpaqueError :: term().
從可能與先前使用的 Path
不同的 Path
重新載入名為 Name
的驅動程式。此函式用於簡介中描述的程式碼變更 情境
。
如果此驅動程式還有其他使用者,則該函式會傳回{error, pending_process}
,但是如果沒有其他使用者,則函式呼叫會暫停,直到所有開啟的埠都關閉。
注意
避免將多個使用者與驅動程式重新載入請求混合使用。
若要避免在開啟的埠上暫停,請改用函式try_load/3
。
Name
和Path
參數的含義與呼叫一般函式load/2
時完全相同。
成功時,該函式會傳回ok
。失敗時,該函式會傳回一個不透明的錯誤,除了先前描述的pending_process
錯誤之外。不透明的錯誤應由函式format_error/1
轉換為人類可讀的形式。
為了更好地控制錯誤處理,請改用 try_load/3
介面。
如果未按照此處所述指定參數,則該函數會拋出 badarg
異常。
-spec reload_driver(Path, Name) -> ok | {error, ErrorDesc} when Path :: path(), Name :: driver(), ErrorDesc :: pending_process | OpaqueError, OpaqueError :: term().
其運作方式與 reload/2
完全相同,但適用於使用 load_driver/2
介面載入的驅動程式。
由於此介面表示當最後一個使用者消失時會終止埠,因此該函式不會暫停等待埠關閉。
如需更多詳細資訊,請參閱此模組描述中的scenarios
和reload/2
的函式描述。
如果未按照此處所述指定參數,則該函數會拋出 badarg
異常。
-spec try_load(Path, Name, OptionList) -> {ok, Status} | {ok, PendingStatus, Ref} | {error, ErrorDesc} when Path :: path(), Name :: driver(), OptionList :: [Option], Option :: {driver_options, DriverOptionList} | {monitor, MonitorOption} | {reload, ReloadOption}, DriverOptionList :: [DriverOption], DriverOption :: kill_ports, MonitorOption :: pending_driver | pending, ReloadOption :: pending_driver | pending, Status :: loaded | already_loaded | PendingStatus, PendingStatus :: pending_driver | pending_process, Ref :: reference(), ErrorDesc :: ErrorAtom | OpaqueError, ErrorAtom :: linked_in_driver | inconsistent | permanent | not_loaded_by_this_process | not_loaded | pending_reload | pending_process, OpaqueError :: term().
提供的控制能力比 load/2
/reload/2
和 load_driver/2
/reload_driver/2
介面更強。它從不等待其他與驅動程式相關的操作完成,而是立即返回驅動程式的狀態,其狀態為下列其中之一:
{ok, loaded}
- 驅動程式已載入且可立即使用。{ok, already_loaded}
- 驅動程式已被另一個進程載入或正在由活動的埠使用,或兩者皆是。您註冊的載入並且預期在未來某個時候會進行對應的try_unload
。{ok, pending_driver}
或{ok, pending_driver, reference()}
- 載入請求已註冊,但由於驅動程式的先前實例仍在等待卸載 (開啟的埠正在使用它),因此載入被延遲。儘管如此,當您完成使用驅動程式時,仍會預期進行卸載。此傳回值通常會在使用選項{reload,pending_driver}
或{reload,pending}
時發生,但當另一個使用者並行卸載驅動程式且設定了驅動程式選項kill_ports
時,可能會發生。換句話說,始終需要處理此傳回值。{ok, pending_process}
或{ok, pending_process, reference()}
- 載入請求已註冊,但由於驅動程式的先前實例仍在等待另一個使用者卸載 (不僅僅是埠,在這種情況下,將傳回{ok,pending_driver}
),因此載入被延遲。儘管如此,當您完成使用驅動程式時,仍會預期進行卸載。此傳回值僅在使用選項{reload,pending}
時發生。
當函式傳回{ok, pending_driver}
或{ok, pending_process}
時,可以使用選項{monitor, MonitorOption}
來取得有關驅動程式實際載入時間的資訊。
當請求監視並且將傳回對應的{ok, pending_driver}
或{ok, pending_process}
時,該函式會改為傳回一個元組{ok, PendingStatus, reference()}
,然後進程會在驅動程式載入時稍後收到監視器訊息。預期的監視器訊息在monitor/2
的函式描述中說明。
注意
在載入的情況下,監視不僅可以使用選項
{reload, ReloadOption}
觸發,而且在載入錯誤是暫時性的特殊情況下也可以觸發。因此,基本上在所有實際情況下都應使用{monitor, pending_driver}
。
該函數接受以下參數:
Path
- 驅動程式物件檔案所在目錄的檔案系統路徑。物件檔案的檔案名稱 (減去副檔名) 必須對應於驅動程式名稱 (在參數Name
中使用),並且驅動程式必須以相同的名稱識別自身。Path
可以作為iolist()提供,這表示它可以是其他iolist/0
、字元 (8 位元整數) 或二進位檔案的清單,所有這些都將被展平為字元序列。(可能已展平的)
Path
參數在整個系統中必須保持一致。驅動程式應由所有使用者使用相同的文字Path
載入。例外情況是當請求重新載入時,在這種情況下,可以不同地指定Path
。請注意,如果使用reload
選項變更了Path
,則稍後嘗試載入驅動程式的所有使用者都需要使用新的Path
。這是另一個原因,要在正在運行的系統中僅讓驅動程式有一個載入器以進行升級。Name
- 此參數是要在後續對 ERTS 中的函式erlang:open_port
的呼叫中使用的驅動程式名稱。名稱可以指定為iolist/0
或atom/0
。載入時指定的名稱用於尋找物件檔案 (在Path
和系統隱含的副檔名後綴 (即.so
) 的幫助下)。驅動程式識別自身的名稱也必須與此Name
參數一致,就像 Beam 檔案的模組名稱必須與其檔案名稱對應一樣。OptionList
- 可以指定一些選項來控制載入操作。這些選項指定為兩個元組的清單。這些元組具有以下值和含義{driver_options, DriverOptionList}
- 這是為了提供更改其一般行為並在整個生命週期中「附著」到驅動程式的選項。指定驅動程式名稱的驅動程式選項始終需要保持一致,即使重新載入驅動程式時也是如此,這表示它們與名稱一樣是驅動程式的一部分。
唯一允許的驅動程式選項是
kill_ports
,這表示當沒有任何進程再載入驅動程式時,所有開啟到驅動程式的埠都會被終止,並帶有結束原因driver_unloaded
。當最後一個使用者呼叫try_unload/2
或當最後一個載入驅動程式的進程結束時,會發生這種情況。{monitor, MonitorOption}
-MonitorOption
告訴try_load/3
在特定條件下觸發驅動程式監視器。當觸發監視器時,該函式會傳回一個三元組{ok, PendingStatus, reference()}
,其中reference/0
是驅動程式監視器的監視器參照。只能指定一個
MonitorOption
。它是以下其中之一- 原子
pending
,這表示每當載入操作被延遲時都要建立監視器, - 原子
pending_driver
,在這種情況下,每當由於開啟埠連線到否則未使用的驅動程式而延遲操作時,就會建立監視器。
選項
pending_driver
用途不大,但為了完整性而存在,因為可以明確定義哪些重新載入選項會導致哪些延遲。但是,如果存在,最好使用與ReloadOption
相同的MonitorOption
。如果未請求重新載入,則指定選項
monitor
仍然有用,因為強制卸載 (驅動程式選項kill_ports
或選項kill_ports
到try_unload/2
) 會觸發暫時狀態,在關閉所有關閉的埠之前,無法執行驅動程式載入。因此,由於try_unload
在幾乎所有情況下都可以傳回{ok, pending_driver}
,因此請務必在生產程式碼中至少指定{monitor, pending_driver}
(請參閱稍早的監視器討論)。- 原子
{reload, ReloadOption}
- 此選項用於從磁碟重新載入驅動程式,通常在程式碼升級情境中。具有reload
選項也表示參數Path
不需要與驅動程式的先前載入保持一致。若要重新載入驅動程式,進程必須先前已載入驅動程式,也就是說,進程中必須有驅動程式的活動使用者。
reload
選項可以是以下其中之一pending
- 使用原子pending
,會對任何驅動程式請求重新載入,並在所有開啟到該驅動程式的連接埠關閉時生效。在這種情況下,即使仍然有待處理的 使用者 載入該驅動程式,也會進行驅動程式更換。即使有待處理的使用者,此選項也會觸發連接埠終止(如果使用驅動程式選項
kill_ports
),使其可用於強制驅動程式更換,但將大部分責任放在驅動程式的 使用者身上。由於不希望在程式碼變更正在進行時有其他 使用者 載入驅動程式,因此很少使用 pending 選項。pending_driver
- 此選項更有用。如果驅動程式未被任何其他 使用者 載入,但驅動程式已開啟連接埠,則會將重新載入排入佇列,在這種情況下會傳回{ok, pending_driver}
(建議使用monitor
選項)。
如果驅動程式已卸載(系統中不存在),則會傳回錯誤碼
not_loaded
。選項reload
適用於使用者已提前載入驅動程式的情況。
此函式可能會傳回許多錯誤,某些錯誤只有在特定選項組合下才會傳回。
某些錯誤是不透明的,只能透過將它們傳遞給函式 format_error/1
來解讀,但某些錯誤可以直接解讀
{error,linked_in_driver}
- 指定名稱的驅動程式是 Erlang 靜態連結的驅動程式,無法使用此 API 操作。{error,inconsistent}
- 驅動程式已經載入其他DriverOptionList
或不同的字面Path
引數。即使指定了
reload
選項,如果DriverOptionList
與目前的選項不同,也可能發生這種情況。{error, permanent}
- 驅動程式已要求將自己設為永久性,使其行為類似於 Erlang 連結的驅動程式,並且無法再使用此 API 操作。{error, pending_process}
- 當指定選項{reload, pending_driver}
時,驅動程式被其他 使用者 載入。{error, pending_reload}
- 當指定選項{reload, ReloadOption}
時,另一個 使用者 已要求重新載入驅動程式。{error, not_loaded_by_this_process}
- 當指定選項reload
時出現。驅動程式Name
存在於系統中,但此程序中沒有它的 使用者。{error, not_loaded}
- 當指定選項reload
時出現。驅動程式Name
不在系統中。只有由此程序載入的驅動程式才能重新載入。
所有其他錯誤碼都必須由函式 format_error/1
轉換。請注意,由於錯誤值的系統相關行為,對 format_error
的呼叫必須從偵測到錯誤的 Erlang 虛擬機器的相同執行個體執行。
如果引數或選項格式錯誤,此函式會擲回 badarg
例外狀況。
-spec try_unload(Name, OptionList) -> {ok, Status} | {ok, PendingStatus, Ref} | {error, ErrorAtom} when Name :: driver(), OptionList :: [Option], Option :: {monitor, MonitorOption} | kill_ports, MonitorOption :: pending_driver | pending, Status :: unloaded | PendingStatus, PendingStatus :: pending_driver | pending_process, Ref :: reference(), ErrorAtom :: linked_in_driver | not_loaded | not_loaded_by_this_process | permanent.
這是卸載(或遞減驅動程式參考計數)的底層函數。它可以像驅動程式選項 kill_ports
隱式執行一樣,用於強制終止埠。此外,它還可以觸發監控器,原因可能是其他 使用者 仍然載入著驅動程式,或因為開啟的埠正在使用該驅動程式。
卸載可以描述為告知模擬器,此特定程序中的程式碼特定部分(即此 使用者)不再需要此驅動程式的過程。如果沒有其他使用者,這可能會觸發驅動程式卸載,在這種情況下,驅動程式名稱會從系統中消失,並且(如果可能)會回收驅動程式可執行程式碼所佔用的記憶體。
如果驅動程式設定了選項 kill_ports
,或者如果將 kill_ports
指定為此函式的選項,則當最後一個 使用者 完成卸載時,將會終止所有使用此驅動程式的待處理連接埠。如果未涉及連接埠終止且有開啟的連接埠,則會延遲卸載,直到沒有更多開啟的連接埠使用此驅動程式為止。如果在此情況下,在卸載驅動程式之前,有另一個 使用者(甚至是此使用者)再次載入驅動程式,則永遠不會進行卸載。
為了讓 使用者 請求卸載以等待實際卸載,可以指定 monitor
觸發器,方式與載入時非常相似。但是,由於此函式的 使用者 很少對遞減參考計數以外的事物感興趣,因此很少需要監控。
注意
如果使用選項
kill_ports
,則監控觸發至關重要,因為無法保證連接埠在驅動程式卸載之前會被終止。因此,至少對於pending_driver
情況,必須觸發監視器。
預期的可能監視器訊息與使用函式 monitor/2
的選項 unloaded
時相同。
成功後,此函式會傳回下列其中一個狀態
{ok, unloaded}
- 驅動程式已立即卸載,這表示驅動程式名稱現在可以供其他驅動程式使用,並且如果底層作業系統允許,則現在可以回收驅動程式物件程式碼所佔用的記憶體。只有在沒有開啟的連接埠使用它且沒有更多 使用者 要求載入它時,才能卸載驅動程式。
{ok, pending_driver}
或{ok, pending_driver, reference()}
- 表示此呼叫從驅動程式中移除了最後一個 使用者,但仍有開啟的連接埠使用它。當所有連接埠關閉且沒有新的 使用者 到達時,將會重新載入驅動程式並回收名稱和記憶體。即使使用了選項
kill_ports
,此傳回值也有效,因為終止連接埠可能是一個不會立即完成的過程。但是,這種情況是暫時的。監視器始終可用於偵測驅動程式何時真正卸載。{ok, pending_process}
或{ok, pending_process, reference()}
- 已註冊卸載請求,但其他 使用者 仍然持有驅動程式。請注意,術語pending_process
可以指正在執行的程序;同一個程序中可能有多個 使用者。如果呼叫只是為了告知模擬器您不再需要此驅動程式,這是正常且健全的傳回值。在簡介中描述的最常見
案例
中,這是最常見的傳回值。
該函數接受以下參數:
OptionList
- 引數OptionList
可用於指定在特定條件下有關連接埠和觸發監視器的特定行為kill_ports
- 如果您是驅動程式的最後一個 使用者,則強制終止所有使用此驅動程式開啟的連接埠,終止原因為driver_unloaded
。如果其他 使用者 已載入驅動程式,則此選項無效。
為了在最後一個 使用者 卸載時獲得終止連接埠的一致行為,請在載入驅動程式時改為使用驅動程式選項
kill_ports
。{monitor, MonitorOption}
- 如果MonitorOption
中指定的條件為 true,則建立驅動程式監視器。有效選項如下pending_driver
- 如果傳回值為{ok, pending_driver}
,則建立驅動程式監視器。pending
- 如果傳回值為{ok, pending_driver}
或{ok, pending_process}
,則建立監視器。
pending_driver
MonitorOption
是迄今為止最有用的。每當使用選項kill_ports
或驅動程式可以使用驅動程式選項kill_ports
載入時,都必須使用它來確保驅動程式確實已卸載且連接埠已關閉。在呼叫
try_unload
時使用監視器觸發器,可確保在執行卸載之前新增監視器,這表示監視器始終會正確觸發,如果單獨呼叫monitor/2
,則不會發生這種情況。
此函式可能會傳回下列錯誤條件,所有錯誤條件均已明確指定(沒有不透明的值)
{error, linked_in_driver}
- 您嘗試卸載 Erlang 靜態連結的驅動程式,該驅動程式無法使用此介面操作(且完全無法卸載)。{error, not_loaded}
- 驅動程式Name
不存在於系統中。{error, not_loaded_by_this_process}
- 驅動程式Name
存在於系統中,但此程序中沒有它的 使用者。作為特殊情況,如果根本沒有驅動程式的使用者,則可以從未呼叫過
try_load/3
的程序中卸載驅動程式,如果包含最後一個使用者的程序終止,可能會發生這種情況。{error, permanent}
- 驅動程式已將自己設為永久性,在這種情況下,它無法再由此介面操作(很像靜態連結的驅動程式)。
如果未按照此處所述指定參數,則該函數會拋出 badarg
異常。
卸載,或至少解除對名為 Name
的驅動程式的引用。如果呼叫者是驅動程式的最後一位 使用者,且沒有其他開啟的埠使用該驅動程式,則驅動程式會被卸載。否則,卸載會被延遲,直到所有埠都關閉,且沒有 使用者 存在。
如果有其他驅動程式的 使用者,則只會減少驅動程式的參考計數,以便不再將呼叫者視為驅動程式的 使用者。有關使用案例,請參閱本模組開頭的 描述
。
傳回的 ErrorDesc
是一個不透明的值,要傳遞給函式 format_error/1
。如需更精確地控制操作,請使用 try_unload/2
介面。
如果未按照此處所述指定參數,則該函數會拋出 badarg
異常。
卸載,或至少解除對名為 Name
的驅動程式的引用。如果呼叫者是驅動程式的最後一位 使用者,則所有剩餘的、使用該驅動程式的開啟埠都會以 driver_unloaded
的原因被終止,並且驅動程式最終會被卸載。
如果驅動程式還有其他使用者,則只會減少該驅動程式的參考計數,使呼叫者不再被視為使用者。使用情境請參閱此模組開頭的說明
。
傳回的 ErrorDesc
是一個不透明的值,要傳遞給函式 format_error/1
。如需更精確地控制操作,請使用 try_unload/2
介面。
如果未按照此處所述指定參數,則該函數會拋出 badarg
異常。