erlang nif 中文手册
2015-02-05 14:10
267 查看
这是翻译erlang官方文档中的 erts-5.9.2的erl_nif部分。翻译完了。水平有限,我就把这个当作是我自己使用了,以后也会继续完善的。
功能
初始化
数据类型
接口-资源分配类
接口-线程操作类
接口-类型操作类
一个典型的用法是:根实现方法用作抛出异常。有时候当果系统没有实现任何NIF库,它也可以用作一个备份。
下面是一个最小调用NIF库的例子:
c部分:
erlang部分:
在linux上的操作如下:
对于一个真正使用的模块,一个更好的实现办法是利用
注意:NIF库不一定要被exproted的,可以作为erlang模块私有。
同时注意一些没有用的函数会被优化时候处理掉,导致调用时候出错。
一个NIF库被load时候是绑定erlang模块的version。如果erlang模块更新了,新模块要去加载多一次NIF作为自己的(或选择不去加载,这样的话,新的erlang模块并没有NIF)。如果一个NIF被多次load和调用的话,意味着NIF里面的static data同样会被共享。为了避免这样的无心的共享static data,每个erlang模块代码应该要保存自己的私有数据,而在NIF里面,可以通过调用
没有方法去声明unload一个NIF库,当erlang模块被卸载时候,NIF会被自动unload。
读写erlang的terms
所有的erlang terms都可以通过作为函数的参数或者返回值来进行erlang和NIF库的传递。erlang的terms对应的是一个叫
所有
二进制
二进制类型的terms可以通过一个结构体
指针指向的原始数据只有通过调用
还不支持任意bit长度。
资源对象
使用资源对象的一个比较安全的方式是调用NIF借口把指向该数据的指针返回,一个资源对象实际上只是一块通过
所有的资源对象都必须带有资源类型,这样可以使得资源在不同模块时候仍然可以区分出来。当库被加载时候调用
注意一旦
另外一种使用资源对象的方法的是使用定义的内存来创建binary terms,
资源类型支持运行时升级,通过运行允许一个被加载的库去接管已经存在的资源类型,并继承所有已经存在的对象,而且对象的类型都会变成那个接管的资源类型.新的库的析构函数从那以后就可以被继承的对象继承。这样的话,就的析构函数就可以被安全卸载。资源对象和模块被坑下后,必须被删除或者被新的NIF接管。卸载的库一直被阻塞直到所有已存在的资源对象被析构或是被新的NIF接管。
多线程和并发
一个NIF库是线程安全的,只要函数的动作只是单纯地读提供的数据,太是不需要直接声明任何同步锁。但是如果你对一个静态变量或者
这是一个初始化NIF库的宏技巧,它应该赋值给一个静态变量。
int (load)(ErlNifEnv env, void** priv_data, ERL_NIF_TERM load_info) 该方法是当NIF库第一次载入时候到会调用。
当库加载失败时候会返回非0,如果没有指定加载方法就把
int (upgrade)(ErlNifEnv env, void[b] priv_data, void old_priv_data, ERL_NIF_TERM load_info)[/b]
当已经载入旧库的库,而且要更新时候使用。
当更新失败时候返回非0,如果没有指定更新方法就把
void (unload)(ErlNifEnv env, void* priv_data)
当库属于过旧要清理的情况下使用,注意这里并不是替换库操作。
int (reload)(ErlNifEnv env, void** priv_data, ERL_NIF_TERM load_info)
这个方法的实现机制是不可靠的,这只是一个开发者特性。不要使用该方法,实际环境中请把
ErlNifEnv
一个进程绑定的环境,会在所有的NIF函数里面作为第一个参数传递,所有传递给
ErlNifFunc
typedef struct { const char ; unsigned ; ERL_NIF_TERM ()(ErlNifEnv* env, int argc, const RL_NIF_TERM argv[]); } ErlNifFunc;
通过它的名字,参数数量和实现去定义一个NIF,
ErlNifBinary
typedef struct { unsigned ; unsigned char* ; } ErlNifBinary;
注意:
ErlNifPid
ErlNifResourceType
每个
ErlNifResourceDtor
typedef void ErlNifResourceDtor(ErlNifEnv env, void obj);
该函数原型包含一个资源的析构函数,这个资源析构函数不允许调用任何制造term的函数。
ErlNifCharEncoding
typedef enum { ERL_NIF_LATIN1 }ErlNifCharEncoding;
这个字符转义用于string和atoms的转换,当前唯一支持的是
ErlNifSysInfo
用于
ErlNifSInt64
一个原生有符号的64bit长度的整形类型。
ErlNifUInt64
一个原生的无符号64bit长度的整形类型。
分配
void enif_free(void* ptr)
释放通过
ErlNifEnv *enif_alloc_env()
分配一个进程独立了的环境,该环境必须用来存放没有绑定任何进程的terms。可以在稍后再通过
返回一个指向新空间的指针。
void enif_clear_env(ErlNifEnv* env)
清除环境中所有的term,使环境可以复用,注意这个环境必须是通过
void enif_free_env(ErlNifEnv* env)
析构环境,里面的term同样会被释放。
ErlNifResourceType enif_open_resource_type(ErlNifEnv env, const char module_str, const char name, ErlNifResourceDtor dtor,ErlNifResourceFlags flags, ErlNifResourceFlags tried)
通过一个字符串
而
ERL_NIF_RT_CREATE: 创建一个新的资源类型。
ERL_NIF_RT_TAKEOVER: 打开一个已经存在的资源对象,并且接管所有实例,而这个
两个flags值可以通过位操作“与”来组合。资源类型的名字对于调用模块是局部的。
函数调用成功会返回一个指向资源类型的指针,然后
注意:该函数之允许在三个回调函数中调用(
void enif_alloc_resource(ErlNifResourceType type, unsigned size)
分配内存给资源对象,要求传入类型和大小。
void enif_release_resource(void* obj)
释放资源对象。
ERL_NIF_TERM enif_make_resource(ErlNifEnv env, void obj)
对
注意如果在
注意:在erlang编程里面,一个资源term只可以存储或者在同节点的不同进程间发送。其他操作如:匹配或者
unsigned enif_sizeof_resource(void* obj)
取出资源的字节长度。
int enif_keep_resource(void* obj)
对资源添加一个引用。该资源对象必须由
int enif_alloc_binary(size_t size, ErlNifBinary* bin)
分配一个
成功返回
int enif_inspect_binary(ErlNifEnv env, ERL_NIF_TERM bin_term, ErlNifBinary bin)
通过
int enif_inspect_iolist_as_binary(ErlNifEnv env, ERL_NIF_TERM term,ErlNifBinary bin)
(这里我认为是将一个iolist的erlang字符串转换成一个erlang的binary字符串)
成功返回
int enif_realloc_binary(ErlNifBinary* bin, size_t size)
改变
void enif_release_binary(ErlNifBinary* bin)
释放binary。
ERL_NIF_TERM enif_make_binary(ErlNifEnv env, ErlNifBinary bin)
创建一个binary term。拥有权会移交给创建的term。而
unsigned char enif_make_new_binary(ErlNifEnv env, size_t size,ERL_NIF_TERM* termp)
分配
ERL_NIF_TERM enif_make_sub_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term,size_t pos, size_t size)
复制部分binary来创建新的binary。
ERL_NIF_TERM enif_make_resource_binary(ErlNifEnv env, void obj, const void*data, size_t size)
创建一个binary term,该binary term在被析构之前必须保持可读和不可变,可能会包含外部的资源对象,在这种情况下,析构函数里面就应该去释放那些对象。
多个binary terms可能属于同一个资源对象,那么该析构函数不会被马上调用,直到最后一个binary被垃圾回收后。如果要返回一个大binary buffer的不同部分,这是一个好方法,
该函数内,拥有权没有发送改变,该资源仍然需要
void enif_system_info(ErlNifSysInfo *sys_info_ptr, size_t size)
该方法会写运行系统的信息到
该函数创建并初始化一个线程选项结构体。失败返回NULL。
该方法线程安全。
void enif_thread_opts_destroy(ErlNifThreadOpts *opts)
销毁一个线程选项。
该方法线程安全。
int enif_thread_create(char name,ErlNifTid tid,void * (func)(void
),void args,ErlNifThreadOpts opts)
成功返回0,反之一个
该线程会在func执行返回或者调用
该方法线程安全。
void enif_thread_exit(void *resp)
该函数终结线程,退出值是
该方法线程安全。
int enif_thread_join(ErlNifTid, void **respp)
该方法是调用的线程跳入另外线程。例如:调用线程会阻塞,直到
该方法线程安全。
ErlNifTid enif_thread_self(void)
返回调用线程的tid。
该方法线程安全。
int enif_equal_tids(ErlNifTid tid1, ErlNifTid tid2)
对比两个线程标识是否相同,不相同返回0,相同返回非0.
该方法线程安全。
int enif_tsd_key_create(char name, ErlNifTSDKey key)
创建一个线程特别的数据key。(key-value存储。先创建key)。在NIF unload前需要释放。
该方法线程安全。
void enif_tsd_key_destroy(ErlNifTSDKey key)
释放一个key。
该方法线程安全。
void *enif_tsd_get(ErlNifTSDKey key)
返回
该方法线程安全。
void enif_tsd_set(ErlNifTSDKey key, void *data)
声明关联
该方法线程安全。
void enif_cond_create(ErlNifCond *cnd)
通过一个字符串创建一个条件变量,返回一个指向这个变量的指针,时候返回
该方法线程安全。
void enif_cond_destory(ErlNifCond *cnd)
摧毁一个条件变量。该方法线程安全。
void enif_cond_wait(ErlNifCond cnd, ErlNifMutex mtx)
该函数会使线程阻塞知道其他线程唤醒。可以通过条件变量去唤醒单个或者全部线程。在线程阻塞之前它会解锁传递过来的互斥量,当被唤醒时候它会锁住改互斥量。所以在调用该方法前,那个互斥量需要先锁住。
该方法线程安全。
void enif_cond_signal(ErlNifCond *cnd)
该函数通过条件变量去单播。如果其他线程等待这个这个信号,其中一个都会被唤醒。
该方法线程安全。
void enif_cond_broadcast(ErlNifCond *cnd)
该函数通过条件变量去广播。如果其他线程等待这个这个信号,全部都会被唤醒。
该方法线程安全。
ErlNifPid enif_self(ErlNifEnv caller_env, ErlNifPid* pid)
把调用该函数的进程和
该方法线程安全。
int enif_send(ErlNifEnv env, ErlNifPid to_pid, ErlNifEnv* msg_env,ERL_NIF_TERM msg)
发送一个信息给一个进程。
如果成功就返回
如果成功调用后,
该方法只有在开启SMP支持后变得线程安全。在non-SMP模式下,只能由NIF调用的那个线程使用。
ErlNifMutex enif_mutex_create(char name)
通过一个字符串去创建一个互斥量。成功返回指向互斥量的指针。失败返回空,在NIF unload前需要释放它。
该方法线程安全。
void enif_mutex_destroy(ErlNifMutex *mtx)
释放一个互斥量。
该方法线程安全。
void enif_mutex_lock(ErlNifMutex *mtx)
锁住一个互斥量。调用线程会阻塞,直到锁住,如果一个线程当前已经锁住,不会再次加锁。
该方法线程安全。
int enif_mutex_trylock(ErlNifMutex *mtx)
该函数尝试锁住一个互斥量,成功返回0,反之返回
该方法线程安全。
void enif_mutex_unlock(ErlNifMutex *mtx)
解锁互斥量。
该方法线程安全。
读写锁操作
ErlNifRWLock enif_rwlock_create(char name)
void enif_rwlock_destroy(ErlNifRWLock rwlck)
void enif_rwlock_rlock(ErlNifRWLock rwlck)
void enif_rwlock_runlock(ErlNifRWLock rwlck)
void enif_rwlock_rwlock(ErlNifRWLock rwlck)
void enif_rwlock_rwunlock(ErlNifRWLock rwlck)
int enif_rwlock_tryrlock(ErlNifRWLock rwlck)
int enif_rwlock_tryrwlock(ErlNifRWLock *rwlck)
返回一个大于,等于,小于0整形数字来表示lhs 大于,等于,小于rhs。分别相当于erlang的运算符 ==,/=,=<,<,>,>=,> (但不包括 =:= 和 =/=)。
ERL_NIF_TERM enif_make_copy(ErlNifEnv* dst_env, ERL_NIF_TERM src_term)
在
int enif_get_atom(ErlNifEnv env, ERL_NIF_TERM term, char buf, unsigned size, ErlNifCharEncoding encode)
在
取term中的值,并赋值到一个参数中(看参数里面哪个同类型的,就是赋值给它的了),成功返回ture,失败返回false
int enif_get_atom_length(ErlNifEnv env, ERL_NIF_TERM term, unsigned len,ErlNifCharEncoding encode)
int enif_get_double(ErlNifEnv env, ERL_NIF_TERM term, double dp)
int enif_get_int(ErlNifEnv env, ERL_NIF_TERM term, int ip)
int enif_get_int64(ErlNifEnv env, ERL_NIF_TERM term, ErlNifSInt64 ip)
int enif_get_local_pid(ErlNifEnv env, ERL_NIF_TERM term, ErlNifPid pid)
int enif_get_list_cell(ErlNifEnv env, ERL_NIF_TERM list, ERL_NIF_TERM head,ERL_NIF_TERM tail)
int enif_get_list_length(ErlNifEnv env, ERL_NIF_TERM term, unsigned len)
int enif_get_long(ErlNifEnv env, ERL_NIF_TERM term, long int ip)
int enif_get_resource(ErlNifEnv env, ERL_NIF_TERM term, ErlNifResourceType type, void** objp)
int enif_get_string(ErlNifEnv env, ERL_NIF_TERM list, char buf, unsigned size, ErlNifCharEncoding encode)
int enif_get_tuple(ErlNifEnv env, ERL_NIF_TERM term, int arity, const ERL_NIF_TERM** array)
int enif_get_uint(ErlNifEnv env, ERL_NIF_TERM term, unsigned int ip)
int enif_get_uint64(ErlNifEnv env, ERL_NIF_TERM term, ErlNifUInt64 ip)
int enif_get_ulong(ErlNifEnv env, ERL_NIF_TERM term, unsigned long* ip)
void enif_priv_data(ErlNifEnv env)
返回之前在load,reload或者upgrade设置的私有数据的指针。
类型判断,如果是该类型就返回true
int enif_is_atom(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_binary(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_empty_list(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_exception(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_number(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_fun(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_identical(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)
int enif_is_pid(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_port(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_ref(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_tuple(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_list(ErlNifEnv* env, ERL_NIF_TERM term)
创建一个term,第一个参数是环境,后面参数是term的值的来源和条件
ERL_NIF_TERM enif_make_atom(ErlNifEnv env, const char name)
ERL_NIF_TERM enif_make_atom_len(ErlNifEnv env, const char name, size_t len)
ERL_NIF_TERM enif_make_badarg(ErlNifEnv env)
ERL_NIF_TERM enif_make_double(ErlNifEnv env, double d)
int enif_make_existing_atom(ErlNifEnv env, const char name, ERL_NIF_TERM atom, ErlNifCharEncoding encode)
int enif_make_existing_atom_len(ErlNifEnv env, const char name, size_t len,ERL_NIF_TERM atom, ErlNifCharEncoding encoding)
ERL_NIF_TERM enif_make_int(ErlNifEnv env, int i)
ERL_NIF_TERM enif_make_int64(ErlNifEnv env, ErlNifSInt64 i)
ERL_NIF_TERM enif_make_list(ErlNifEnv env, unsigned cnt, ...)
ERL_NIF_TERM enif_make_list_cell(ErlNifEnv env, ERL_NIF_TERM head,ERL_NIF_TERM tail)
ERL_NIF_TERM enif_make_list_from_array(ErlNifEnv env, const ERL_NIF_TERM arr[], unsigned cnt)
int enif_make_reverse_list(ErlNifEnv env, ERL_NIF_TERM term, ERL_NIF_TERM
list)
ERL_NIF_TERM enif_make_long(ErlNifEnv env, long int i)
ERL_NIF_TERM enif_make_pid(ErlNifEnv env, const ErlNifPid pid)
ERL_NIF_TERM enif_make_ref(ErlNifEnv* env)
ERL_NIF_TERM enif_make_string(ErlNifEnv env, const char string,ErlNifCharEncoding encoding)
ERL_NIF_TERM enif_make_string_len(ErlNifEnv env, const char string, size_t len, ErlNifCharEncoding encoding)
ERL_NIF_TERM enif_make_tuple(ErlNifEnv env, unsigned cnt, ...)
ERL_NIF_TERM enif_make_tuple_from_array(ErlNifEnv env, const ERL_NIF_TERM arr[], unsigned cnt)
ERL_NIF_TERM enif_make_uint(ErlNifEnv env, unsigned int i)
ERL_NIF_TERM enif_make_uint64(ErlNifEnv env, ErlNifUInt64 i)
ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i)
by dp
--EOF
← Previous
Archive
Next →
© puzzleyes 2014 with help from
Jekyll Bootstrap and
The Hooligan Theme
erlang nif 中文手册
概括功能
初始化
数据类型
接口-资源分配类
接口-线程操作类
接口-类型操作类
概括
NIF库包含了erlang模块的一些方法的原生实现。这些NIF方法的调用方式跟其他普通方法的调用一样,但是每个NIF函数都要用erlang对应的实现,如果NIF库成功载入,在调用NIF函数之前,会先调用对应的erlang实现的函数。一个典型的用法是:根实现方法用作抛出异常。有时候当果系统没有实现任何NIF库,它也可以用作一个备份。
下面是一个最小调用NIF库的例子:
c部分:
[code]/* 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部分:
[code]-module(niftest). -export([init/0, hello/0]). init() -> erlang:load_nif("./niftest", 0). hello() -> "NIF library not loaded".
在linux上的操作如下:
[code]$> gcc -fPIC -shared -o niftest.so niftest.c -I $ERL_ROOT/usr/include/ $> erl 1> c(niftest). {ok,niftest} 2> niftest:hello(). "NIF library not loaded" 3> niftest:init(). ok 4> niftest:hello(). "Hello world!"
对于一个真正使用的模块,一个更好的实现办法是利用
on_load> >
注:这里的on_load是erlang的一个描述符,跟-export一样,通常用法是: -on_load(init/0),在erlang模块被load的时候,会调用指定方法把c模块也load进。
注意:NIF库不一定要被exproted的,可以作为erlang模块私有。
同时注意一些没有用的函数会被优化时候处理掉,导致调用时候出错。
一个NIF库被load时候是绑定erlang模块的version。如果erlang模块更新了,新模块要去加载多一次NIF作为自己的(或选择不去加载,这样的话,新的erlang模块并没有NIF)。如果一个NIF被多次load和调用的话,意味着NIF里面的static data同样会被共享。为了避免这样的无心的共享static data,每个erlang模块代码应该要保存自己的私有数据,而在NIF里面,可以通过调用
void *enif_priv_data(ErlNifEnv* env)来获得私有数据。
没有方法去声明unload一个NIF库,当erlang模块被卸载时候,NIF会被自动unload。
功能
NIF库所有函数有以下几种功能:读写erlang的terms
所有的erlang terms都可以通过作为函数的参数或者返回值来进行erlang和NIF库的传递。erlang的terms对应的是一个叫
ERL_NIF_TERM的c结构体,而且只能通过调用特定的API才能读写erlang terms。大部分读terms的API都是
enif_get_前缀的。而大部分写terms的API都是
enif_make_前缀,而通常会把写的那个
ERL_NIF_TERM作为返回值返回。还有一些API是用来判断terms的,例如
enif_is_atom,
enif_is_identical,
enif_compare。
所有
ERL_NIF_TERM都属于一个代表NIF环境的类型:
ErlNifEnv。所有terms的生命周期都由该
ErlNifEnv来控制。所有读写terms的函数的第一个变量都是这个
ErlNifEnv。
二进制
二进制类型的terms可以通过一个结构体
ErlNifBinary来操作。这个结构体包含一个指向原始二进制数据的指针和这个数据在字节长度。数据和长度都是只读的类型而且只能通过调用API函数去写(
注:调用某些方法后,会使他们变成可读)。然而通常会实例一个
ErlNifBinary然后分配给用户(通常是本地变量)。
指针指向的原始数据只有通过调用
enif_alloc_bianry或者
enif_realloc_bianry之后才能变得可改变。其他所以操作binary的函数都是只读。一个可以改变的binary在最后必须要调用
enif_release_binary来释放或者调用
enif_make_binary转换成只读的erlang terms。只读的binary是不需要被释放。在同样的NIF call里面可以使用
enif_make_new_binary分配和返回一个binary。binaries会被序列化全部字节。bitstrings
还不支持任意bit长度。
资源对象
使用资源对象的一个比较安全的方式是调用NIF借口把指向该数据的指针返回,一个资源对象实际上只是一块通过
enif_alloc_resource分配的内存。一个处理方法是通过使用
enif_make_resource把这块内存(指针)返回给erlang。
enif_make_resource的返回值是完全不透明的,它可以在同节点内不同进程间传递和存储,唯一的正确用法是在最后把返回值返回给NIF,然后NIF可以调用
enif_get_resource取得指针。直到最后一个
ERL_NIF_TERM被虚拟机回收和资源已经被
enif_release_resource释放的时候,资源对象才会被回收。
所有的资源对象都必须带有资源类型,这样可以使得资源在不同模块时候仍然可以区分出来。当库被加载时候调用
enif_get_resource去创建资源类型。当对象带有资源类型后,可以通过
enif_get_resource来校验是否是期待的类型。一个资源类型可以用户自定义的析构函数(借用C++)。资源类型是唯一定义的string名字和唯一的实现模块。
[code] 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创建了term返回给Erlang之后,有两个选择,一是保存它的指针到分配的结构体里面以后再释放。二是在垃圾收集时候释放它。
另外一种使用资源对象的方法的是使用定义的内存来创建binary terms,
enif_make_resource_binary会创建binary terms并连接一个资源对象。当该binary terms 被回收时候后会调用资源对象的析构函数,同时该binary terms可以被释放。
资源类型支持运行时升级,通过运行允许一个被加载的库去接管已经存在的资源类型,并继承所有已经存在的对象,而且对象的类型都会变成那个接管的资源类型.新的库的析构函数从那以后就可以被继承的对象继承。这样的话,就的析构函数就可以被安全卸载。资源对象和模块被坑下后,必须被删除或者被新的NIF接管。卸载的库一直被阻塞直到所有已存在的资源对象被析构或是被新的NIF接管。
多线程和并发
一个NIF库是线程安全的,只要函数的动作只是单纯地读提供的数据,太是不需要直接声明任何同步锁。但是如果你对一个静态变量或者
enif_priv_data进行写操作,你就要实现自己的同步锁操作。在进程独立环境里面的terms可以被多线程共享。资源对象需要锁。库在初始化时候的回调函数
load,
reload和
upgrade里就算是共享的静态数据也是线程安全的。避免在NIF里面进行耗时的操作,这样会降低VM的相应速度。Erlang代码调用NIF时候是直接调同样调度线程去执行,调度会因此阻塞,直到返回。
初始化
ERL_NIF_INIT(MODULE, ErlNifFunc funcs[], load, reload,upgrade, unload)这是一个初始化NIF库的宏技巧,它应该赋值给一个静态变量。
MODULE是erlang的模块名,是用一串无空格的字符串作为标识,它由一个宏去字符串化。
funcs是一个静态的数组 ,用来存放描述NIF库中实现的所有的方法名。
load,
reload,
upgrade,
unload是函数的指针,在NIF库初始化或者卸载,更新时候就会自动调用对应的方法。(下面有介绍)
int (load)(ErlNifEnv env, void** priv_data, ERL_NIF_TERM load_info) 该方法是当NIF库第一次载入时候到会调用。
*priv_data是一个指向保存自由数据的指针,该区域可以在多次NIF中保持静态,当该方法调用时候会被初始化为
NULL。
enif_priv_data方法可以返回该指针。
load_info是
erlang:load_nif/2的第二个参数。
当库加载失败时候会返回非0,如果没有指定加载方法就把
ERL_NIF_INIT的
load设为
NULL。
int (upgrade)(ErlNifEnv env, void[b] priv_data, void old_priv_data, ERL_NIF_TERM load_info)[/b]
当已经载入旧库的库,而且要更新时候使用。
*old_priv_data已经包含了之前调用
load和
reload的值,而
*priv_data会被初始化为
NULL.
*old_priv_data和
*priv_data都是可写的。
当更新失败时候返回非0,如果没有指定更新方法就把
ERL_NIF_INIT的
upgrade设为
NULL。
void (unload)(ErlNifEnv env, void* priv_data)
当库属于过旧要清理的情况下使用,注意这里并不是替换库操作。
int (reload)(ErlNifEnv env, void** priv_data, ERL_NIF_TERM load_info)
这个方法的实现机制是不可靠的,这只是一个开发者特性。不要使用该方法,实际环境中请把
reload设为
NULL
数据类型
ERL_NIF_TERMERL_NIF_TERM类型的变量可以引用任何erlang term,这是个不透明类型,而且它的值只可以用作api函数的参数或者返回值。所有的
ERL_NIF_TERM都属于
ErlNifEnv。一个term是不可以单独摧毁的,它会一直有效,直到它的环境被摧毁。
ErlNifEnv
ErlNifEnv被描述为erlang terms的宿主(生存环境),环境中所有的terms的生命周期都和该环境一样。
ErlNifEnv是一个不透明类型,指向它的指针只可以在api函数中传递,这里有两种环境,进程绑定和进程独立。
一个进程绑定的环境,会在所有的NIF函数里面作为第一个参数传递,所有传递给
ErlNifFunc
typedef struct { const char ; unsigned ; ERL_NIF_TERM ()(ErlNifEnv* env, int argc, const RL_NIF_TERM argv[]); } ErlNifFunc;
通过它的名字,参数数量和实现去定义一个NIF,
fptr是一个指向NIF实现函数的指针。NIF的参数
argv包含了erlang传递给NIF的全部参数,
argc是参数数组的长度。例如:如果参数
argv[N-1]就表明是第N个参数。注意:这个
argc可以使一个C的函数被多个erlang函数的调用,这些erlang调用时候可以用不同的参数长度。
ErlNifBinary
typedef struct { unsigned ; unsigned char* ; } ErlNifBinary;
ErlNifBianry包含一个检查二进制term的短暂信息,
data是一个指向长度为
size,存放二进制原生内容的buffer。
注意:
ErlNifBinary是一个半透明的类型,只允许读字段
size和
data。
ErlNifPid
ErlNifPid是一个进程的身份,对比pid terms(
ERL_NIF_TERM的实例),
ErlNifPid是自身包含自己且为绑定任何 environment。是一个不透明类型。
ErlNifResourceType
每个
ErlNifResourceType代表着一种内存管理资源对象,该可以可以被垃圾回收。每个资源类型都有一个唯一的名字和一个析构函数。对象销毁时候会自动调用析构函数。
ErlNifResourceDtor
typedef void ErlNifResourceDtor(ErlNifEnv env, void obj);
该函数原型包含一个资源的析构函数,这个资源析构函数不允许调用任何制造term的函数。
ErlNifCharEncoding
typedef enum { ERL_NIF_LATIN1 }ErlNifCharEncoding;
这个字符转义用于string和atoms的转换,当前唯一支持的是
ERL_NIF_LATINL(iso-latin-l,8-bit ascii)。
ErlNifSysInfo
用于
enif_system_info去返回运行时系统的信息。包含当前精确的信息,跟
ErlDrvSysInfo一样精确。
ErlNifSInt64
一个原生有符号的64bit长度的整形类型。
ErlNifUInt64
一个原生的无符号64bit长度的整形类型。
接口-资源分配类
viod * enif_alloc(size_t size)分配
size个字节大小的内存,如果分配失败就返回
NULL。
void enif_free(void* ptr)
释放通过
enif_alloc分配的内存。
ErlNifEnv *enif_alloc_env()
分配一个进程独立了的环境,该环境必须用来存放没有绑定任何进程的terms。可以在稍后再通过
enif_make_copy复制到一个进程环境,或者通过
enif_send作为一个信息发送到一个进程上。
返回一个指向新空间的指针。
void enif_clear_env(ErlNifEnv* env)
清除环境中所有的term,使环境可以复用,注意这个环境必须是通过
enif_alloc_env分配的。
void enif_free_env(ErlNifEnv* env)
析构环境,里面的term同样会被释放。
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会给已经存在的实例和将来创建的实例析构时候使用。
两个flags值可以通过位操作“与”来组合。资源类型的名字对于调用模块是局部的。
module_str是目前未使用,记得设为
NULL。
函数调用成功会返回一个指向资源类型的指针,然后
*tried会被设成
ERL_NIF_RT_CREATE或者
ERL_NIF_RT_TAKEOVER去表明实际动作是什么。如果失败就返回
NULL,并且把
*tried赋值为
flags的值。允许
tried是
NULL。
注意:该函数之允许在三个回调函数中调用(
load,
reload,
upgrade)
void enif_alloc_resource(ErlNifResourceType type, unsigned size)
分配内存给资源对象,要求传入类型和大小。
void enif_release_resource(void* obj)
释放资源对象。
ERL_NIF_TERM enif_make_resource(ErlNifEnv env, void obj)
对
enif_alloc_resource分配的内存资源对象创建一个不透明处理。拥有权并没有发生转移,该资源对象还是需要用
enif_release_resource释放。
注意如果在
enif_make_resource分配term之后马上调用
enif_release_resource的话,在term被垃圾回收时候,该资源对象会马上释放。
注意:在erlang编程里面,一个资源term只可以存储或者在同节点的不同进程间发送。其他操作如:匹配或者
term_to_binary会有个不可以预知的结果。
unsigned enif_sizeof_resource(void* obj)
取出资源的字节长度。
int enif_keep_resource(void* obj)
对资源添加一个引用。该资源对象必须由
enif_alloc_resource分配。
int enif_alloc_binary(size_t size, ErlNifBinary* bin)
分配一个
size个字节大小的二进制空间,初始化一个
ErlNifbinary,把指针传入,会关联分配的空间。该二进制空间必须用
enif_release_binary释放或者拥有者通过
enif_make_binary转义成erlang的term。一个分配好空间的
ErlNifBinary可以在多次NIF调用中保存下来。
成功返回
true,失败返回
false。
int enif_inspect_binary(ErlNifEnv env, ERL_NIF_TERM bin_term, ErlNifBinary bin)
通过
bin_term的信息初始化
bin指向的结构体。成功返回
true,如果
bin_term不是一个binary会失败。
int enif_inspect_iolist_as_binary(ErlNifEnv env, ERL_NIF_TERM term,ErlNifBinary bin)
term是iolist,通过
term初始化bin指向的结构体,跟
enif_inspect_binary一样,
bin指向的数据生命周期很短不需要手动释放。
(这里我认为是将一个iolist的erlang字符串转换成一个erlang的binary字符串)
成功返回
true,如果
term不是连续buffer会失败。
int enif_realloc_binary(ErlNifBinary* bin, size_t size)
改变
bin的大小。该binary可能是只读的,在这种情况下,会它会被抛弃,并且重新分配内存给
*bin。(it will be left untouched and amutable copy is allocated and assigned to *bin)
这里重新分配后的binary可以使erlang看来变量可变了。因为Erlang中的binary数据与NIF C中操作的是同一块内存的数据。
void enif_release_binary(ErlNifBinary* bin)
释放binary。
ERL_NIF_TERM enif_make_binary(ErlNifEnv env, ErlNifBinary bin)
创建一个binary term。拥有权会移交给创建的term。而
bin会被认为只读的(实际上你还可以操作的,这只是建议)。
unsigned char enif_make_new_binary(ErlNifEnv env, size_t size,ERL_NIF_TERM* termp)
分配
size大小字节的内存并创建term。这个binary的数据在NIF返回之前都是可变的。这是个快速创建binary的方法。缺点是该binary不能在多次NIF调用里保存,而且不可以重新分配内存大小。
ERL_NIF_TERM enif_make_sub_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term,size_t pos, size_t size)
复制部分binary来创建新的binary。
pos是位置,
size是长度。(是用来在C中模仿erlang的字符串binary操作的)
ERL_NIF_TERM enif_make_resource_binary(ErlNifEnv env, void obj, const void*data, size_t size)
创建一个binary term,该binary term在被析构之前必须保持可读和不可变,可能会包含外部的资源对象,在这种情况下,析构函数里面就应该去释放那些对象。
多个binary terms可能属于同一个资源对象,那么该析构函数不会被马上调用,直到最后一个binary被垃圾回收后。如果要返回一个大binary buffer的不同部分,这是一个好方法,
该函数内,拥有权没有发送改变,该资源仍然需要
enif_release_resource去释放。
void enif_system_info(ErlNifSysInfo *sys_info_ptr, size_t size)
该方法会写运行系统的信息到
ErlNifSysInfo。
接口-线程操作类
ErlNifThreadOpts enif_thread_opts_create(char name)name用一个字符串来标识线程选项,将来可能用于debug 功能。
该函数创建并初始化一个线程选项结构体。失败返回NULL。
该方法线程安全。
void enif_thread_opts_destroy(ErlNifThreadOpts *opts)
销毁一个线程选项。
该方法线程安全。
int enif_thread_create(char name,ErlNifTid tid,void * (func)(void
),void args,ErlNifThreadOpts opts)
name用一个字符串来标识线程,将来可能用于debug 功能。
tid指向线程标识变量的指针。
func指向线程执行函数的指针。
opts指向线程选项或者
NULL。
成功返回0,反之一个
errno值会返回。新创建的线程会调用
func,而
arg就是参数。
不允许自己分配空间给ErlNifThreadOpts,只能通过 erl_nif_thread_opts_create()去创建
该线程会在func执行返回或者调用
erl_nif_thread_exit时候死亡。NIF在unload之前,创建的线程需要通过
erl_nif_thread_join去加入线程。不可能存在‘分离在外’的线程。
如果没有加入成功,在NIF unload时候,整个系统可能会崩溃。
该方法线程安全。
void enif_thread_exit(void *resp)
该函数终结线程,退出值是
*resp。而这个退出值可以在后来加入的线程重新操作。
该方法线程安全。
int enif_thread_join(ErlNifTid, void **respp)
该方法是调用的线程跳入另外线程。例如:调用线程会阻塞,直到
tid线程被终结。成功会返回0,失败返回
errno对应错误。一个线程只能加入一次,如果多于一次,结果是未知的。如果
respp为空,那么在退出线程时候就会被忽略,反之会存储下来。
该方法线程安全。
ErlNifTid enif_thread_self(void)
返回调用线程的tid。
该方法线程安全。
int enif_equal_tids(ErlNifTid tid1, ErlNifTid tid2)
对比两个线程标识是否相同,不相同返回0,相同返回非0.
该方法线程安全。
int enif_tsd_key_create(char name, ErlNifTSDKey key)
创建一个线程特别的数据key。(key-value存储。先创建key)。在NIF unload前需要释放。
该方法线程安全。
void enif_tsd_key_destroy(ErlNifTSDKey key)
释放一个key。
该方法线程安全。
void *enif_tsd_get(ErlNifTSDKey key)
返回
key对应的数据。如果没有数据关联,就返回NULL。
该方法线程安全。
void enif_tsd_set(ErlNifTSDKey key, void *data)
声明关联
key和
data。
该方法线程安全。
void enif_cond_create(ErlNifCond *cnd)
通过一个字符串创建一个条件变量,返回一个指向这个变量的指针,时候返回
NULL,NIF在unloaded之前需要把这个条件变量销毁。
该方法线程安全。
void enif_cond_destory(ErlNifCond *cnd)
摧毁一个条件变量。该方法线程安全。
void enif_cond_wait(ErlNifCond cnd, ErlNifMutex mtx)
该函数会使线程阻塞知道其他线程唤醒。可以通过条件变量去唤醒单个或者全部线程。在线程阻塞之前它会解锁传递过来的互斥量,当被唤醒时候它会锁住改互斥量。所以在调用该方法前,那个互斥量需要先锁住。
该方法线程安全。
void enif_cond_signal(ErlNifCond *cnd)
该函数通过条件变量去单播。如果其他线程等待这个这个信号,其中一个都会被唤醒。
该方法线程安全。
void enif_cond_broadcast(ErlNifCond *cnd)
该函数通过条件变量去广播。如果其他线程等待这个这个信号,全部都会被唤醒。
该方法线程安全。
ErlNifPid enif_self(ErlNifEnv caller_env, ErlNifPid* pid)
把调用该函数的进程和
*pid绑定,返回pid。
该方法线程安全。
int enif_send(ErlNifEnv env, ErlNifPid to_pid, ErlNifEnv* msg_env,ERL_NIF_TERM msg)
发送一个信息给一个进程。
env是调用进程的环境,仅当如果是由一个线程发起调用时候把该值设为
NULL。
*to_pid指接收信息的进程,这个pid应该关联了一个本地节点。
msg_env发送的term所属的环境,必须是一个进程独立的环境(由
enif_alloc_env分配)
msg要发送的信息term。
如果成功就返回
true,如果
*to_pid并没有关联一个存活着的本地进程会返回
false。
如果成功调用后,
msg_env的所有term都会变得无效,这时候应该调用
enif_free_env或者
enif_clear_env去释放或者重用。
该方法只有在开启SMP支持后变得线程安全。在non-SMP模式下,只能由NIF调用的那个线程使用。
ErlNifMutex enif_mutex_create(char name)
通过一个字符串去创建一个互斥量。成功返回指向互斥量的指针。失败返回空,在NIF unload前需要释放它。
该方法线程安全。
void enif_mutex_destroy(ErlNifMutex *mtx)
释放一个互斥量。
该方法线程安全。
void enif_mutex_lock(ErlNifMutex *mtx)
锁住一个互斥量。调用线程会阻塞,直到锁住,如果一个线程当前已经锁住,不会再次加锁。
该方法线程安全。
int enif_mutex_trylock(ErlNifMutex *mtx)
该函数尝试锁住一个互斥量,成功返回0,反之返回
EBUSY。
该方法线程安全。
void enif_mutex_unlock(ErlNifMutex *mtx)
解锁互斥量。
该方法线程安全。
读写锁操作
ErlNifRWLock enif_rwlock_create(char name)
void enif_rwlock_destroy(ErlNifRWLock rwlck)
void enif_rwlock_rlock(ErlNifRWLock rwlck)
void enif_rwlock_runlock(ErlNifRWLock rwlck)
void enif_rwlock_rwlock(ErlNifRWLock rwlck)
void enif_rwlock_rwunlock(ErlNifRWLock rwlck)
int enif_rwlock_tryrlock(ErlNifRWLock rwlck)
int enif_rwlock_tryrwlock(ErlNifRWLock *rwlck)
接口-类型操作类
int enif_compare(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)返回一个大于,等于,小于0整形数字来表示lhs 大于,等于,小于rhs。分别相当于erlang的运算符 ==,/=,=<,<,>,>=,> (但不包括 =:= 和 =/=)。
ERL_NIF_TERM enif_make_copy(ErlNifEnv* dst_env, ERL_NIF_TERM src_term)
在
dst_env环境中创建一个复制
src_term。
int enif_get_atom(ErlNifEnv env, ERL_NIF_TERM term, char buf, unsigned size, ErlNifCharEncoding encode)
在
size大小的
buf里面写入一个结束符。由term译码后变成字符组成,返回字节数。如果term不是一个长度为
size-1的atom就返回0.
取term中的值,并赋值到一个参数中(看参数里面哪个同类型的,就是赋值给它的了),成功返回ture,失败返回false
int enif_get_atom_length(ErlNifEnv env, ERL_NIF_TERM term, unsigned len,ErlNifCharEncoding encode)
int enif_get_double(ErlNifEnv env, ERL_NIF_TERM term, double dp)
int enif_get_int(ErlNifEnv env, ERL_NIF_TERM term, int ip)
int enif_get_int64(ErlNifEnv env, ERL_NIF_TERM term, ErlNifSInt64 ip)
int enif_get_local_pid(ErlNifEnv env, ERL_NIF_TERM term, ErlNifPid pid)
int enif_get_list_cell(ErlNifEnv env, ERL_NIF_TERM list, ERL_NIF_TERM head,ERL_NIF_TERM tail)
int enif_get_list_length(ErlNifEnv env, ERL_NIF_TERM term, unsigned len)
int enif_get_long(ErlNifEnv env, ERL_NIF_TERM term, long int ip)
int enif_get_resource(ErlNifEnv env, ERL_NIF_TERM term, ErlNifResourceType type, void** objp)
int enif_get_string(ErlNifEnv env, ERL_NIF_TERM list, char buf, unsigned size, ErlNifCharEncoding encode)
int enif_get_tuple(ErlNifEnv env, ERL_NIF_TERM term, int arity, const ERL_NIF_TERM** array)
int enif_get_uint(ErlNifEnv env, ERL_NIF_TERM term, unsigned int ip)
int enif_get_uint64(ErlNifEnv env, ERL_NIF_TERM term, ErlNifUInt64 ip)
int enif_get_ulong(ErlNifEnv env, ERL_NIF_TERM term, unsigned long* ip)
void enif_priv_data(ErlNifEnv env)
返回之前在load,reload或者upgrade设置的私有数据的指针。
类型判断,如果是该类型就返回true
int enif_is_atom(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_binary(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_empty_list(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_exception(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_number(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_fun(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_identical(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)
int enif_is_pid(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_port(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_ref(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_tuple(ErlNifEnv env, ERL_NIF_TERM term)
int enif_is_list(ErlNifEnv* env, ERL_NIF_TERM term)
创建一个term,第一个参数是环境,后面参数是term的值的来源和条件
ERL_NIF_TERM enif_make_atom(ErlNifEnv env, const char name)
ERL_NIF_TERM enif_make_atom_len(ErlNifEnv env, const char name, size_t len)
ERL_NIF_TERM enif_make_badarg(ErlNifEnv env)
ERL_NIF_TERM enif_make_double(ErlNifEnv env, double d)
int enif_make_existing_atom(ErlNifEnv env, const char name, ERL_NIF_TERM atom, ErlNifCharEncoding encode)
int enif_make_existing_atom_len(ErlNifEnv env, const char name, size_t len,ERL_NIF_TERM atom, ErlNifCharEncoding encoding)
ERL_NIF_TERM enif_make_int(ErlNifEnv env, int i)
ERL_NIF_TERM enif_make_int64(ErlNifEnv env, ErlNifSInt64 i)
ERL_NIF_TERM enif_make_list(ErlNifEnv env, unsigned cnt, ...)
ERL_NIF_TERM enif_make_list_cell(ErlNifEnv env, ERL_NIF_TERM head,ERL_NIF_TERM tail)
ERL_NIF_TERM enif_make_list_from_array(ErlNifEnv env, const ERL_NIF_TERM arr[], unsigned cnt)
int enif_make_reverse_list(ErlNifEnv env, ERL_NIF_TERM term, ERL_NIF_TERM
list)
ERL_NIF_TERM enif_make_long(ErlNifEnv env, long int i)
ERL_NIF_TERM enif_make_pid(ErlNifEnv env, const ErlNifPid pid)
ERL_NIF_TERM enif_make_ref(ErlNifEnv* env)
ERL_NIF_TERM enif_make_string(ErlNifEnv env, const char string,ErlNifCharEncoding encoding)
ERL_NIF_TERM enif_make_string_len(ErlNifEnv env, const char string, size_t len, ErlNifCharEncoding encoding)
ERL_NIF_TERM enif_make_tuple(ErlNifEnv env, unsigned cnt, ...)
ERL_NIF_TERM enif_make_tuple_from_array(ErlNifEnv env, const ERL_NIF_TERM arr[], unsigned cnt)
ERL_NIF_TERM enif_make_uint(ErlNifEnv env, unsigned int i)
ERL_NIF_TERM enif_make_uint64(ErlNifEnv env, ErlNifUInt64 i)
ERL_NIF_TERM enif_make_ulong(ErlNifEnv* env, unsigned long i)
by dp
--EOF
← Previous
Archive
Next →
Published
20 September 2012Category
erlang© puzzleyes 2014 with help from
Jekyll Bootstrap and
The Hooligan Theme
相关文章推荐
- MySQL中文参考手册--8.MySQL教程--8.3 常用查询的例子
- linux学习笔记七:安装中文man手册
- Netty中文用户手册(二)
- rsync中文手册之使用rsync实现网站镜像和备份linux第1/3页
- 最新JDK6API中文参考手册[chm格式]下载
- Magento 2中文手册教程 - 在浏览器运行安全设置 cron.php
- MySQL中文参考手册
- Maven POM的中文参考手册
- dhtmlx技术使用总结与介绍中文手册
- 下载Hibernate中文参考手册
- Swift网络封装库Moya中文手册之RxSwift
- sshd_config中文手册2
- Delphi编译错误中文手册
- S3C2410中文芯片手册-11.串口
- 基本函数Memcache中文手册——《Memcache中文手册》 php版
- GCC 中文手册(下)
- linux 打造man中文手册图解(man-pages-zh帮助页)
- GNU make中文手册
- WinCVS中文版及中文使用手册
- RFC中文手册