檢視原始碼 erl_nif
Erlang NIF 函式庫的 API 函式。
說明
NIF 函式庫包含 Erlang 模組某些函式的原生實作。原生實作的函式 (NIF) 的呼叫方式與任何其他函式相同,對呼叫者而言沒有任何差異。NIF 函式庫會建置為動態連結的函式庫檔案,並在執行時透過呼叫 erlang:load_nif/2
來載入。
警告
原生函式會作為 VM 原生程式碼的直接延伸執行。執行並非在安全環境中進行。VM 無法提供與執行 Erlang 程式碼時相同的服務,例如搶佔式排程或記憶體保護。如果原生函式行為不佳,整個 VM 將會行為失常。
- 當機的原生函式會導致整個 VM 當機。
- 實作錯誤的原生函式可能會導致 VM 內部狀態不一致,這可能會導致 VM 當機,或在呼叫原生函式後的任何時間點發生 VM 的其他各種不當行為。
- 在傳回之前執行 長時間工作的原生函式會降低 VM 的反應速度,並可能導致其他各種奇怪的行為。這類奇怪的行為包括但不限於極端的記憶體使用量,以及排程器之間的不良負載平衡。由於長時間工作而可能發生的奇怪行為也可能因 Erlang/OTP 版本而異。
範例
NIF 函式庫的最小範例看起來如下
/* niftest.c */
#include <erl_nif.h>
static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
return enif_make_string(env, "Hello world!", ERL_NIF_LATIN1);
}
static ErlNifFunc nif_funcs[] =
{
{"hello", 0, hello}
};
ERL_NIF_INIT(niftest,nif_funcs,NULL,NULL,NULL,NULL)
Erlang 模組看起來如下
-module(niftest).
-export([init/0, hello/0]).
-nifs([hello/0]).
-on_load(init/0).
init() ->
erlang:load_nif("./niftest", 0).
hello() ->
erlang:nif_error("NIF library not loaded").
編譯和測試看起來如下 (在 Linux 上)
$> gcc -fPIC -shared -o niftest.so niftest.c -I $ERL_ROOT/usr/include/
$> erl
1> c(niftest).
{ok,niftest}
2> niftest:hello().
"Hello world!"
在上述範例中,on_load
指令會用於在模組載入時自動呼叫 init
函式。函式 init
又會呼叫 erlang:load_nif/2
,這會載入 NIF 函式庫,並將 hello
函式取代為其 C 原生實作。載入後,NIF 函式庫會持續存在。在清除其所屬的模組執行個體之前,它不會被卸載。
-nifs()
屬性指定模組中要以 NIF 取代的函式。
每個 NIF 都必須在 Erlang 中實作,以便在成功載入 NIF 函式庫之前呼叫該函式時可以被叫用。典型的這類 stub 實作是呼叫 erlang:nif_error
,這會引發例外狀況。如果 NIF 函式庫缺少某些作業系統或硬體架構的實作,Erlang 函式也可以用作後援實作。
注意
NIF 不需要匯出,它可以是模組的本機函式。但是,編譯器會將未使用的本機 stub 函式最佳化移除,導致 NIF 函式庫載入失敗。
功能
NIF 程式碼與 Erlang 執行階段系統之間的所有互動都是透過呼叫 NIF API 函式來執行。存在用於下列功能的函式
讀取和寫入 Erlang 項 - 任何 Erlang 項都可以作為函式引數傳遞給 NIF,並作為函式傳回值傳回。這些項屬於 C 類型
ERL_NIF_TERM
,且只能使用 API 函式讀取或寫入。大多數讀取項內容的函式都會加上enif_get_
前綴,如果項屬於預期的類型 (或不是),通常會傳回true
(或false
)。寫入項的函式都加上enif_make_
前綴,且通常會傳回建立的ERL_NIF_TERM
。還有一些函式可以用於查詢項,例如enif_is_atom
、enif_is_identical
和enif_compare
。類型
ERL_NIF_TERM
的所有項都屬於ErlNifEnv
類型的環境,但在載入期間建立的 atom 除外 (由回呼load
或upgrade
建立)。項的生命週期是由其環境物件的生命週期所控制。所有讀取或寫入項的 API 函式都會將項所屬的環境作為第一個函式引數。但是,在載入期間建立的 atom 可以作為任何ErlNifEnv
中的項進行參考。也就是說,最佳做法是在載入期間建立所有 atom,並將它們儲存在靜態/全域變數中,例如#include <erl_nif.h> ERL_NIF_TERM world_atom; static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { world_atom = enif_make_atom(env, "world"); return 0; } static ERL_NIF_TERM hello(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { ERL_NIF_TERM hello_string = enif_make_string(env, "Hello", ERL_NIF_LATIN1); return enif_make_tuple2(env, hello_string, world_atom); } static ErlNifFunc nif_funcs[] = { { "hello", 0, hello } }; ERL_NIF_INIT(niftest, nif_funcs, load, NULL, NULL, NULL)
二進位檔 - 類型為二進位的項是使用結構類型
ErlNifBinary
來存取的,該結構類型包含指向原始二進位資料的指標 (data
),以及資料的大小 (size
),單位為位元組。data
和size
都是唯讀的,且只能使用對 API 函式的呼叫來寫入。ErlNifBinary
的執行個體永遠都由使用者配置 (通常作為區域變數)。只有在呼叫
enif_alloc_binary
或enif_realloc_binary
後,data
指向的原始資料才是可變的。所有其他對二進位進行操作的函式都會將資料保留為唯讀。可變的二進位最後必須透過enif_release_binary
釋放,或透過使用enif_make_binary
將其傳輸至 Erlang 項來設為唯讀。但是,它不一定需要在同一個 NIF 呼叫中發生。唯讀的二進位不需要釋放。enif_make_new_binary
可以用作在同一個 NIF 呼叫中配置和傳回二進位的捷徑。二進位是整個位元組的序列。目前尚不支援具有任意位元長度的位元字串。
資源物件
使用資源物件是從 NIF 傳回原生資料結構指標的安全方式。資源物件只是透過enif_alloc_resource
配置的記憶體區塊。然後可以使用enif_make_resource
將此記憶體區塊的控制代碼 ("安全指標") 傳回 Erlang。enif_make_resource
傳回的項本質上是不透明的。它可以儲存並在程序之間傳遞,但唯一的真正最終用途是將其傳回給 NIF 作為引數。然後 NIF 可以呼叫enif_get_resource
並取回記憶體區塊的指標,這保證仍然有效。資源物件只有在 VM 垃圾收集器收集最後一個控制代碼項,且資源透過enif_release_resource
釋放時才會解除配置 (不一定按照該順序)。所有資源物件都會建立為某些資源類型的執行個體。這使得不同模組的資源可以區分。資源類型會在載入函式庫時透過呼叫
enif_open_resource_type
來建立。之後,可以配置該資源類型的物件,而enif_get_resource
會驗證資源是否屬於預期的類型。資源類型可以具有使用者提供的解構函式,該函式會在該類型的資源釋放時自動呼叫 (透過垃圾收集器或enif_release_resource
)。資源類型是由提供的名稱字串和實作模組的名稱唯一識別。ERL_NIF_TERM term; MyStruct* obj = enif_alloc_resource(my_resource_type, sizeof(MyStruct)); /* initialize struct ... */ term = enif_make_resource(env, obj); if (keep_a_reference_of_our_own) { /* store 'obj' in static variable, private data or other resource object */ } else { enif_release_resource(obj); /* resource now only owned by "Erlang" */ } return term;
請注意,一旦
enif_make_resource
建立要傳回給 Erlang 的項,程式碼就可以選擇保留自己的已配置結構的原生指標並稍後釋放,或立即釋放並僅依靠垃圾收集器在最終收集該項時解除配置資源物件。資源物件的另一個用途是建立具有使用者定義的記憶體管理的二進位項。
enif_make_resource_binary
會建立連接到資源物件的二進位項。當垃圾收集器收集二進位時,會呼叫資源的解構函式,屆時可以釋放二進位資料。這方面的一個範例可以是包含來自mmap
檔案的資料的二進位項。然後,解構函式可以執行munmap
來釋放記憶體區域。資源類型支援在執行時進行升級,方法是允許已載入的 NIF 函式庫接管現有的資源類型,並藉此「繼承」該類型的所有現有物件。之後,會針對繼承的物件呼叫新函式庫的解構函式,而且可以安全地卸載具有舊解構函式的函式庫。升級模組的現有資源物件必須刪除或由新的 NIF 函式庫接管。只要函式庫中存在具有解構函式的資源物件,就會延後卸載函式庫。
模組升級和靜態資料 - 已載入的 NIF 函式庫會繫結至載入它的 Erlang 模組執行個體。如果升級模組,新的模組執行個體需要載入自己的 NIF 函式庫 (或者可能選擇不載入)。但是,如果新的模組執行個體想要,它可以選擇載入與舊程式碼完全相同的 NIF 函式庫。共用動態函式庫表示函式庫定義的靜態資料也會共用。為了避免模組執行個體之間無意共用靜態資料,每個 Erlang 模組版本都可以保留自己的私人資料。此私人資料可以在載入 NIF 函式庫時設定,稍後可以透過呼叫
enif_priv_data
來擷取。執行緒和並行 - 只要 NIF 充當純函式且僅讀取提供的引數,NIF 就是執行緒安全的,無需任何明確的同步處理。當您透過靜態變數或
enif_priv_data
寫入共用狀態時,您需要提供自己的明確同步處理。這包括執行緒之間共用的程序獨立環境中的項。如果您將資源物件視為可變的物件,也需要同步處理。函式庫初始化回呼函式
load
和upgrade
即使對於共享狀態資料也是執行緒安全的。版本管理 - 當建置 NIF 函式庫時,關於 NIF API 版本資訊會被編譯到函式庫中。當載入 NIF 函式庫時,執行階段系統會驗證函式庫是否為相容版本。
erl_nif.h
定義了以下內容:ERL_NIF_MAJOR_VERSION
- 當 Erlang 執行階段系統的 NIF 函式庫發生不相容的變更時會遞增。通常,當ERL_NIF_MAJOR_VERSION
變更時,重新編譯 NIF 函式庫就足夠了,但在極少數情況下,可能表示必須稍微修改 NIF 函式庫。如果發生這種情況,當然會記錄在文件中。ERL_NIF_MINOR_VERSION
- 當新增新功能時會遞增。執行階段系統使用次要版本來確定要使用哪些功能。
如果主要版本不同,或者主要版本相同但 NIF 函式庫使用的次要版本大於執行階段系統使用的次要版本,執行階段系統通常會拒絕載入 NIF 函式庫。然而,在兩個主要版本轉換期間,主要版本提升後允許使用較舊的主要版本的 NIF 函式庫。但是,如果使用已棄用的功能,此類舊的 NIF 函式庫可能會失敗。
時間測量 - 在 NIF 函式庫中支援時間測量
I/O 佇列
Erlang nif 函式庫包含用於輕鬆處理 unix 系統呼叫writev
所使用的 I/O 向量的函式。I/O 佇列不是執行緒安全的,因此必須使用其他同步機制。SysIOVec
ErlNifIOVec
enif_ioq_create()
enif_ioq_destroy()
enif_ioq_enq_binary()
enif_ioq_enqv()
enif_ioq_deq()
enif_ioq_peek()
enif_ioq_peek_head()
enif_inspect_iovec()
enif_free_iovec()
寫入檔案描述符時的典型用法如下所示
int writeiovec(ErlNifEnv *env, ERL_NIF_TERM term, ERL_NIF_TERM *tail, ErlNifIOQueue *q, int fd) { ErlNifIOVec vec, *iovec = &vec; SysIOVec *sysiovec; int saved_errno; int iovcnt, n; if (!enif_inspect_iovec(env, 64, term, tail, &iovec)) return -2; if (enif_ioq_size(q) > 0) { /* If the I/O queue contains data we enqueue the iovec and then peek the data to write out of the queue. */ if (!enif_ioq_enqv(q, iovec, 0)) return -3; sysiovec = enif_ioq_peek(q, &iovcnt); } else { /* If the I/O queue is empty we skip the trip through it. */ iovcnt = iovec->iovcnt; sysiovec = iovec->iov; } /* Attempt to write the data */ n = writev(fd, sysiovec, iovcnt); saved_errno = errno; if (enif_ioq_size(q) == 0) { /* If the I/O queue was initially empty we enqueue any remaining data into the queue for writing later. */ if (n >= 0 && !enif_ioq_enqv(q, iovec, n)) return -3; } else { /* Dequeue any data that was written from the queue. */ if (n > 0 && !enif_ioq_deq(q, n, NULL)) return -4; } /* return n, which is either number of bytes written or -1 if some error happened */ errno = saved_errno; return n; }
長時間執行的 NIF
正如本手冊頁開頭的 警告 文字中提到的,原生函式必須相對快速地傳回,這一點至關重要。很難給出原生函式允許工作的確切最大時間量,但通常行為良好的原生函式會在 1 毫秒內傳回呼叫者。這可以使用不同的方法實現。如果您可以完全控制在原生函式中執行的程式碼,最好的方法是將工作分成多個工作區塊,並多次呼叫原生函式。但是,例如在呼叫第三方函式庫時,這並非總是可行。enif_consume_timeslice()
函式可用於通知執行階段系統 NIF 呼叫的長度。除非 NIF 執行速度非常快,否則通常都需要使用此函式。如果 NIF 呼叫太長,則必須透過以下其中一種方式處理,以避免效能降低、排程器負載平衡問題和其他奇怪的行為:
Yielding NIF - 如果長時間運行的 NIF 的功能可以拆分,以便透過一系列較短的 NIF 呼叫來實現其工作,則應用程式有兩個選項:
- 從 Erlang 層級進行一系列的 NIF 呼叫。
- 呼叫一個 NIF,該 NIF 首先執行一部分工作,然後呼叫
enif_schedule_nif
函式以排程另一個 NIF 呼叫來執行下一部分工作。以這種方式排程的最後一次呼叫可以傳回整體結果。
以這種方式分解長時間執行的函式,使 VM 能夠在 NIF 呼叫之間重新獲得控制權。
從效能角度和系統特性角度來看,這種方法始終優先於下面描述的其他替代方法。
執行緒化 NIF - 這是透過將工作分派給由 NIF 函式庫管理的另一個執行緒、從 NIF 傳回並等待結果來完成的。執行緒可以使用
enif_send
將結果傳送回 Erlang 程序。下面提供了有關執行緒基本功能的資訊。Dirty NIF
無法拆分且無法在一毫秒或更短的時間內執行的 NIF 被稱為「dirty NIF」,因為它執行的工作是 Erlang 執行階段系統的普通排程器無法乾淨地處理的。使用此類函式的應用程式必須向執行階段表明這些函式是 dirty 的,以便可以特別處理它們。這是透過在名為 dirty 排程器的獨立排程器集中執行 dirty 作業來處理的。在 dirty 排程器上執行的 dirty NIF 沒有與普通 NIF 相同的持續時間限制。正確分類 dirty 作業非常重要。I/O 綁定作業應如此分類,而 CPU 綁定作業也應如此分類。如果您應將 CPU 綁定作業分類為 I/O 綁定作業,則 dirty I/O 排程器可能會使普通排程器處於飢餓狀態。I/O 綁定作業預期會阻塞等待 I/O 和/或花費有限的時間來移動資料。
若要排程 dirty NIF 以供執行,應用程式有兩個選項:
- 在其
ErlNifFunc
條目中為 dirty NIF 設定適當的 flags 值。 - 呼叫
enif_schedule_nif
,將要執行的 dirty NIF 的指標傳遞給它,並使用引數flags
指示它預期操作是 CPU 綁定還是 I/O 綁定。
在 I/O 綁定和 CPU 綁定之間交替的作業可以使用
enif_schedule_nif
重新分類和重新排程,以便它始終在正確類型的 dirty 排程器上執行。有關更多資訊,請參閱 erl 命令列引數+SDcpu
和+SDio
的文件。當程序執行 dirty NIF 時,與其通信的一些操作可能需要很長時間才能完成。在 dirty NIF 傳回之前,無法暫停或垃圾收集正在執行 dirty NIF 的程序。因此,等待這些操作完成的其他程序可能必須等待很長時間。封鎖多重排程,即呼叫
erlang:system_flag(multi_scheduling, block)
也可能需要很長時間才能完成。這是因為所有 dirty 排程器上的所有正在進行的 dirty 操作都必須完成,封鎖操作才能完成。但是,許多與執行 dirty NIF 的程序通信的操作可以在執行 dirty NIF 時完成。例如,透過
process_info
擷取有關它的資訊、設定其組長、註冊/取消註冊其名稱等等。執行 dirty NIF 的程序的終止只能在執行 dirty NIF 時完成到某種程度。所有 Erlang 資源(例如其已註冊的名稱和其 ETS 表格)都會釋放。所有連結和監視器都會被觸發。但是,NIF 的執行不會停止。NIF 可以安全地繼續執行、分配堆記憶體等等,但當然最好盡快停止執行。NIF 可以使用
enif_is_current_process_alive
檢查目前的程序是否處於活動狀態。當傳送程序不處於活動狀態時,使用enif_send
和enif_port_command
進行的通信也會被丟棄。某些內部資源(例如程序堆積和程序控制區塊)的釋放會延遲到 dirty NIF 完成。- 在其
初始化
ERL_NIF_INIT(MODULE, ErlNifFunc funcs[], load, NULL, upgrade, unload)
- 這是初始化 NIF 函式庫的神奇巨集。它將在全域檔案範圍內求值。MODULE
是 Erlang 模組的名稱,作為沒有字串引號的識別碼。它由巨集字串化。funcs
是此函式庫中所有已實作 NIF 的函式描述符的靜態陣列。load
、upgrade
和unload
是指向函式的指標。將呼叫load
或upgrade
其中之一來初始化函式庫。呼叫unload
來釋放函式庫。所有這些都在下面單獨描述。第四個引數
NULL
會被忽略。它先前用於已棄用的reload
回呼,自 OTP 20 以來不再支援該回呼。如果編譯 NIF 程式庫以透過
--enable-static-nifs
進行靜態包含,則必須將巨集STATIC_ERLANG_NIF_LIBNAME
定義為封存檔案的名稱(不包括副檔名 .a),且沒有字串引號。它只能包含 C 縮排器中允許的字元。必須在包含erl_nif.h
之前定義巨集。如果改為使用較舊的巨集STATIC_ERLANG_NIF
,則封存檔案的名稱必須與模組的名稱相符。int (*load)(ErlNifEnv* caller_env, void** priv_data, ERL_NIF_TERM load_info)
- 當載入 NIF 函式庫且此模組沒有先前載入的函式庫時,會呼叫load
。如果函式庫需要在 NIF 呼叫之間保持狀態,則可以設定
*priv_data
指向某些私有資料。enif_priv_data
會傳回此指標。呼叫load
時,*priv_data
會初始化為NULL
。load_info
是erlang:load_nif/2
的第二個引數。如果
load
傳回的值不是0
,則函式庫無法載入。如果不需要初始化,則load
可以為NULL
。int (*upgrade)(ErlNifEnv* caller_env, void** priv_data, void** old_priv_data, ERL_NIF_TERM load_info)
-upgrade
會在 NIF 函式庫載入,且此模組有舊程式碼並已載入 NIF 函式庫時被呼叫。其運作方式與
load
相同,但*old_priv_data
已經包含舊模組實例最後一次呼叫load
或upgrade
所設定的值。upgrade
被呼叫時,*priv_data
會初始化為NULL
。可以同時寫入*priv_data
和*old_priv_data
。如果
upgrade
回傳的值不是0
,或者upgrade
為NULL
,則函式庫載入會失敗。void (*unload)(ErlNifEnv* caller_env, void* priv_data)
- 當 NIF 函式庫所屬的模組實例被清除為舊版時,會呼叫unload
。相同模組的新程式碼可能存在,也可能不存在。
資料類型
ERL_NIF_TERM
-ERL_NIF_TERM
類型的變數可以參考任何 Erlang 項。這是一種不透明的類型,其值只能用作 API 函式的引數或 NIF 的回傳值。所有ERL_NIF_TERM
都屬於一個環境 (ErlNifEnv
)。項無法單獨解構,它會保持有效直到其環境被解構。ErlNifEnv
-ErlNifEnv
代表一個可以容納 Erlang 項的環境。只要環境有效,環境中的所有項都有效。ErlNifEnv
是一種不透明的類型;指向它的指標只能傳遞給 API 函式。存在三種環境:程序綁定環境
作為第一個引數傳遞給所有 NIF。傳遞給 NIF 的所有函式引數都屬於該環境。NIF 的回傳值也必須是屬於同一環境的項。程序綁定環境包含有關呼叫 Erlang 程序暫時性的資訊。該環境僅在它作為引數提供的執行緒中有效,直到 NIF 回傳為止。因此,在 NIF 呼叫之間儲存指向程序綁定環境的指標是無用且危險的。
回呼環境
作為第一個引數傳遞給所有非 NIF 回呼函式 (load
、upgrade
、unload
、dtor
、down
、stop
和dyncall
)。其運作方式類似於程序綁定環境,但使用一個在回呼函式回傳時「終止」的暫時性虛擬程序。可以在此環境中建立項,但它們僅在回呼期間可存取。程序獨立環境
透過呼叫enif_alloc_env
建立。此環境可用於在 NIF 呼叫之間儲存項,並使用enif_send
發送項。具有其所有項的程序獨立環境會保持有效,直到您使用enif_free_env
或enif_send
明確使其失效為止。
列表/元組/映射的所有包含項必須屬於與列表/元組/映射本身相同的環境。可以使用
enif_make_copy
在環境之間複製項。ErlNifFunc
typedef struct { const char* name; unsigned arity; ERL_NIF_TERM (*fptr)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); unsigned flags; } ErlNifFunc;
透過其名稱、arity 和實作描述 NIF。
fptr
- 指向實作 NIF 的函式的指標。argv
- 包含傳遞給 NIF 的函式引數。argc
- 陣列長度,即函式 arity。argv[N-1]
因此表示 NIF 的第 N 個引數。請注意,引數argc
允許相同的 C 函式實作多個具有不同 arity (但可能具有相同名稱) 的 Erlang 函式。flags
- 對於常規 NIF 為0
(因此對於靜態初始化的ErlNifFunc
實例可以省略其值)。flags
可以用來指示 NIF 是一個 dirty NIF,將在 dirty 排程器執行緒上執行。如果預期 dirty NIF 是 CPU 密集型,則其
flags
欄位應設定為ERL_NIF_DIRTY_JOB_CPU_BOUND
或ERL_NIF_DIRTY_JOB_IO_BOUND
。注意
如果設定了
ERL_NIF_DIRTY_JOB_*_BOUND
旗標之一,且執行時系統不支援 dirty 排程器,則執行時系統會拒絕載入 NIF 函式庫。
ErlNifBinary
typedef struct { size_t size; unsigned char* data; } ErlNifBinary;
ErlNifBinary
包含有關檢查的二進制項的暫時性資訊。data
是指向具有二進制原始內容的size
位元組緩衝區的指標。請注意,
ErlNifBinary
是一種半不透明的類型,您只允許讀取欄位size
和data
。ErlNifBinaryToTerm
- 可指定給enif_binary_to_term
的選項列舉。對於預設行為,請使用值0
。從不受信任的來源接收資料時,請使用選項
ERL_NIF_BIN2TERM_SAFE
。ErlNifMonitor
- 這是一種識別監視器的不透明資料類型。當呼叫
enif_monitor_process
時,nif 撰寫器會提供儲存監視器的記憶體。執行時系統不會儲存資料的位址,因此ErlNifMonitor
可以像任何其他資料一樣使用,可以複製、在記憶體中移動、遺忘等等。若要比較兩個監視器,必須使用enif_compare_monitors
。ErlNifOnHaltCallback
typedef void ErlNifOnHaltCallback(void *priv_data);
on halt 回呼函式的函式原型。
可以使用
enif_set_option()
安裝 on halt 回呼。當執行時系統停止時,將會呼叫此類已安裝的回呼。ErlNifOnUnloadThreadCallback
typedef void ErlNifOnUnloadThreadCallback(void *priv_data);
on_unload_thread 回呼函式的函式原型。
可以使用
enif_set_option()
安裝 on_unload_thread 回呼。當此模組實例被清除時,每個排程器執行緒都會呼叫此類已安裝的回呼。ErlNifOption
- 可以使用enif_set_option()
設定的選項列舉。目前有效的選項
ERL_NIF_OPT_DELAY_HALT
- 啟用執行時系統停止的延遲,並啟用刷新,直到 NIF 函式庫中的所有 NIF 呼叫都回傳為止。ERL_NIF_OPT_ON_HALT
- 安裝一個回呼,當執行時系統停止並啟用刷新時,將會呼叫該回呼。ERL_NIF_OPT_ON_UNLOAD_THREAD
- 安裝一個回呼,當 NIF 函式庫所屬的模組實例被清除為舊版時,每個排程器執行緒都會呼叫該回呼。
ErlNifPid
- 程序識別碼 (pid)。與 pid 項 (ERL_NIF_TERM
的實例) 相反,ErlNifPid
是獨立的,不綁定到任何 環境。ErlNifPid
是一種不透明的類型。它可以複製、在記憶體中移動、遺忘等等。ErlNifPort
- 連接埠識別碼。與連接埠 ID 項 (ERL_NIF_TERM
的實例) 相反,ErlNifPort
是獨立的,不綁定到任何 環境。ErlNifPort
是一種不透明的類型。它可以複製、在記憶體中移動、遺忘等等。ErlNifResourceType
-ErlNifResourceType
的每個實例都代表一類可進行垃圾回收的記憶體管理資源物件。每個資源類型都有一個唯一的名稱和一個解構函式,當其類型的物件被釋放時會呼叫該解構函式。ErlNifResourceTypeInit
typedef struct { ErlNifResourceDtor* dtor; // #1 Destructor ErlNifResourceStop* stop; // #2 Select stop ErlNifResourceDown* down; // #3 Monitor down int members; ErlNifResourceDynCall* dyncall; // #4 Dynamic call } ErlNifResourceTypeInit;
由 enif_open_resource_type_x enif_init_resource_type 讀取的初始化結構。
ErlNifResourceDtor
typedef void ErlNifResourceDtor(ErlNifEnv* caller_env, void* obj);
資源解構函式的函式原型。
obj
引數是指向資源的指標。在解構函式中,唯一允許使用資源的方式是最後一次存取其使用者資料。解構函式保證是資源解除配置之前的最後一個回呼。ErlNifResourceDown
typedef void ErlNifResourceDown(ErlNifEnv* caller_env, void* obj, ErlNifPid* pid, ErlNifMonitor* mon);
在 enif_monitor_process 的請求下呼叫的資源 down 函式的函式原型。
obj
是資源,pid
是正在退出的被監視程序的識別碼,mon
是監視器的識別碼。ErlNifResourceStop
typedef void ErlNifResourceStop(ErlNifEnv* caller_env, void* obj, ErlNifEvent event, int is_direct_call);
在 enif_select 的請求下呼叫的資源停止函式的函式原型。
obj
是資源,event
是作業系統事件,如果呼叫直接來自enif_select
,則is_direct_call
為 true,如果呼叫是排程的呼叫 (可能來自另一個執行緒),則為 false。ErlNifResourceDynCall
typedef void ErlNifResourceDynCall(ErlNifEnv* caller_env, void* obj, void* call_data);
動態資源呼叫函式的功能原型,由 enif_dynamic_resource_call 呼叫。參數
obj
是資源物件,而call_data
是傳遞給enif_dynamic_resource_call
的最後一個參數。ErlNifCharEncoding
typedef enum { ERL_NIF_LATIN1, ERL_NIF_UTF8, }ErlNifCharEncoding;
字串和原子中使用的字元編碼。唯一支援的編碼是 ISO Latin-1 (8 位元 ASCII) 的
ERL_NIF_LATIN1
和 UTF-8 的ERL_NIF_UTF8
。ErlNifSysInfo
- 由enif_system_info
用於回傳關於執行時系統的資訊。包含與ErlDrvSysInfo
相同的內容。ErlNifSInt64
- 原生有號 64 位元整數型別。ErlNifUInt64
- 原生無號 64 位元整數型別。ErlNifTime
- 用於表示時間的有號 64 位元整數型別。ErlNifTimeUnit
- NIF API 支援的時間單位列舉。ERL_NIF_SEC
- 秒。ERL_NIF_MSEC
- 毫秒。ERL_NIF_USEC
- 微秒。ERL_NIF_NSEC
- 奈秒。
ErlNifUniqueInteger
- 可以從enif_make_unique_integer
請求的屬性列舉。對於預設屬性,請使用值0
。ERL_NIF_UNIQUE_POSITIVE
- 僅回傳正整數。ERL_NIF_UNIQUE_MONOTONIC
- 僅回傳對應於建立時間的嚴格單調遞增的整數。
ErlNifHash
- 可以使用enif_hash
產生的支援雜湊型別列舉。ERL_NIF_INTERNAL_HASH
- 不可移植的雜湊函式,僅保證在一個 Erlang VM 實例中,相同的 term 會產生相同的雜湊值。它採用 32 位元的 salt 值,並產生介於
0..2^32-1
的雜湊值。ERL_NIF_PHASH2
- 可移植的雜湊函式,無論機器架構和 ERTS 版本如何,相同的 Erlang term 都會產生相同的雜湊值。它會忽略 salt 值,並產生介於
0..2^27-1
的雜湊值。比
ERL_NIF_INTERNAL_HASH
慢。它對應於erlang:phash2/1
。
SysIOVec
- 系統 I/O 向量,如 Unix 上的writev
和 Win32 上的WSASend
所使用。它在ErlNifIOVec
中以及enif_ioq_peek
中使用。ErlNifIOVec
typedef struct { int iovcnt; size_t size; SysIOVec* iov; } ErlNifIOVec;
一個包含
iovcnt
個指向資料的SysIOVec
的 I/O 向量。它由enif_inspect_iovec
和enif_ioq_enqv
使用。ErlNifIOQueueOpts
- 設定ErlNifIOQueue
的選項。- ERL_NIF_IOQ_NORMAL - 建立一個正常的 I/O 佇列。
enif_alloc()
void * enif_alloc(
size_t size);
配置 size
位元組的記憶體。
如果配置失敗,則回傳 NULL
。
回傳的指標會適當地對齊,以符合配置記憶體中的任何內建型別。
enif_alloc_binary()
int enif_alloc_binary(
size_t size,
ErlNifBinary* bin);
配置一個新的二元資料,大小為 size
位元組。初始化 bin
指向的結構,使其參照到配置的二元資料。二元資料必須由 enif_release_binary
釋放,或使用 enif_make_binary
將所有權轉移到 Erlang term。配置的 (且擁有的) ErlNifBinary
可以在 NIF 呼叫之間保留。
如果您不需要重新配置或在 NIF 呼叫之間保持資料有效,請考慮使用 enif_make_new_binary
,因為它會在可能的情況下在程序堆積上配置小的二元資料。
成功時回傳 true
,如果配置失敗則回傳 false
。
enif_alloc_env()
ErlNifEnv * enif_alloc_env();
配置一個新的程序獨立環境。該環境可用於保存未繫結到任何程序的 term。此類 term 稍後可以使用 enif_make_copy
複製到程序環境中,或使用 enif_send
作為訊息傳送到程序。
回傳新環境的指標。
自 OTP R14B 起可用
enif_alloc_resource()
void * enif_alloc_resource(
ErlNifResourceType* type,
unsigned size);
配置一個記憶體管理的資源物件,其類型為 type
,大小為 size
位元組。
自 OTP R13B04 起可用
enif_binary_to_term()
size_t enif_binary_to_term(
ErlNifEnv *env,
const unsigned char* data,
size_t size,
ERL_NIF_TERM *term,
unsigned int opts);
建立一個 term,它是解碼 data
處二元資料的結果,該資料必須根據 Erlang 外部 term 格式進行編碼。從 data
讀取的位元組數不超過 size
。參數 opts
對應於 erlang:binary_to_term/2
的第二個參數,且必須為 0
或 ERL_NIF_BIN2TERM_SAFE
。
成功時,將產生的 term 儲存在 *term
中,並回傳讀取的位元組數。如果解碼失敗或 opts
無效,則回傳 0
。
另請參閱 ErlNifBinaryToTerm
、erlang:binary_to_term/2
和 enif_term_to_binary
。
自 OTP 19.0 起可用
enif_clear_env()
void enif_clear_env(ErlNifEnv* env);
釋放環境中的所有 term,並清除環境以供重複使用。該環境必須已使用 enif_alloc_env
進行配置。
自 OTP R14B 起可用
enif_compare()
int enif_compare(
ERL_NIF_TERM lhs,
ERL_NIF_TERM rhs);
如果 lhs
< rhs
,則回傳小於 0
的整數;如果 lhs
= rhs
,則回傳 0
;如果 lhs
> rhs
,則回傳大於 0
的整數。對應於 Erlang 運算子 ==
、/=
、=<
、<
、>=
和 >
(但不是 =:=
或 =/=
)。
自 OTP R13B04 起可用
enif_compare_monitors()
int enif_compare_monitors(
const ErlNifMonitor *monitor1,
const ErlNifMonitor *monitor2);
比較兩個 ErlNifMonitor
。也可以用於對監視器施加一些人為的順序,無論出於何種原因。
如果 monitor1
和 monitor2
相等,則回傳 0
;如果 monitor1
< monitor2
,則回傳小於 0
的值;如果 monitor1
> monitor2
,則回傳大於 0
的值。
自 OTP 20.0 起可用
enif_compare_pids()
int enif_compare_pids(
const ErlNifPid *pid1,
const ErlNifPid *pid2);
根據 term 順序比較兩個 ErlNifPid
。
如果 pid1
和 pid2
相等,則回傳 0
;如果 pid1
< pid2
,則回傳小於 0
的值;如果 pid1
> pid2
,則回傳大於 0
的值。
自 OTP 22.0 起可用
enif_cond_broadcast()
void enif_cond_broadcast(
ErlNifCond *cnd);
與 erl_drv_cond_broadcast
相同。
自 OTP R13B04 起可用
enif_cond_create()
ErlNifCond * enif_cond_create(
char *name);
與 erl_drv_cond_create
相同。
自 OTP R13B04 起可用
enif_cond_destroy()
void enif_cond_destroy(
ErlNifCond *cnd);
與 erl_drv_cond_destroy
相同。
自 OTP R13B04 起可用
enif_cond_name()
char* enif_cond_name(
ErlNifCond* cnd);
與 erl_drv_cond_name
相同。
自 OTP 21.0 起可用
enif_cond_signal()
void enif_cond_signal(
ErlNifCond *cnd);
與 erl_drv_cond_signal
相同。
自 OTP R13B04 起可用
enif_cond_wait()
void enif_cond_wait(
ErlNifCond *cnd,
ErlNifMutex *mtx);
與 erl_drv_cond_wait
相同。
自 OTP R13B04 起可用
enif_consume_timeslice()
int enif_consume_timeslice(
ErlNifEnv *env,
int percent);
向執行時系統提供一個提示,說明自上次提示以來,或自 NIF 開始以來 (如果未指定先前的提示) 目前的 NIF 呼叫已消耗多少 CPU 時間。時間被指定為一個百分比,表示一個程序允許執行 Erlang 程式碼,直到它可以被暫停以給其他可執行程序時間的 timeslice。排程 timeslice 不是一個精確的實體,但通常可以近似為大約 1 毫秒。
請注意,是否以及如何使用此資訊取決於執行時系統。某些平台上的實作可以使用其他方法來判斷消耗的 CPU 時間。無論如何,耗時的 NIF 應該頻繁呼叫 enif_consume_timeslice
以判斷是否允許繼續執行。
參數 percent
必須是介於 1 和 100 之間的整數。此函式只能從呼叫 NIF 的執行緒中呼叫,且參數 env
必須是呼叫進程的環境。
如果時間片已耗盡,則傳回 1
,否則傳回 0
。如果傳回 1
,NIF 應盡快傳回,以便進程讓出。
提供此函式是為了更好地支援協作排程、提高系統回應能力,並更容易防止因為 NIF 獨佔排程器執行緒而導致虛擬機行為異常。它可以將長時間工作分割成多次重複的 NIF 呼叫,而無需建立執行緒。
另請參閱此手冊頁開頭的警告文字。
自 OTP R16B 起可用
enif_convert_time_unit()
ErlNifTime enif_convert_time_unit(
ErlNifTime val,
ErlNifTimeUnit from,
ErlNifTimeUnit to);
將時間單位 from
的 val
值轉換為時間單位 to
的對應值。結果會使用 floor 函式捨去。
val
- 要轉換時間單位的值。from
-val
的時間單位。to
- 傳回值的時間單位。
如果使用無效的時間單位參數呼叫,則傳回 ERL_NIF_TIME_ERROR
。
另請參閱 ErlNifTime
和 ErlNifTimeUnit
。
自 OTP 18.3 起可用
enif_cpu_time()
ERL_NIF_TERM enif_cpu_time(
ErlNifEnv *env);
以與 erlang:timestamp()
相同的格式傳回 CPU 時間。CPU 時間是目前的邏輯 CPU 自過去某個任意時間點以來所花費的執行時間。如果作業系統不支援擷取此值,enif_cpu_time
會呼叫 enif_make_badarg
。
自 OTP 19.0 起可用
enif_demonitor_process()
int enif_demonitor_process(
ErlNifEnv* caller_env,
void* obj,
const ErlNifMonitor* mon);
取消先前使用 enif_monitor_process
建立的監視器。參數 obj
是指向保留監視器的資源的指標,而 *mon
則識別該監視器。
參數 caller_env
是呼叫執行緒的環境(程序綁定或回呼環境),如果從不是由 ERTS 產生的自訂執行緒呼叫,則為 NULL
。
如果監視器已成功識別並移除,則傳回 0
。如果無法識別監視器,則傳回非零值,表示它可能是
- 從未為此資源建立
- 已取消
- 已觸發
- 即將被並行執行緒觸發
此函式是執行緒安全的。
自 OTP 20.0 起可用
enif_dynamic_resource_call()
int enif_dynamic_resource_call(
ErlNifEnv* caller_env,
ERL_NIF_TERM rt_module,
ERL_NIF_TERM rt_name,
ERL_NIF_TERM resource,
void* call_data);
呼叫由另一個 NIF 模組實作的資源類型程式碼。原子 rt_module
和 rt_name
識別要呼叫的資源類型。參數 resource
識別該類型的資源物件。
已識別資源類型的回呼dyncall
將使用指向資源物件obj
的指標和傳遞的參數call_data
來呼叫。call_data
參數通常是指向結構的指標,該結構用於將參數傳遞給 dyncall
函式,並將結果傳回給呼叫者。
如果呼叫了 dyncall
回呼函式,則傳回 0。如果未進行呼叫,則傳回非零值,如果 rt_module
和 rt_name
未識別具有 dyncall
回呼的資源類型,或者 resource
不是該類型的資源物件,就會發生這種情況。
自 OTP 24.0 起可用
enif_equal_tids()
int enif_equal_tids(
ErlNifTid tid1,
ErlNifTid tid2);
與 erl_drv_equal_tids
相同。
自 OTP R13B04 起可用
enif_fprintf()
int enif_fprintf(
FILE *stream,
const char *format,
...);
類似於 fprintf
,但此格式字串也接受 "%T"
,它會格式化 ERL_NIF_TERM
類型的 Erlang 項。
此函式主要用於偵錯目的。不建議使用 %T
列印非常大的項。即使成功,此函式也可能會更改 errno
。
自 OTP 21.0 起可用
enif_free()
void enif_free(
void* ptr);
釋放由 enif_alloc
配置的記憶體。
enif_free_env()
void enif_free_env(
ErlNifEnv* env);
釋放使用 enif_alloc_env
配置的環境。環境中建立的所有項也會被釋放。
自 OTP R14B 起可用
enif_free_iovec()
void enif_free_iovec(
ErlNifIOVec* iov);
釋放從 enif_inspect_iovec
傳回的 io 向量。只有在將 NULL
環境傳遞給 enif_inspect_iovec
時才需要此操作。
ErlNifIOVec *iovec = NULL;
size_t max_elements = 128;
ERL_NIF_TERM tail;
if (!enif_inspect_iovec(NULL, max_elements, term, &tail, &iovec))
return 0;
// Do things with the iovec
/* Free the iovector, possibly in another thread or nif function call */
enif_free_iovec(iovec);
自 OTP 20.1 起可用
enif_get_atom()
int enif_get_atom(
ErlNifEnv *env,
ERL_NIF_TERM term,
char *buf,
unsigned size,
ErlNifCharEncoding encoding);
在 buf
指向的大小為 size
位元組的緩衝區中寫入一個以 NULL
結尾的字串,其中包含使用編碼的原子 term
的字串表示形式。
傳回寫入的位元組數(包括終止 NULL
字元),如果 term
不是原子,且使用 encoding
時最大長度為 size-1
位元組,則傳回 0
。
自 OTP R13B04 起可用
enif_get_atom_length()
int enif_get_atom_length(
ErlNifEnv *env,
ERL_NIF_TERM term,
unsigned *len,
ErlNifCharEncoding encoding);
將 *len
設定為使用 編碼的原子 term
的長度(不包括終止 NULL
字元的位元組數)。
成功時傳回 true
,如果 term
不是原子,或者無法使用 encoding
對原子進行編碼,則傳回 false
。
自 OTP R14B 起可用
enif_get_double()
int enif_get_double(
ErlNifEnv* env,
ERL_NIF_TERM term,
double* dp);
將 *dp
設定為 term
的浮點值。
成功時傳回 true
,如果 term
不是浮點數,則傳回 false
。
自 OTP R13B04 起可用
enif_get_int()
int enif_get_int(
ErlNifEnv* env,
ERL_NIF_TERM term,
int* ip);
將 *ip
設定為 term
的整數值。
成功時傳回 true
,如果 term
不是整數,或超出 int
類型的範圍,則傳回 false
。
enif_get_int64()
int enif_get_int64(
ErlNifEnv* env,
ERL_NIF_TERM term,
ErlNifSInt64* ip);
將 *ip
設定為 term
的整數值。
成功時傳回 true
,如果 term
不是整數,或超出帶號 64 位元整數的範圍,則傳回 false
。
自 OTP R14B 起可用
enif_get_local_pid()
int enif_get_local_pid(
ErlNifEnv* env,
ERL_NIF_TERM term,
ErlNifPid* pid);
如果 term
是節點本機程序的 pid,此函式會從中初始化 pid 變數 *pid
並傳回 true
。否則傳回 false
。不會檢查程序是否還在執行中。
注意
如果參數
term
是原子undefined
,enif_get_local_pid
將傳回 false。
自 OTP R14B 起可用
enif_get_local_port()
int enif_get_local_port(
ErlNifEnv* env,
ERL_NIF_TERM term,
ErlNifPort* port_id);
如果 term
識別節點本機埠,此函式會從中初始化埠變數 *port_id
並傳回 true
。否則傳回 false
。不會檢查埠是否還在執行中。
自 OTP 19.0 起可用
enif_get_list_cell()
int enif_get_list_cell(
ErlNifEnv* env,
ERL_NIF_TERM list,
ERL_NIF_TERM* head,
ERL_NIF_TERM* tail);
從列表 list
設定 *head
和 *tail
。
成功時傳回 true
,如果它不是列表或列表為空,則傳回 false
。
enif_get_list_length()
int enif_get_list_length(
ErlNifEnv* env,
ERL_NIF_TERM term,
unsigned* len);
將 *len
設定為列表 term
的長度。
成功時傳回 true
,如果 term
不是正確的列表,則傳回 false
。
自 OTP R14B 起可用
enif_get_long()
int enif_get_long(
ErlNifEnv* env,
ERL_NIF_TERM term,
long int* ip);
將 *ip
設定為 term
的長整數值。
成功時傳回 true
,如果 term
不是整數,或超出 long int
類型的範圍,則傳回 false
。
自 OTP R13B04 起可用
enif_get_map_size()
int enif_get_map_size(
ErlNifEnv* env,
ERL_NIF_TERM term,
size_t *size);
將 *size
設定為映射 term
中鍵值對的數量。
成功時返回 true
,如果 term
不是映射則返回 false
。
自 OTP 18.0 起可用
enif_get_map_value()
int enif_get_map_value(
ErlNifEnv* env,
ERL_NIF_TERM map,
ERL_NIF_TERM key,
ERL_NIF_TERM* value);
將 *value
設定為映射 map
中與 key
關聯的值。
成功時返回 true
,如果 map
不是映射,或者如果 map
不包含 key
,則返回 false
。
自 OTP 18.0 起可用
enif_get_resource()
int enif_get_resource(
ErlNifEnv* env,
ERL_NIF_TERM term,
ErlNifResourceType* type,
void** objp);
將 *objp
設定為指向由 term
引用的資源物件。
成功時返回 true
,如果 term
不是類型為 type
的資源物件的句柄,則返回 false
。
enif_get_resource
不會為資源物件新增參考。但是,只要資源句柄 term
有效,則保證在 *objp
中收到的指標有效。
自 OTP R13B04 起可用
enif_get_string()
int enif_get_string(
ErlNifEnv* env,
ERL_NIF_TERM list,
char* buf,
unsigned size,
ErlNifCharEncoding encoding);
在 buf
所指向的大小為 size
的緩衝區中寫入一個以 NULL
結尾的字串,該字串由字串 list
中的字元組成。字元使用編碼寫入。
返回以下其中之一
- 寫入的位元組數(包括終止的
NULL
字元) - 如果由於緩衝區空間而截斷了字串,則為
-size
- 如果
list
不是可以使用encoding
編碼的字串,或者如果size
<1
,則為0
。
除非緩衝區 size
< 1
,否則寫入的字串始終以 NULL
結尾。
自 OTP R13B04 起可用
enif_get_string_length()
int enif_get_string_length(
ErlNifEnv *env,
ERL_NIF_TERM list,
unsigned *len,
ErlNifCharEncoding encoding);
將 *len
設定為字串 list
的長度(不包括終止 NULL
字元的位元組數),並使用編碼。
成功時返回 true
,如果 list
不是可以使用 encoding
編碼的字串,則返回 false
。
自 OTP 26.0 起可用
enif_get_tuple()
int enif_get_tuple(
ErlNifEnv* env,
ERL_NIF_TERM term,
int* arity,
const ERL_NIF_TERM** array);
如果 term
是一個元組,此函數會將 *array
設定為指向包含元組元素的陣列,並將 *arity
設定為元素數。請注意,該陣列是唯讀的,且 (*array)[N-1]
是元組的第 N 個元素。如果元組的元數為零,則 *array
未定義。
成功時返回 true
,如果 term
不是元組,則返回 false
。
自 OTP R13B04 起可用
enif_get_uint()
int enif_get_uint(
ErlNifEnv* env,
ERL_NIF_TERM term,
unsigned int* ip);
將 *ip
設定為 term
的無符號整數值。
成功時返回 true
,如果 term
不是無符號整數或超出 unsigned int
類型的界限,則返回 false
。
自 OTP R13B04 起可用
enif_get_uint64()
int enif_get_uint64(
ErlNifEnv* env,
ERL_NIF_TERM term,
ErlNifUInt64* ip);
將 *ip
設定為 term
的無符號整數值。
成功時返回 true
,如果 term
不是無符號整數或超出無符號 64 位元整數的界限,則返回 false
。
自 OTP R14B 起可用
enif_get_ulong()
int enif_get_ulong(
ErlNifEnv* env,
ERL_NIF_TERM term,
unsigned long* ip);
將 *ip
設定為 term
的無符號長整數值。
成功時返回 true
,如果 term
不是無符號整數或超出 unsigned long
類型的界限,則返回 false
。
enif_getenv()
int enif_getenv(
const char* key,
char* value,
size_t *value_size);
與 erl_drv_getenv
相同。
自 OTP 18.2 起可用
enif_has_pending_exception()
int enif_has_pending_exception(
ErlNifEnv* env,
ERL_NIF_TERM* reason);
如果環境 env
有關聯的待處理例外,則返回 true
。如果 reason
是一個 NULL
指標,則忽略它。否則,如果存在與 env
關聯的待處理例外,則將 *reason
設定為例外術語的值。例如,如果呼叫 enif_make_badarg
來設定待處理的 badarg
例外,則稍後呼叫 enif_has_pending_exception(env, &reason)
會將 *reason
設定為原子 badarg
,然後返回 true
。
另請參閱 enif_make_badarg
和 enif_raise_exception
。
自 OTP 18.0 起可用
enif_hash()
ErlNifUInt64 enif_hash(
ErlNifHash type,
ERL_NIF_TERM term,
ErlNifUInt64 salt);
根據指定的 ErlNifHash
type
對 term
進行雜湊處理。
所取鹽 (如果有) 和傳回值的範圍取決於雜湊類型。
自 OTP 20.0 起可用
enif_inspect_binary()
int enif_inspect_binary(
ErlNifEnv* env,
ERL_NIF_TERM bin_term,
ErlNifBinary* bin);
使用有關二元術語 bin_term
的資訊初始化 bin
所指向的結構。
成功時返回 true
,如果 bin_term
不是二元,則返回 false
。
enif_inspect_iolist_as_binary()
int enif_inspect_iolist_as_binary(
ErlNifEnv* env,
ERL_NIF_TERM term,
ErlNifBinary* bin);
使用與 iolist
具有相同位元組內容的連續緩衝區初始化 bin
所指向的結構。與 inspect_binary
一樣,bin
所指向的資料是暫時性的,不需要釋放。
成功時返回 true
,如果 iolist
不是 iolist,則返回 false
。
自 OTP R13B04 起可用
enif_inspect_iovec()
int enif_inspect_iovec(
ErlNifEnv* env,
size_t max_elements,
ERL_NIF_TERM iovec_term,
ERL_NIF_TERM* tail,
ErlNifIOVec** iovec);
使用 iovec_term
中提供的二元清單來填入 iovec
。呼叫中處理的元素數限制為 max_elements
,且 tail
設定為清單的其餘部分。請注意,在某些平台上,輸出可能長於 max_elements
。
若要從任意 iolist 建立二元清單,請使用 erlang:iolist_to_iovec/1
。
在呼叫此函數時,iovec
應該包含指向 NULL
的指標或應該在可能的情況下使用的 ErlNifIOVec 結構。例如:
/* Don't use a pre-allocated structure */
ErlNifIOVec *iovec = NULL;
enif_inspect_iovec(env, max_elements, term, &tail, &iovec);
/* Use a stack-allocated vector as an optimization for vectors with few elements */
ErlNifIOVec vec, *iovec = &vec;
enif_inspect_iovec(env, max_elements, term, &tail, &iovec);
iovec
的內容在呼叫的 nif 函數返回之前有效。如果 iovec
應該在 nif 呼叫返回後仍然有效,則可以使用 NULL
環境呼叫此函數。如果未給定環境,則 iovec
擁有向量中的資料,且必須使用 enif_free_iovec
明確釋放。
成功時返回 true
,如果 iovec_term
不是 iovec,則返回 false
。
自 OTP 20.1 起可用
enif_ioq_create()
ErlNifIOQueue * enif_ioq_create(
ErlNifIOQueueOpts opts);
建立可用於儲存資料的新 I/O 佇列。opts
必須設定為 ERL_NIF_IOQ_NORMAL
。
自 OTP 20.1 起可用
enif_ioq_destroy()
void enif_ioq_destroy(
ErlNifIOQueue *q);
銷毀 I/O 佇列並釋放其所有內容
自 OTP 20.1 起可用
enif_ioq_deq()
int enif_ioq_deq(
ErlNifIOQueue *q,
size_t count,
size_t *size);
從 I/O 佇列取消佇列 count
個位元組。如果 size
不是 NULL
,則會將佇列的新大小放在那裡。
成功時返回 true
,如果 I/O 不包含 count
個位元組,則返回 false
。如果失敗,則佇列將保持不變。
自 OTP 20.1 起可用
enif_ioq_enq_binary()
int enif_ioq_enq_binary(
ErlNifIOQueue *q,
ErlNifBinary *bin,
size_t skip);
將 bin
放入 q
中,跳過前 skip
個位元組。
成功時返回 true
,如果 skip
大於 bin
的大小,則返回 false
。二元資料的任何所有權都會轉移到佇列,且在 NIF 呼叫的其餘部分將 bin
視為唯讀,然後視為已釋放。
自 OTP 20.1 起可用
enif_ioq_enqv()
int enif_ioq_enqv(
ErlNifIOQueue *q,
ErlNifIOVec *iovec,
size_t skip);
將 iovec
放入 q
中,跳過前 skip
個位元組。
成功時返回 true
,如果 skip
大於 iovec
的大小,則返回 false
。
自 OTP 20.1 起可用
enif_ioq_peek()
SysIOVec * enif_ioq_peek(
ErlNifIOQueue *q,
int *iovlen);
將 I/O 佇列取得為指向 SysIOVec
陣列的指標。它也會傳回 iovlen
中的元素數。
此函數不會從佇列中移除任何項目,必須使用 enif_ioq_deq
執行此操作。
傳回的陣列適合與 Unix 系統呼叫 writev
一起使用。
自 OTP 20.1 起可用
enif_ioq_peek_head()
int enif_ioq_peek_head(
ErlNifEnv *env,
ErlNifIOQueue *q,
size_t *size,
ERL_NIF_TERM *bin_term);
取得 IO 佇列的頭部,作為二進制項。
如果 size
不是 NULL
,頭部的大小會放在該處。
此函數不會從佇列中移除任何項目,必須使用 enif_ioq_deq
執行此操作。
成功時返回 true
,如果佇列為空則返回 false
。
自 OTP 21.0 起可用
enif_ioq_size()
size_t enif_ioq_size(
ErlNifIOQueue *q);
取得 q
的大小。
自 OTP 20.1 起可用
enif_is_atom()
int enif_is_atom(
ErlNifEnv* env,
ERL_NIF_TERM term);
如果 term
是原子 (atom),則返回 true
。
自 OTP R13B04 起可用
enif_is_binary()
int enif_is_binary(
ErlNifEnv* env,
ERL_NIF_TERM term);
如果 term
是二進制 (binary),則返回 true
。
enif_is_current_process_alive()
int enif_is_current_process_alive(
ErlNifEnv* env);
如果目前正在執行的進程仍然存活,則返回 true
,否則返回 false
。
此函數只能從 NIF 呼叫的執行緒中使用,並且環境必須對應於目前正在執行的進程。
自 OTP 19.0 起可用
enif_is_empty_list()
int enif_is_empty_list(
ErlNifEnv* env,
ERL_NIF_TERM term);
如果 term
是空列表,則返回 true
。
自 OTP R13B04 起可用
enif_is_exception()
int enif_is_exception(
ErlNifEnv* env,
ERL_NIF_TERM term);
如果 term
是例外 (exception),則返回 true。
自 OTP R14B03 起可用
enif_is_fun()
int enif_is_fun(
ErlNifEnv* env,
ERL_NIF_TERM term);
如果 term
是 fun (匿名函數),則返回 true
。
自 OTP R13B04 起可用
enif_is_identical()
int enif_is_identical(
ERL_NIF_TERM lhs,
ERL_NIF_TERM rhs);
如果兩個項是完全相同的,則返回 true
。對應於 Erlang 運算符 =:=
和 =/=
。
自 OTP R13B04 起可用
enif_is_list()
int enif_is_list(
ErlNifEnv* env,
ERL_NIF_TERM term);
如果 term
是一個列表,則返回 true
。
自 OTP R14B 起可用
enif_is_map()
int enif_is_map(
ErlNifEnv* env,
ERL_NIF_TERM term);
如果 term
是一個 map (映射),則返回 true
,否則返回 false
。
自 OTP 18.0 起可用
enif_is_number()
int enif_is_number(
ErlNifEnv* env,
ERL_NIF_TERM term);
如果 term
是一個數字,則返回 true
。
自 OTP R15B 起可用
enif_is_pid()
int enif_is_pid(
ErlNifEnv* env,
ERL_NIF_TERM term);
如果 term
是一個 pid (進程識別碼),則返回 true
。
自 OTP R13B04 起可用
enif_is_pid_undefined()
int enif_is_pid_undefined(
const ErlNifPid* pid);
如果 pid
已被 enif_set_pid_undefined
設為未定義,則返回 true
。
自 OTP 22.0 起可用
enif_is_port()
int enif_is_port(
ErlNifEnv* env,
ERL_NIF_TERM term);
如果 term
是一個 port (端口),則返回 true
。
自 OTP R13B04 起可用
enif_is_port_alive()
int enif_is_port_alive(
ErlNifEnv* env,
ErlNifPort *port_id);
如果 port_id
仍然存活,則返回 true
。
此函式是執行緒安全的。
自 OTP 19.0 起可用
enif_is_process_alive()
int enif_is_process_alive(
ErlNifEnv* env,
ErlNifPid *pid);
如果 pid
仍然存活,則返回 true
。
此函式是執行緒安全的。
自 OTP 19.0 起可用
enif_is_ref()
int enif_is_ref(
ErlNifEnv* env,
ERL_NIF_TERM term);
如果 term
是一個 reference (參考),則返回 true
。
自 OTP R13B04 起可用
enif_is_tuple()
int enif_is_tuple(
ErlNifEnv* env,
ERL_NIF_TERM term);
如果 term
是一個 tuple (元組),則返回 true
。
自 OTP R14B 起可用
enif_keep_resource()
int enif_keep_resource(
void* obj);
為從 enif_alloc_resource
取得的資源物件 obj
添加一個引用。每次呼叫 enif_keep_resource
於某個物件,都必須在該物件被銷毀之前,透過呼叫 enif_release_resource
來平衡。
自 OTP R14B 起可用
enif_make_atom()
ERL_NIF_TERM enif_make_atom(
ErlNifEnv *env,
const char *name);
使用 ISO Latin-1 編碼,從以 NULL
結尾的 C 字串 name
建立一個原子項。如果 name
的長度超過原子允許的最大長度(255 個字元),enif_make_atom
會調用 enif_make_badarg
。
enif_make_atom_len()
ERL_NIF_TERM enif_make_atom_len(
ErlNifEnv *env,
const char *name,
size_t len);
使用 ISO Latin-1 編碼,從長度為 len
的字串 name
建立一個原子項。NULL
字元會被視為任何其他字元。如果 len
超過原子允許的最大長度(255 個字元),enif_make_atom
會調用 enif_make_badarg
。
自 OTP R14B 起可用
enif_make_badarg()
ERL_NIF_TERM enif_make_badarg(
ErlNifEnv* env);
建立一個 badarg
例外,以便從 NIF 返回,並將其與環境 env
關聯。一旦 NIF 或其調用的任何函數調用了 enif_make_badarg
,運行時會確保在 NIF 返回時引發 badarg
例外,即使 NIF 嘗試返回一個非例外項也是如此。
從 enif_make_badarg
返回的值只能用作調用它的 NIF (直接或間接) 的返回值,或者傳遞給 enif_is_exception
,但不能傳遞給任何其他 NIF API 函數。
另請參閱 enif_has_pending_exception
和 enif_raise_exception
。
注意
在 ERTS 7.0(Erlang/OTP 18)之前,從
enif_make_badarg
返回的值必須從 NIF 返回。此要求現在已取消,因為如果已調用enif_make_badarg
,則會忽略 NIF 的返回值。
enif_make_binary()
ERL_NIF_TERM enif_make_binary(
ErlNifEnv* env,
ErlNifBinary* bin);
從 bin
建立二進制項。二進制資料的任何所有權都轉移到建立的項,並且在 NIF 呼叫的其餘部分,bin
被視為唯讀,然後被釋放。
enif_make_copy()
ERL_NIF_TERM enif_make_copy(
ErlNifEnv* dst_env,
ERL_NIF_TERM src_term);
建立項 src_term
的副本。副本在環境 dst_env
中建立。源項可以位於任何環境中。
自 OTP R14B 起可用
enif_make_double()
ERL_NIF_TERM enif_make_double(
ErlNifEnv* env,
double d);
從 double
建立一個浮點數項。如果參數 double
不是有限的或為 NaN,enif_make_double
會調用 enif_make_badarg
。
自 OTP R13B04 起可用
enif_make_existing_atom()
int enif_make_existing_atom(
ErlNifEnv *env,
const char *name,
ERL_NIF_TERM *atom,
ErlNifCharEncoding encoding);
嘗試從具有 編碼 的以 NULL
結尾的 C 字串 name
建立一個已存在的原子項。
如果原子已存在,此函數會將項存儲在 *atom
中並返回 true
,否則返回 false
。如果字串 name
超過原子允許的最大長度(255 個字元),或者 name
的編碼不正確,則也會返回 false
。
自 OTP R13B04 起可用
enif_make_existing_atom_len()
int enif_make_existing_atom_len(
ErlNifEnv *env,
const char *name,
size_t len,
ERL_NIF_TERM *atom,
ErlNifCharEncoding encoding);
嘗試從長度為 len
位元組且具有 編碼 的字串 name
建立一個已存在的原子項。NULL
字元會被視為任何其他字元。
如果原子已存在,此函數會將項存儲在 *atom
中並返回 true
,否則返回 false
。如果字串 name
超過原子允許的最大長度(255 個字元),或者 name
的編碼不正確,則也會返回 false
。
自 OTP R14B 起可用
enif_make_int()
ERL_NIF_TERM enif_make_int(
ErlNifEnv* env,
int i);
建立一個整數項。
enif_make_int64()
ERL_NIF_TERM enif_make_int64(
ErlNifEnv* env,
ErlNifSInt64 i);
從一個有符號 64 位元整數建立一個整數項。
自 OTP R14B 起可用
enif_make_list()
ERL_NIF_TERM enif_make_list(
ErlNifEnv* env,
unsigned cnt,
...);
建立一個長度為 cnt
的普通列表項。預期 cnt
數量(在 cnt
之後)類型為 ERL_NIF_TERM
的參數作為列表的元素。
如果 cnt
為 0,則返回一個空列表。
enif_make_list1()
enif_make_list2()
enif_make_list3()
enif_make_list4()
enif_make_list5()
enif_make_list6()
enif_make_list7()
enif_make_list8()
enif_make_list9()
ERL_NIF_TERM enif_make_list1(
ErlNifEnv* env,
ERL_NIF_TERM e1);
ERL_NIF_TERM enif_make_list2(
ErlNifEnv* env,
ERL_NIF_TERM e1, ERL_NIF_TERM e2);
ERL_NIF_TERM enif_make_list3(
ErlNifEnv* env,
ERL_NIF_TERM e1, ERL_NIF_TERM e2, ERL_NIF_TERM e3);
ERL_NIF_TERM enif_make_list4(
ErlNifEnv* env,
ERL_NIF_TERM e1, ..., ERL_NIF_TERM e4);
ERL_NIF_TERM enif_make_list5(
ErlNifEnv* env,
ERL_NIF_TERM e1, ..., ERL_NIF_TERM e5);
ERL_NIF_TERM enif_make_list6(
ErlNifEnv* env,
ERL_NIF_TERM e1, ..., ERL_NIF_TERM e6);
ERL_NIF_TERM enif_make_list7(
ErlNifEnv* env,
ERL_NIF_TERM e1, ..., ERL_NIF_TERM e7);
ERL_NIF_TERM enif_make_list8(
ErlNifEnv* env,
ERL_NIF_TERM e1, ..., ERL_NIF_TERM e8);
ERL_NIF_TERM enif_make_list9(
ErlNifEnv* env,
ERL_NIF_TERM e1, ..., ERL_NIF_TERM e9);
建立一個長度由函數名稱指示的普通列表項。與可變參數 enif_make_list
相比,首選這些函數(巨集),以便在參數數量不匹配時獲得編譯時錯誤。
自 OTP R13B04 起可用
enif_make_list_cell()
ERL_NIF_TERM enif_make_list_cell(
ErlNifEnv* env,
ERL_NIF_TERM head,
ERL_NIF_TERM tail);
建立一個列表單元格 [head | tail]
。
enif_make_list_from_array()
ERL_NIF_TERM enif_make_list_from_array(
ErlNifEnv* env,
const ERL_NIF_TERM arr[],
unsigned cnt);
建立一個包含長度為 cnt
的陣列 arr
元素的普通列表。
如果 cnt
為 0,則返回一個空列表。
自 OTP R13B04 起可用
enif_make_long()
ERL_NIF_TERM enif_make_long(
ErlNifEnv* env,
long int i);
從 long int
建立一個整數項。
自 OTP R13B04 起可用
enif_make_map_put()
int enif_make_map_put(
ErlNifEnv* env,
ERL_NIF_TERM map_in,
ERL_NIF_TERM key,
ERL_NIF_TERM value,
ERL_NIF_TERM* map_out);
建立 map map_in
的副本,並插入具有 value
的 key
。如果 key
已存在於 map_in
中,則舊的關聯值會被 value
替換。
如果成功,此函數會將 *map_out
設定為新的 map 並返回 true
。如果 map_in
不是 map,則返回 false
。
map_in
項必須屬於環境 env
。
自 OTP 18.0 起可用
enif_make_map_remove()
int enif_make_map_remove(
ErlNifEnv* env,
ERL_NIF_TERM map_in,
ERL_NIF_TERM key,
ERL_NIF_TERM* map_out);
如果 map map_in
包含 key
,此函數會在 *map_out
中建立 map_in
的副本,並移除 key
和相關的值。如果 map map_in
不包含 key
,則 *map_out
會被設定為 map_in
。
成功時返回 true
,如果 map_in
不是 map 則返回 false
。
map_in
項必須屬於環境 env
。
自 OTP 18.0 起可用
enif_make_map_update()
int enif_make_map_update(
ErlNifEnv* env,
ERL_NIF_TERM map_in,
ERL_NIF_TERM key,
ERL_NIF_TERM new_value,
ERL_NIF_TERM* map_out);
建立 map map_in
的副本,並將 key
的舊相關值替換為 new_value
。
如果成功,此函數會將 *map_out
設定為新的 map 並返回 true
。如果 map_in
不是 map 或不包含 key
,則返回 false
。
map_in
項必須屬於環境 env
。
自 OTP 18.0 起可用
enif_make_map_from_arrays()
int enif_make_map_from_arrays(
ErlNifEnv* env,
ERL_NIF_TERM keys[],
ERL_NIF_TERM values[],
size_t cnt,
ERL_NIF_TERM *map_out);
從給定的鍵和值建立 map 項。
如果成功,此函數會將 *map_out
設定為新的 map 並返回 true
。如果有任何重複的鍵,則返回 false
。
所有鍵和值必須屬於 env
。
自 OTP 21.0 起可用
enif_make_monitor_term()
ERL_NIF_TERM enif_make_monitor_term(
ErlNifEnv* env,
const ErlNifMonitor* mon);
建立一個 term,用於識別從 enif_monitor_process
收到的給定監視器。
此函數主要用於除錯目的。
自 OTP 22.0 起可用
enif_make_new_atom()
int enif_make_new_atom(
ErlNifEnv *env,
const char *name,
ERL_NIF_TERM *atom,
ErlNifCharEncoding encoding);
從以 NULL
結尾的 C 字串 name
建立一個 atom 項,並使用 編碼。
如果成功,則返回 true
,並且 atom 項會儲存在 *atom
中。
否則,如果 name
的長度超過 atom 允許的最大長度(255 個字元),或者如果 name
未正確編碼,則返回 false
。
自 OTP 26.0 起可用
enif_make_new_atom_len()
int enif_make_new_atom_len(
ErlNifEnv *env,
const char *name,
size_t len,
ERL_NIF_TERM *atom,
ErlNifCharEncoding encoding);
從長度為 len
位元組的字串 name
建立一個 atom 項,並使用 編碼。
如果成功,則返回 true
,並且 atom 項會儲存在 *atom
中。
否則,如果字串超過 atom 允許的最大長度(255 個字元),或者如果字串未正確編碼,則返回 false
。
自 OTP 26.0 起可用
enif_make_new_binary()
unsigned char * enif_make_new_binary(
ErlNifEnv* env,
size_t size,
ERL_NIF_TERM* termp);
分配大小為 size
位元組的二進位資料,並建立一個擁有的項。二進位資料在呼叫 NIF 返回之前是可變的。這是一種建立新二進位資料的快速方法,無需使用 ErlNifBinary
。缺點是二進位資料無法在 NIF 呼叫之間保留,也無法重新分配。
返回指向原始二進位資料的指標,並將 *termp
設定為二進位項。
自 OTP R14B 起可用
enif_make_new_map()
ERL_NIF_TERM enif_make_new_map(
ErlNifEnv* env);
建立一個空的 map 項。
自 OTP 18.0 起可用
enif_make_pid()
ERL_NIF_TERM enif_make_pid(
ErlNifEnv* env,
const ErlNifPid* pid);
從 *pid
建立 pid 項或 atom undefined
。
自 OTP R14B 起可用
enif_make_ref()
ERL_NIF_TERM enif_make_ref(
ErlNifEnv* env);
建立一個類似 erlang:make_ref/0
的參考。
自 OTP R13B04 起可用
enif_make_resource()
ERL_NIF_TERM enif_make_resource(
ErlNifEnv* env,
void* obj);
建立一個不透明的句柄,指向由 enif_alloc_resource
取得的記憶體管理資源物件。沒有執行所有權轉移,因為資源物件仍然需要由 enif_release_resource
釋放。但是,請注意,對 enif_release_resource
的呼叫可以在從 enif_make_resource
取得 term 後立即發生,在這種情況下,當 term 被垃圾回收時,資源物件會被釋放。如需更多詳細資訊,請參閱使用者指南中 建立和返回資源物件的範例。
注意
自 ERTS 9.0 (OTP-20.0) 起,資源 term 在透過
term_to_binary
進行比較和序列化或在節點之間傳遞時具有已定義的行為。
當傳遞給
enif_get_resource
時,如果兩個資源 term 會產生相同的資源物件指標,則它們將比較相等。如果資源物件在呼叫
binary_to_term
時仍然存在,則可以使用term_to_binary
序列化資源 term,並稍後完全重新建立。如果資源物件已被釋放,則將從binary_to_term
返回過時的資源 term。對於過時的資源 term,enif_get_resource
將返回 false。當在訊息中將資源 term 傳遞到遠端節點並再次傳回時,也適用相同的序列化原則。資源 term 在除了其資源物件仍存在於記憶體中的節點之外的所有節點上都將視為過時。
在 ERTS 9.0 (OTP-20.0) 之前,所有資源 term 都彼此比較相等,並與空的二進位資料 (
<<>>
) 相等。如果序列化,它們將被重新建立為普通的空二進位資料。
自 OTP R13B04 起可用
enif_make_resource_binary()
ERL_NIF_TERM enif_make_resource_binary(
ErlNifEnv* env,
void* obj,
const void* data,
size_t size);
建立一個二進位項,該項的記憶體由 enif_alloc_resource
取得的資源物件 obj
管理。返回的二進位項由 data
指向的 size
位元組組成。此原始二進位資料必須保持可讀且不變,直到呼叫資源的解構函式。二進位資料可以儲存在資源物件的外部,在這種情況下,解構函式負責釋放資料。
多個二進位項可以由同一個資源物件管理。解構函式直到最後一個二進位資料被垃圾回收才被呼叫。這對於返回較大二進位緩衝區的不同部分很有用。
與 enif_make_resource
一樣,沒有執行所有權轉移。資源仍然需要使用 enif_release_resource
釋放。
自 OTP R14B 起可用
enif_make_reverse_list()
int enif_make_reverse_list(
ErlNifEnv* env,
ERL_NIF_TERM list_in,
ERL_NIF_TERM *list_out);
將 *list_out
設定為清單 list_in
的反向清單,並返回 true
;如果 list_in
不是清單,則返回 false
。
此函數僅適用於短清單,因為會建立清單的副本,該副本在 NIF 返回後才會被釋放。
list_in
項必須屬於環境 env
。
自 OTP R15B 起可用
enif_make_string()
ERL_NIF_TERM enif_make_string(
ErlNifEnv *env,
const char *string,
ErlNifCharEncoding encoding);
建立一個包含以 NULL
結尾的字串 string
字元的清單,並使用 編碼。
enif_make_string_len()
ERL_NIF_TERM enif_make_string_len(
ErlNifEnv *env,
const char *string,
size_t len,
ErlNifCharEncoding encoding);
建立一個包含長度為 len
的字串 string
字元的清單,並使用 編碼。NULL
字元會被視為任何其他字元。
自 OTP R14B 起可用
enif_make_sub_binary()
ERL_NIF_TERM enif_make_sub_binary(
ErlNifEnv* env,
ERL_NIF_TERM bin_term,
size_t pos,
size_t size);
建立二進位資料 bin_term
的子二進位資料,從以零為基礎的位置 pos
開始,長度為 size
位元組。bin_term
必須是二進位資料或位元字串。pos+size
必須小於或等於 bin_term
中完整位元組的數量。
自 OTP R13B04 起可用
enif_make_tuple()
ERL_NIF_TERM enif_make_tuple(
ErlNifEnv* env,
unsigned cnt,
...);
建立一個 arity 為 cnt
的 tuple 項。需要 cnt
個類型為 ERL_NIF_TERM
的引數(在 cnt
之後),作為 tuple 的元素。
enif_make_tuple1()
enif_make_tuple2()
enif_make_tuple3()
enif_make_tuple4()
enif_make_tuple5()
enif_make_tuple6()
enif_make_tuple7()
enif_make_tuple8()
enif_make_tuple9()
ERL_NIF_TERM enif_make_tuple1(
ErlNifEnv* env,
ERL_NIF_TERM e1);
ERL_NIF_TERM enif_make_tuple2(
ErlNifEnv* env,
ERL_NIF_TERM e1, ERL_NIF_TERM e2);
ERL_NIF_TERM enif_make_tuple3(
ErlNifEnv* env,
ERL_NIF_TERM e1, ERL_NIF_TERM e2, ERL_NIF_TERM e3);
ERL_NIF_TERM enif_make_tuple4(
ErlNifEnv* env,
ERL_NIF_TERM e1, ..., ERL_NIF_TERM e4);
ERL_NIF_TERM enif_make_tuple5(
ErlNifEnv* env,
ERL_NIF_TERM e1, ..., ERL_NIF_TERM e5);
ERL_NIF_TERM enif_make_tuple6(
ErlNifEnv* env,
ERL_NIF_TERM e1, ..., ERL_NIF_TERM e6);
ERL_NIF_TERM enif_make_tuple7(
ErlNifEnv* env,
ERL_NIF_TERM e1, ..., ERL_NIF_TERM e7);
ERL_NIF_TERM enif_make_tuple8(
ErlNifEnv* env,
ERL_NIF_TERM e1, ..., ERL_NIF_TERM e8);
ERL_NIF_TERM enif_make_tuple9(
ErlNifEnv* env,
ERL_NIF_TERM e1, ..., ERL_NIF_TERM e9);
建立一個長度由函數名稱指示的 tuple 項。優先使用這些函數(巨集)而不是可變引數 enif_make_tuple
,以便在引數數量不符時產生編譯時間錯誤。
自 OTP R13B04 起可用
enif_make_tuple_from_array()
ERL_NIF_TERM enif_make_tuple_from_array(
ErlNifEnv* env,
const ERL_NIF_TERM arr[],
unsigned cnt);
建立一個包含長度為 cnt
的陣列 arr
元素的 tuple。
自 OTP R13B04 起可用
enif_make_uint()
ERL_NIF_TERM enif_make_uint(
ErlNifEnv* env,
unsigned int i);
從 unsigned int
建立一個整數項。
自 OTP R13B04 起可用
enif_make_uint64()
ERL_NIF_TERM enif_make_uint64(
ErlNifEnv* env,
ErlNifUInt64 i);
從 unsigned 64 位元整數建立一個整數項。
自 OTP R14B 起可用
enif_make_ulong()
ERL_NIF_TERM enif_make_ulong(
ErlNifEnv* env,
unsigned long i);
從 unsigned long int
建立一個整數項。
enif_make_unique_integer()
ERL_NIF_TERM enif_make_unique_integer(
ErlNifEnv *env,
ErlNifUniqueInteger properties);
返回一個唯一整數,其屬性與 erlang:unique_integer/1
指定的屬性相同。
env
是在其中建立整數的環境。
ERL_NIF_UNIQUE_POSITIVE
和 ERL_NIF_UNIQUE_MONOTONIC
可以作為第二個參數傳遞,以變更返回整數的屬性。它們可以透過 OR 運算結合在一起。
另請參閱 ErlNifUniqueInteger
。
自 OTP 19.0 起可用
enif_map_iterator_create()
int enif_map_iterator_create(
ErlNifEnv *env,
ERL_NIF_TERM map,
ErlNifMapIterator *iter,
ErlNifMapIteratorEntry entry);
透過初始化 iter
指向的結構,為 map map
建立一個迭代器。參數 entry
決定迭代器的起始位置:ERL_NIF_MAP_ITERATOR_FIRST
或 ERL_NIF_MAP_ITERATOR_LAST
。
成功時返回 true
,如果 map
不是 map,則返回 false。
map 迭代器僅在 map
所屬的環境 env
的生命週期內有效。迭代器必須透過呼叫 enif_map_iterator_destroy
來銷毀。
ERL_NIF_TERM key, value;
ErlNifMapIterator iter;
enif_map_iterator_create(env, my_map, &iter, ERL_NIF_MAP_ITERATOR_FIRST);
while (enif_map_iterator_get_pair(env, &iter, &key, &value)) {
do_something(key,value);
enif_map_iterator_next(env, &iter);
}
enif_map_iterator_destroy(env, &iter);
注意
map 的鍵值對沒有定義的迭代順序。唯一的保證是,單個 map 實例的迭代順序在該 map 所屬的環境的生命週期內會被保留。
自 OTP 18.0 起可用
enif_map_iterator_destroy()
void enif_map_iterator_destroy(
ErlNifEnv *env,
ErlNifMapIterator *iter);
銷毀由 enif_map_iterator_create
建立的 map 迭代器。
自 OTP 18.0 起可用
enif_map_iterator_get_pair()
int enif_map_iterator_get_pair(
ErlNifEnv *env,
ErlNifMapIterator *iter,
ERL_NIF_TERM *key,
ERL_NIF_TERM *value);
取得目前 map 迭代器位置的鍵和值項。
成功時,設定 *key
和 *value
並返回 true
。如果迭代器位於頭部(第一個項目之前)或尾部(最後一個項目之後),則返回 false
。
自 OTP 18.0 起可用
enif_map_iterator_is_head()
int enif_map_iterator_is_head(
ErlNifEnv *env,
ErlNifMapIterator *iter);
如果 map 迭代器 iter
位於第一個項目之前,則返回 true
。
自 OTP 18.0 起可用
enif_map_iterator_is_tail()
int enif_map_iterator_is_tail(
ErlNifEnv *env,
ErlNifMapIterator *iter);
如果 map 迭代器 iter
位於最後一個項目之後,則返回 true
。
自 OTP 18.0 起可用
enif_map_iterator_next()
int enif_map_iterator_next(
ErlNifEnv *env,
ErlNifMapIterator *iter);
遞增 map 迭代器以指向下一個鍵值項目。
如果迭代器現在位於有效的鍵值項目,則返回 true
,如果迭代器位於尾部(最後一個項目之後),則返回 false
。
自 OTP 18.0 起可用
enif_map_iterator_prev()
int enif_map_iterator_prev(
ErlNifEnv *env,
ErlNifMapIterator *iter);
遞減 map 迭代器以指向前一個鍵值項目。
如果迭代器現在位於有效的鍵值項目,則返回 true
,如果迭代器位於頭部(第一個項目之前),則返回 false
。
自 OTP 18.0 起可用
enif_monitor_process()
int enif_monitor_process(
ErlNifEnv* caller_env,
void* obj,
const ErlNifPid* target_pid,
ErlNifMonitor* mon);
從資源開始監視一個程序。當一個程序被監視時,程序退出會導致呼叫與資源類型相關聯的提供的 down
回呼。
參數 obj
是指向資源的指標,用於持有監視器,而 *target_pid
識別要監視的本地程序。
如果 mon
不是 NULL
,則成功呼叫會將監視器的識別碼儲存在 ErlNifMonitor
結構中,該結構由 mon
指向。此識別碼用於在之後透過 enif_demonitor_process
移除監視器或與 enif_compare_monitors
比較。當觸發監視器或解除配置資源時,監視器會自動移除。
參數 caller_env
是呼叫執行緒的環境(程序綁定或回呼環境),如果從不是由 ERTS 產生的自訂執行緒呼叫,則為 NULL
。
成功時返回 0
,如果沒有提供 down
回呼,則返回 < 0,如果程序不再活動或 target_pid
是未定義,則返回 > 0。
此函式是執行緒安全的。
自 OTP 20.0 起可用
enif_monotonic_time()
ErlNifTime enif_monotonic_time(
ErlNifTimeUnit time_unit);
返回目前的 Erlang 單調時間。請注意,負值並不罕見。
time_unit
是傳回值的時間單位。
如果使用無效的時間單位參數呼叫,或從不是排程器執行緒的執行緒呼叫,則返回 ERL_NIF_TIME_ERROR
。
另請參閱 ErlNifTime
和 ErlNifTimeUnit
。
自 OTP 18.3 起可用
enif_mutex_create()
ErlNifMutex * enif_mutex_create(
char *name);
與 erl_drv_mutex_create
相同。
自 OTP R13B04 起可用
enif_mutex_destroy()
void enif_mutex_destroy(
ErlNifMutex *mtx);
與 erl_drv_mutex_destroy
相同。
自 OTP R13B04 起可用
enif_mutex_lock()
void enif_mutex_lock(
ErlNifMutex *mtx);
與 erl_drv_mutex_lock
相同。
自 OTP R13B04 起可用
enif_mutex_name()
char* enif_mutex_name(
ErlNifMutex* mtx);
與 erl_drv_mutex_name
相同。
自 OTP 21.0 起可用
enif_mutex_trylock()
int enif_mutex_trylock(
ErlNifMutex *mtx);
與 erl_drv_mutex_trylock
相同。
自 OTP R13B04 起可用
enif_mutex_unlock()
void enif_mutex_unlock(
ErlNifMutex *mtx);
與 erl_drv_mutex_unlock
相同。
自 OTP R13B04 起可用
enif_now_time()
ERL_NIF_TERM enif_now_time(
ErlNifEnv *env);
返回 erlang:now()
時間戳記。
此函數已過時。
自 OTP 19.0 起可用
enif_open_resource_type()
ErlNifResourceType * enif_open_resource_type(
ErlNifEnv* env,
const char* module_str,
const char* name,
ErlNifResourceDtor* dtor,
ErlNifResourceFlags flags,
ErlNifResourceFlags* tried);
建立或接管由字串 name
識別的資源類型,並將它賦予由 dtor
指向的解構函數。參數 flags
可以有以下值
ERL_NIF_RT_CREATE
- 建立一個不存在的新資源類型。ERL_NIF_RT_TAKEOVER
- 開啟現有的資源類型並接管其所有實例的所有權。提供的解構子dtor
會針對現有的實例以及呼叫 NIF 庫尚未建立的新實例呼叫。
兩個旗標值可以使用位元 OR 運算結合。資源類型名稱在呼叫模組的本機範圍內。參數 module_str
(尚未) 使用,且必須為 NULL
。如果不需要解構子,dtor
可以是 NULL
。
成功時,此函數會返回指向資源類型的指標,且 *tried
會設定為 ERL_NIF_RT_CREATE
或 ERL_NIF_RT_TAKEOVER
以表示已完成的操作。失敗時,會返回 NULL
,並將 *tried
設定為 flags
。允許將 tried
設定為 NULL
。
請注意,enif_open_resource_type
僅允許在兩個回呼 load
和 upgrade
中呼叫。只有在呼叫的 load
/upgrade
函數成功返回時,才會建立或接管資源類型。
另請參閱 enif_open_resource_type_x
。
自 OTP R13B04 起可用
enif_open_resource_type_x()
ErlNifResourceType * enif_open_resource_type_x(
ErlNifEnv* env,
const char* name,
const ErlNifResourceTypeInit* init,
ErlNifResourceFlags flags,
ErlNifResourceFlags* tried);
與 enif_open_resource_type
相同,只是它接受用於與 enif_select
和 enif_monitor_process
一起使用的資源類型的其他回呼函數。
參數 init
是指向 ErlNifResourceTypeInit
結構的指標,該結構包含資源類型的解構子、向下和停止回呼的函數指標。
注意
只有
ErlNifResourceTypeInit
中的成員dtor
、down
和stop
會被enif_open_resource_type_x
讀取。若要實作新的dyncall
回呼,請使用enif_init_resource_type
。
自 OTP 20.0 起可用
enif_init_resource_type()
ErlNifResourceType * enif_init_resource_type(
ErlNifEnv* env,
const char* name,
const ErlNifResourceTypeInit* init,
ErlNifResourceFlags flags,
ErlNifResourceFlags* tried);
與 enif_open_resource_type_x
相同,只是它接受用於與 enif_dynamic_resource_call
一起使用的資源類型的其他回呼函數。
參數 init
是指向 ErlNifResourceTypeInit
結構的指標,該結構包含回呼函數指標 dtor
、down
、stop
和新的 dyncall
。結構也包含欄位 members
,必須將其設定為從結構頂部計算的已初始化回呼數目。例如,若要初始化包括 dyncall
的所有回呼,members
應設定為 4。所有回呼都是選用的,可以設定為 NULL
。
自 OTP 24.0 起可用
enif_port_command()
int enif_port_command(
ErlNifEnv* env, const
ErlNifPort* to_port,
ErlNifEnv *msg_env,
ERL_NIF_TERM msg);
與 erlang:port_command/2
的運作方式相同,只是它始終完全非同步。
env
- 呼叫程序的環境。不得為NULL
。*to_port
- 接收埠的埠 ID。埠 ID 是指本機節點上的埠。msg_env
- 訊息項的環境。可以是使用enif_alloc_env
或NULL
配置的程序獨立環境。msg
- 要傳送的訊息項。與erlang:port_command/2
的有效負載相同限制適用。
使用 NULL
的 msg_env
是一種最佳化,它將呼叫 enif_alloc_env
、enif_make_copy
、enif_port_command
和 enif_free_env
分組為一個呼叫。當大多數項要從 env
複製到 msg_env
時,此最佳化才有用。
如果成功傳送命令,則返回 true
。如果命令失敗,則返回 false
,例如
*to_port
並未指涉本機埠。- 目前執行的程序 (即,傳送者) 未處於活動狀態。
msg
無效。
另請參閱 enif_get_local_port
。
自 OTP 19.0 起可用
enif_priv_data()
void * enif_priv_data(
ErlNifEnv* env);
自 OTP R13B04 起可用
enif_raise_exception()
ERL_NIF_TERM enif_raise_exception(
ErlNifEnv* env,
ERL_NIF_TERM reason);
建立一個錯誤例外,使用術語 reason
,並從 NIF 返回,並將其與環境 env
關聯。一旦 NIF 或其呼叫的任何函式調用 enif_raise_exception
,運行時會確保當 NIF 返回時,即使 NIF 嘗試返回非例外術語,也會引發它建立的例外。
enif_raise_exception
的返回值只能用作調用它的 NIF(直接或間接)的返回值,或者傳遞給 enif_is_exception
,但不能傳遞給任何其他 NIF API 函式。
另請參閱 enif_has_pending_exception
和 enif_make_badarg
。
自 OTP 18.0 起可用
enif_realloc()
void * enif_realloc(
void* ptr,
size_t size);
將 enif_alloc
分配的記憶體重新分配為 size
位元組。
如果重新分配失敗,則返回 NULL
。
回傳的指標會適當地對齊,以符合配置記憶體中的任何內建型別。
自 OTP 20.2 起可用
enif_realloc_binary()
int enif_realloc_binary(
ErlNifBinary* bin,
size_t size);
更改二進制 bin
的大小。源二進制可以是唯讀的,在這種情況下,它保持不變,並分配一個可變副本並將其賦值給 *bin
。
成功時返回 true
,如果記憶體分配失敗,則返回 false
。
自 OTP R13B04 起可用
enif_release_binary()
void enif_release_binary(
ErlNifBinary* bin);
釋放從 enif_alloc_binary
取得的二進制。
enif_release_resource()
void enif_release_resource(
void* obj);
移除對從 enif_alloc_resource
取得的資源物件 obj
的引用。當最後一個引用被移除時,資源物件會被銷毀。每次調用 enif_release_resource
都必須對應於先前對 enif_alloc_resource
或 enif_keep_resource
的調用。由 enif_make_resource
建立的引用只能由垃圾收集器移除。
無法保證何時會調用未引用資源的解構器。它可以直接由 enif_release_resource
調用,但也可能會被安排在稍後時間調用,可能由另一個執行緒調用。
自 OTP R13B04 起可用
enif_rwlock_create()
ErlNifRWLock * enif_rwlock_create(
char *name);
與 erl_drv_rwlock_create
相同。
自 OTP R13B04 起可用
enif_rwlock_destroy()
void enif_rwlock_destroy(
ErlNifRWLock *rwlck);
與 erl_drv_rwlock_destroy
相同。
自 OTP R13B04 起可用
enif_rwlock_name()
char* enif_rwlock_name(
ErlNifRWLock* rwlck);
與 erl_drv_rwlock_name
相同。
自 OTP 21.0 起可用
enif_rwlock_rlock()
void enif_rwlock_rlock(
ErlNifRWLock *rwlck);
與 erl_drv_rwlock_rlock
相同。
自 OTP R13B04 起可用
enif_rwlock_runlock()
void enif_rwlock_runlock(
ErlNifRWLock *rwlck);
與 erl_drv_rwlock_runlock
相同。
自 OTP R13B04 起可用
enif_rwlock_rwlock()
void enif_rwlock_rwlock(
ErlNifRWLock *rwlck);
與 erl_drv_rwlock_rwlock
相同。
自 OTP R13B04 起可用
enif_rwlock_rwunlock()
void enif_rwlock_rwunlock(
ErlNifRWLock *rwlck);
與 erl_drv_rwlock_rwunlock
相同。
自 OTP R13B04 起可用
enif_rwlock_tryrlock()
int enif_rwlock_tryrlock(
ErlNifRWLock *rwlck);
與 erl_drv_rwlock_tryrlock
相同。
自 OTP R13B04 起可用
enif_rwlock_tryrwlock()
int enif_rwlock_tryrwlock(
ErlNifRWLock *rwlck);
與 erl_drv_rwlock_tryrwlock
相同。
自 OTP R13B04 起可用
enif_schedule_nif()
ERL_NIF_TERM enif_schedule_nif(
ErlNifEnv* caller_env,
const char* fun_name,
int flags,
ERL_NIF_TERM (*fp)(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]),
int argc,
const ERL_NIF_TERM argv[]);
排程 NIF fp
執行。此函式允許應用程式將長時間運行的工作分解為多個常規 NIF 調用,或排程 dirty NIF 在 dirty 排程器執行緒上執行。
caller_env
- 必須是呼叫 NIF 的程序綁定環境。fun_name
- 為排程執行的 NIF 提供一個名稱。如果無法轉換為原子,enif_schedule_nif
會返回badarg
例外。flags
- 對於常規 NIF,必須設定為0
。如果模擬器在啟用 dirty 排程器支援的情況下建置,則如果預計作業是 CPU 密集型,flags
可以設定為ERL_NIF_DIRTY_JOB_CPU_BOUND
,對於將是 I/O 密集型的作業,則設定為ERL_NIF_DIRTY_JOB_IO_BOUND
。如果模擬器中沒有 dirty 排程器執行緒可用,嘗試排程這樣的作業會導致notsup
例外。argc
和argv
- 可以是傳遞給呼叫 NIF 的原始值,也可以是呼叫 NIF 建立的值。
呼叫 NIF 必須使用 enif_schedule_nif
的返回值作為其自身的返回值。
請注意,enif_schedule_nif
,顧名思義,僅排程 NIF 以供將來執行。呼叫 NIF 不會阻塞等待排程的 NIF 執行並返回。這表示呼叫 NIF 無法預期收到排程的 NIF 返回值並將其用於進一步的操作。
自 OTP 17.3 起可用
enif_select()
int enif_select(
ErlNifEnv* env,
ErlNifEvent event,
enum ErlNifSelectFlags mode,
void* obj,
const ErlNifPid* pid,
ERL_NIF_TERM ref);
當特定於作業系統的事件物件準備好進行讀取或寫入操作時,可以使用此函式接收非同步通知。
參數 event
識別事件物件。在 Unix 系統上,使用函式 select
/poll
。事件物件必須是 select
/poll
可以使用的 socket、pipe 或其他檔案描述符物件。
參數 mode
描述要等待的事件類型。它可以是 ERL_NIF_SELECT_READ
、ERL_NIF_SELECT_WRITE
或一個按位 OR 組合以等待兩者。它也可以是 ERL_NIF_SELECT_STOP
或 ERL_NIF_SELECT_CANCEL
,如下所述。當觸發讀取或寫入事件時,會將如下的通知訊息傳送到由 pid
識別的程序
{select, Obj, Ref, ready_input | ready_output}
ready_input
或 ready_output
表示事件物件是否已準備好進行讀取或寫入。
注意
為了完全控制訊息格式,請使用在 erts-11.0 (OTP-22.0) 中引入的較新函式
enif_select_read
或enif_select_write
。
參數 pid
可以是 NULL
,表示呼叫程序。它不能設定為 未定義。
參數 obj
是從 enif_alloc_resource
取得的資源物件。資源物件的目的是作為事件物件的容器,以管理其狀態和生命週期。資源的句柄在通知訊息中作為 Obj
接收。
參數 ref
必須是從 erlang:make_ref/0
取得的引用,或者原子 undefined
。它將在通知中作為 Ref
傳遞。如果使用選擇性的 receive
語句來等待通知,則在 receive
之前建立的引用將利用運行時最佳化,繞過佇列中所有先前接收到的訊息。
通知僅為單次。若要接收相同類型(讀取或寫入)的進一步通知,在收到每個通知後,必須重複調用 enif_select
。
ERL_NIF_SELECT_CANCEL
可用於取消先前選擇的事件。它必須與 ERL_NIF_SELECT_READ
和/或 ERL_NIF_SELECT_WRITE
按位 OR 組合使用,以指示要取消的事件類型。當指定 ERL_NIF_SELECT_CANCEL
時,會忽略參數 pid
和 ref
。返回值會告知事件是否確實已取消,或者是否可能已傳送通知。
為了安全地關閉已傳遞給 enif_select
的事件物件,請使用 ERL_NIF_SELECT_STOP
作為 mode
。當可以安全關閉事件物件時,將會調用資源 obj
的 stop
回調。即使已收到(或取消)所有通知且未進一步調用 enif_select
,也必須使用這種安全關閉事件物件的方式。ERL_NIF_SELECT_STOP
將在調用或排程 stop
回調之前,先取消所有選定的事件。當指定 ERL_NIF_SELECT_STOP
時,會忽略參數 pid
和 ref
。
對於特定的作業系統 event
,第一次調用 enif_select
將在事件物件和包含資源之間建立關係。對於 event
的所有後續調用,都必須將其包含的資源作為參數 obj
傳遞。當使用 mode
作為 ERL_NIF_SELECT_STOP
調用 enif_select
並且已返回對應的 stop
回調時,關係將會解除。一個資源可以包含多個事件物件,但一個事件物件只能包含在一個資源中。在所有包含的關係解除之前,資源將不會被銷毀。
注意
使用
enif_monitor_process
搭配enif_select
來偵測失敗的 Erlang 程序,並防止它們導致資源及其包含的作業系統事件物件永久洩漏。
成功時會返回一個非負值,其中可以設置以下位元:
ERL_NIF_SELECT_STOP_CALLED
- 停止回呼是由enif_select
直接呼叫。ERL_NIF_SELECT_STOP_SCHEDULED
- 停止回呼已排程在其他執行緒上執行,或稍後由此執行緒執行。ERL_NIF_SELECT_READ_CANCELLED
- 讀取事件已由ERL_NIF_SELECT_CANCEL
或ERL_NIF_SELECT_STOP
取消,並保證不會產生ready_input
通知訊息。ERL_NIF_SELECT_WRITE_CANCELLED
- 寫入事件已由ERL_NIF_SELECT_CANCEL
或ERL_NIF_SELECT_STOP
取消,並保證不會產生ready_output
通知訊息。
如果呼叫失敗,則返回一個負值,其中可以設置以下位元:
ERL_NIF_SELECT_INVALID_EVENT
- 參數event
不是有效的作業系統事件物件。ERL_NIF_SELECT_FAILED
- 系統呼叫未能將事件物件加入輪詢集合。
注意
使用位元 AND 運算來測試回傳值中的特定位元。未來版本可能會加入新的有效位元,以提供關於成功和失敗呼叫更詳細的資訊。請勿使用像
==
這樣的相等性測試,因為這可能會導致您的應用程式停止運作。範例
retval = enif_select(env, fd, ERL_NIF_SELECT_STOP, resource, ref); if (retval < 0) { /* handle error */ } /* Success! */ if (retval & ERL_NIF_SELECT_STOP_CALLED) { /* ... */ }
注意
模式標誌
ERL_NIF_SELECT_CANCEL
以及回傳標誌ERL_NIF_SELECT_READ_CANCELLED
和ERL_NIF_SELECT_WRITE_CANCELLED
是在 erts-11.0 (OTP-22.0) 中引入的。
自 OTP 20.0 起可用
enif_select_read()
自 OTP 22.0 起可用
enif_select_write()
int enif_select_read(
ErlNifEnv* env,
ErlNifEvent event,
void* obj,
const ErlNifPid* pid,
ERL_NIF_TERM msg,
ErlNifEnv* msg_env);
int enif_select_write(
ErlNifEnv* env,
ErlNifEvent event,
void* obj,
const ErlNifPid* pid,
ERL_NIF_TERM msg,
ErlNifEnv* msg_env);
這些是 enif_select 的變體,您可以提供自己的訊息項 msg
,該訊息將會傳送至程序,而不是預定義的元組 {select,_,_,_}.
參數 msg_env
必須是 NULL
或使用 enif_alloc_env
配置的 msg
環境。如果參數 msg_env
為 NULL
,則會複製項 msg
,否則,對 enif_select_read
或 enif_select_write
的成功呼叫將會使 msg
和 msg_env
皆失效。然後,環境必須使用 enif_free_env
釋放,或使用 enif_clear_env
清除以供重複使用。不成功的呼叫會使 msg
和 msg_env
保持有效。
除了訊息格式外,enif_select_read
和 enif_select_write
的行為與 enif_select 完全相同,其中參數 mode
為 ERL_NIF_SELECT_READ
或 ERL_NIF_SELECT_WRITE
。要取消或關閉事件,請使用 enif_select。
自 OTP 22.0 起可用
enif_self()
ErlNifPid * enif_self(
ErlNifEnv* caller_env,
ErlNifPid* pid);
初始化 *pid
處的 ErlNifPid
變數,以表示呼叫的程序。
如果成功,則返回 pid
;如果 caller_env
不是程序綁定環境,則返回 NULL。
自 OTP R14B 起可用
enif_send()
int enif_send(
ErlNifEnv* caller_env,
ErlNifPid* to_pid,
ErlNifEnv* msg_env,
ERL_NIF_TERM msg);
傳送訊息到程序。
caller_env
- 呼叫執行緒的環境(程序綁定或 回呼環境),如果從非由 ERTS 產生的自訂執行緒呼叫,則為NULL
。*to_pid
- 接收程序的 pid。該 pid 必須指向本機節點上的程序。msg_env
- 訊息項的環境。必須是使用enif_alloc_env
配置的程序獨立環境,或為 NULL。msg
- 要傳送的訊息項。
如果訊息成功傳送,則返回 true
。如果傳送操作失敗,則返回 false
,也就是說:
*to_pid
沒有指向一個存活的本機程序。- 目前執行的程序 (即,傳送者) 未處於活動狀態。
對 enif_send
的成功呼叫會使訊息環境 msg_env
及其所有項(包括 msg
)失效。環境必須使用 enif_free_env
釋放,或使用 enif_clear_env
清除以供重複使用。不成功的呼叫會使 msg
和 msg_env
保持有效。
如果 msg_env
設定為 NULL
,則會複製 msg
項,並且原始項及其環境在呼叫後仍然有效。
此函式是執行緒安全的。
注意
僅從 ERTS 8.0 (Erlang/OTP 19) 開始支援將
msg_env
作為NULL
傳遞。
自 OTP R14B 起可用
enif_set_option()
int enif_set_option(
ErlNifEnv *env,
ErlNifOption opt,
...);
設定選項。成功時,將返回零。失敗時,將返回非零值。目前可以設定以下選項:
enif_set_option(env, ERL_NIF_OPT_DELAY_HALT)
啟用延遲運行時系統暫停,並啟用刷新,直到 NIF 程式庫中的所有 NIF 呼叫都已返回。如果尚未啟用*延遲暫停*功能,即使程序仍在 NIF 程式庫的 NIF 中執行,啟用刷新的暫停也可能會完成。請注意,這裡的*返回*是指 NIF 將控制權返回運行時系統的第一個點,而不是 NIF 呼叫返回到呼叫 NIF 的 Erlang 代碼的點。也就是說,如果您在系統暫停時,使用
enif_schedule_nif()
從 NIF 中排程 NIF 的執行,即使已為 NIF 程式庫啟用*延遲暫停*,排程的 NIF 呼叫也不會執行。當呼叫其中一個
erlang:halt()
BIF 時,運行時系統會暫停。預設情況下,會啟用刷新,但可以使用erlang:halt/2
BIF 停用刷新。停用刷新後,*延遲暫停*設定將無效。也就是說,即使已啟用*延遲暫停*設定,運行時系統也會在不等待 NIF 返回的情況下暫停。有關更多資訊,請參閱erlang:halt/2
的{flush, boolean()}
選項。只能在 NIF 程式庫的
load()
或upgrade()
呼叫中,在載入 NIF 程式庫期間,呼叫enif_set_option()
來設定ERL_NIF_OPT_DELAY_HALT
選項,如果在其他地方設定將會失敗。env
參數 *必須* 是傳遞到load()
或upgrade()
呼叫的回呼環境。此選項也只能設定一次。也就是說,一旦啟用*延遲暫停*設定,就無法變更。*延遲暫停*設定與載入 NIF 程式庫的模組實例相關聯。也就是說,如果載入使用 NIF 程式庫的模組的新版本和舊版本,它們可以具有相同或不同的*延遲暫停*設定。延遲暫停功能可以與 on halt 回呼結合使用。在這種情況下,on halt 回呼通常用於通知程式庫中被封鎖在 NIF 中的程序,表示該返回以讓運行時系統完成暫停。這些 NIF 應該是髒 NIF,因為普通 NIF 永遠不應該長時間封鎖。
enif_set_option(env, ERL_NIF_OPT_ON_HALT, on_halt)
安裝一個回呼,當運行時系統在啟用刷新的情況下暫停時將會呼叫該回呼。
當呼叫其中一個
erlang:halt()
BIF 時,運行時系統會暫停。預設情況下,會啟用刷新,但可以使用erlang:halt/2
BIF 停用刷新。停用刷新後,即使已安裝任何 on halt 回呼,運行時系統也會在不呼叫任何此類回呼的情況下暫停。有關更多資訊,請參閱erlang:halt/2
的{flush, boolean()}
選項。只能在 NIF 程式庫的
load()
或upgrade()
呼叫中,在載入 NIF 程式庫期間,呼叫enif_set_option()
來設定ERL_NIF_OPT_ON_HALT
選項,如果在其他地方呼叫將會失敗。env
參數 *必須* 是傳遞到load()
或upgrade()
呼叫的回呼環境。on_halt
參數應該是指向要安裝的回呼的函式指標。on_halt
回呼將與載入 NIF 程式庫的模組實例相關聯。也就是說,如果載入使用 NIF 程式庫的模組的新版本和舊版本,它們都可以安裝不同的、無或相同的 on halt 回呼。在 程式碼清除期間卸載 NIF 程式庫時,已安裝的 on halt 回呼將會被卸載。只能設定一次ERL_NIF_OPT_ON_HALT
選項。也就是說,一旦安裝了 on halt 回呼,除了清除載入 NIF 程式庫的模組實例外,無法透過任何其他方式變更或移除該回呼。當安裝的 on halt 回呼函式被呼叫時,它會被傳遞一個指向
priv_data
的指標作為參數。這個priv_data
指標可以在載入 NIF 函式庫時設定。on halt 回呼函式可以與延遲停止結合使用,直到所有對函式庫的呼叫都已返回。在這種情況下,on halt 回呼函式通常用於通知在函式庫的 NIF 中被阻塞的程序,是時候返回以讓執行期系統完成停止。這些 NIF 應該是 dirty NIF,因為普通的 NIF 不應長時間阻塞。
enif_set_option(env, ERL_NIF_OPT_ON_UNLOAD_THREAD, on_unload_thread)
安裝一個回呼函式,當 NIF 函式庫所屬的模組實例被清除為舊時,每個排程器執行緒都會呼叫此函式。典型的用途是釋放執行緒特定的資料。
ERL_NIF_OPT_ON_UNLOAD_THREAD
選項只能在呼叫load()
或upgrade()
載入 NIF 函式庫時設定,如果在其他地方呼叫則會失敗。env
參數必須是傳遞給load()
或upgrade()
呼叫的回呼環境。on_unload_thread
參數應該是一個指向要安裝的回呼函式的函式指標。這個 on_unload_thread 回呼函式將與 NIF 函式庫實例載入的模組實例綁定。也就是說,如果載入了使用 NIF 函式庫的新舊版本模組,它們都可以安裝不同、無或相同的 on_unload_thread 回呼函式。ERL_NIF_OPT_ON_UNLOAD_THREAD
選項只能設定一次,一旦為模組實例安裝後,就不能更改或移除。當安裝的 on_unload_thread 回呼函式被呼叫時,它會被傳遞一個指向
priv_data
的指標作為參數。這個priv_data
指標可以在載入 NIF 函式庫時設定。對 on_unload_thread 函式的呼叫是由不同的排程器執行緒並行進行的。執行緒之間沒有強制同步。但是,只有在所有對 on_unload_thread 的呼叫都返回後,才會對模組實例進行單一的最終化呼叫
unload()
回呼函式。
自 OTP 26.0 起可用
enif_set_pid_undefined()
void enif_set_pid_undefined(
ErlNifPid* pid);
將 ErlNifPid
變數設定為未定義。請參閱 enif_is_pid_undefined
。
自 OTP 22.0 起可用
enif_sizeof_resource()
unsigned enif_sizeof_resource(
void* obj);
取得透過 enif_alloc_resource
取得的資源物件 obj
的位元組大小。
自 OTP R13B04 起可用
enif_snprintf()
int enif_snprintf(
char *str,
size_t size,
const char *format,
...);
與 snprintf
類似,但此格式字串也接受 "%T"
,它可以格式化 ERL_NIF_TERM
類型的 Erlang 項。
此函式主要用於偵錯目的。不建議使用 %T
列印非常大的項。即使成功,此函式也可能會更改 errno
。
自 OTP 19.0 起可用
enif_system_info()
void enif_system_info(
ErlNifSysInfo *sys_info_ptr,
size_t size);
與 driver_system_info
相同。
自 OTP R13B04 起可用
enif_term_to_binary()
int enif_term_to_binary(
ErlNifEnv *env,
ERL_NIF_TERM term,
ErlNifBinary *bin);
使用 enif_alloc_binary
分配一個新的二進制資料,並根據 Erlang 外部項格式儲存編碼 term
的結果。
成功時返回 true
,如果分配失敗則返回 false
。
另請參閱 erlang:term_to_binary/1
和 enif_binary_to_term
。
自 OTP 19.0 起可用
enif_term_type()
ErlNifTermType enif_term_type(
ErlNifEnv *env,
ERL_NIF_TERM term);
判斷給定項的類型。該項必須是一個普通的 Erlang 項,而不是 enif_raise_exception
、enif_schedule_nif
或類似函式返回的特殊項。
目前定義了以下類型
ERL_NIF_TERM_TYPE_ATOM
ERL_NIF_TERM_TYPE_BITSTRING
- 位元字串或二進制資料ERL_NIF_TERM_TYPE_FLOAT
ERL_NIF_TERM_TYPE_FUN
ERL_NIF_TERM_TYPE_INTEGER
ERL_NIF_TERM_TYPE_LIST
- 列表,無論是否為空ERL_NIF_TERM_TYPE_MAP
ERL_NIF_TERM_TYPE_PID
ERL_NIF_TERM_TYPE_PORT
ERL_NIF_TERM_TYPE_REFERENCE
ERL_NIF_TERM_TYPE_TUPLE
請注意,未來可能會新增新的類型,因此呼叫者必須準備好處理未知的類型。
自 OTP 22.0 起可用
enif_thread_create()
int enif_thread_create(
char *name,
ErlNifTid *tid,
void * (*func)(void *),
void *args,
ErlNifThreadOpts *opts);
與 erl_drv_thread_create
相同。
自 OTP R13B04 起可用
enif_thread_exit()
void enif_thread_exit(
void *resp);
與 erl_drv_thread_exit
相同。
自 OTP R13B04 起可用
enif_thread_join()
int enif_thread_join(
ErlNifTid tid,
void **respp);
與 erl_drv_thread_join
相同。
自 OTP R13B04 起可用
enif_thread_name()
char* enif_thread_name(
ErlNifTid tid);
與 erl_drv_thread_name
相同。
自 OTP 21.0 起可用
enif_thread_opts_create()
ErlNifThreadOpts * enif_thread_opts_create(
char *name);
與 erl_drv_thread_opts_create
相同。
自 OTP R13B04 起可用
enif_thread_opts_destroy()
void enif_thread_opts_destroy(
ErlNifThreadOpts *opts);
與 erl_drv_thread_opts_destroy
相同。
自 OTP R13B04 起可用
enif_thread_self()
ErlNifTid enif_thread_self(void);
與 erl_drv_thread_self
相同。
自 OTP R13B04 起可用
enif_thread_type()
int enif_thread_type(void);
確定目前執行緒的類型。正值表示排程器執行緒,而負值或零表示另一種執行緒類型。目前存在以下特定類型(未來可能會擴展)
ERL_NIF_THR_UNDEFINED
- 未定義的執行緒,不是排程器執行緒。ERL_NIF_THR_NORMAL_SCHEDULER
- 一般排程器執行緒。ERL_NIF_THR_DIRTY_CPU_SCHEDULER
- dirty CPU 排程器執行緒。ERL_NIF_THR_DIRTY_IO_SCHEDULER
- dirty I/O 排程器執行緒。
自 OTP 19.0 起可用
enif_time_offset()
ErlNifTime enif_time_offset(
ErlNifTimeUnit time_unit);
返回 Erlang 單調時間 和 Erlang 系統時間 之間目前的時差,並轉換為作為參數傳遞的 time_unit
。
time_unit
是傳回值的時間單位。
如果使用無效的時間單位參數呼叫,或從非排程器執行緒呼叫,則返回 ERL_NIF_TIME_ERROR
。
另請參閱 ErlNifTime
和 ErlNifTimeUnit
。
自 OTP 18.3 起可用
enif_tsd_get()
void * enif_tsd_get(
ErlNifTSDKey key);
與 erl_drv_tsd_get
相同。
自 OTP R13B04 起可用
enif_tsd_key_create()
int enif_tsd_key_create(
char *name,
ErlNifTSDKey *key);
與 erl_drv_tsd_key_create
相同。
自 OTP R13B04 起可用
enif_tsd_key_destroy()
void enif_tsd_key_destroy(
ErlNifTSDKey key);
與 erl_drv_tsd_key_destroy
相同。
自 OTP R13B04 起可用
enif_tsd_set()
void enif_tsd_set(
ErlNifTSDKey key,
void *data);
與 erl_drv_tsd_set
相同。
自 OTP R13B04 起可用
enif_vfprintf()
int enif_vfprintf(
FILE *stream,
const char *format,
va_list ap);
等同於 enif_fprintf
,但它使用 va_list
而不是可變數量的參數呼叫。
自 OTP 21.0 起可用
enif_vsnprintf()
int enif_vsnprintf(
char *str,
size_t size,
const char *format,
va_list ap);
等同於 enif_snprintf
,但它使用 va_list
而不是可變數量的參數呼叫。
自 OTP 21.0 起可用
enif_whereis_pid()
int enif_whereis_pid(
ErlNifEnv *caller_env,
ERL_NIF_TERM name,
ErlNifPid *pid);
透過已註冊的名稱查找程序。
caller_env
- 呼叫執行緒的環境(程序綁定或 回呼環境),如果從非由 ERTS 產生的自訂執行緒呼叫,則為NULL
。name
- 已註冊程序的名稱,以原子形式表示。*pid
- 儲存已解析程序 ID 的ErlNifPid
。
成功時,將 *pid
設定為以 name
註冊的本地程序,並返回 true
。如果 name
不是已註冊的程序,或不是原子,則返回 false
且 *pid
不變。
與 erlang:whereis/1
的運作方式相同,但僅限於程序。請參閱 enif_whereis_port
以解析已註冊的 port。
自 OTP 20.0 起可用
enif_whereis_port()
int enif_whereis_port(
ErlNifEnv *caller_env,
ERL_NIF_TERM name,
ErlNifPort *port);
透過已註冊的名稱查找 port。
caller_env
- 呼叫執行緒的環境(程序綁定或 回呼環境),如果從非由 ERTS 產生的自訂執行緒呼叫,則為NULL
。name
- 已註冊 port 的名稱,以原子形式表示。*port
- 儲存已解析 port ID 的ErlNifPort
。
成功時,將 *port
設定為以 name
註冊的 port,並返回 true
。如果 name
不是已註冊的 port,或不是原子,則返回 false
且 *port
不變。
與 erlang:whereis/1
的運作方式相同,但僅限於 port。請參閱 enif_whereis_pid
以解析已註冊的程序。
自 OTP 20.0 起可用