NIF除了自身提供的功能外,还封装了一系列driver的功能,这些功能与操作系统平台紧密相关,主要包括:
系统信息,
操作系统线程及线程私有资源 ,条件变量、信号量、读写锁等,这些功能本身与erlang的进程体系无关,本身也是线程安全的,因此可以直接复用到NIF中,统一NIF的接口。
此处简单的分析一个操作系统线程创建的接口,其余的类似。
int enif_thread_create(char *name, ErlNifTid *tid, void* (*func)(void *),
void *args, ErlNifThreadOpts *opts) {
return erl_drv_thread_create(name,tid,func,args,(ErlDrvThreadOpts*)opts);
}
enif_thread_create直接调用了对应的driver接口erl_drv_thread_create,其它复用driver功能的接口也类似。
int
erl_drv_thread_create(char *name,
ErlDrvTid *tid,
void* (*func)(void*),
void* arg,
ErlDrvThreadOpts *opts)
{
#ifdef USE_THREADS
int res;
struct ErlDrvTid_ *dtid;
ethr_thr_opts ethr_opts;
ethr_thr_opts *use_opts;
if (!opts)
use_opts = NULL;
else {
sys_memcpy((void *) ðr_opts,
(void *) &def_ethr_opts,
sizeof(ethr_thr_opts));
ethr_opts.suggested_stack_size = opts->suggested_stack_size;
use_opts = ðr_opts;
}
dtid = erts_alloc_fnf(ERTS_ALC_T_DRV_TID,
(sizeof(struct ErlDrvTid_)
+ (name ? sys_strlen(name) + 1 : 0)));
/* 分配一个ErlDrvTid_结构,保存线程描述符 */
/*
struct ErlDrvTid_ {
ethr_tid tid;
void* (*func)(void*);
void* arg;
int drv_thr;
Uint tsd_len;
void **tsd;
char *name;
};
*/
if (!dtid)
return ENOMEM;
dtid->drv_thr = 1;
dtid->func = func;
dtid->arg = arg;
dtid->tsd = NULL;
dtid->tsd_len = 0;
/* 填充线程描述符,func为线程执行入口点,arg为其参数,tsd为线程私有数据结构,可以保存线程私有数据,与线程紧密相关 */
if (!name)
dtid->name = no_name;
else {
dtid->name = ((char *) dtid) + sizeof(struct ErlDrvTid_);
sys_strcpy(dtid->name, name);
}
res = ethr_thr_create(&dtid->tid, erl_drv_thread_wrapper, dtid, use_opts);
/* 创建一个操作系统线程,该线程并不直接以用户提供的函数为入口点,而是提供了一层外覆函数,
外覆 函数为erl_drv_thread_wrapper */
if (res != 0) {
erts_free(ERTS_ALC_T_DRV_TID, dtid);
return res;
}
*tid = (ErlDrvTid) dtid;
/* 返回创建的线程描述符 */
return 0;
#else
return ENOTSUP;
#endif
}
int ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg, ethr_thr_opts *opts)
{
ethr_thr_wrap_data__ twd;
pthread_attr_t attr;
int res, dres;
int use_stack_size = (opts && opts->suggested_stack_size >= 0
? opts->suggested_stack_size
: -1 /* Use system default */);
#ifdef ETHR_MODIFIED_DEFAULT_STACK_SIZE
if (use_stack_size < 0)
use_stack_size = ETHR_MODIFIED_DEFAULT_STACK_SIZE;
#endif
#if ETHR_XCHK
if (ethr_not_completely_inited__) {
ETHR_ASSERT(0);
return EACCES;
}
if (!tid || !func) {
ETHR_ASSERT(0);
return EINVAL;
}
#endif
ethr_atomic32_init(&twd.result, (ethr_sint32_t) -1);
twd.tse = ethr_get_ts_event();
twd.thr_func = func;
twd.arg = arg;
res = pthread_attr_init(&attr);
if (res != 0)
return res;
/* Error cleanup needed after this point */
/* Schedule child thread in system scope (if possible) ... */
res = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
if (res != 0 && res != ENOTSUP)
goto error;
if (use_stack_size >= 0) {
size_t suggested_stack_size = (size_t) use_stack_size;
size_t stack_size;
#ifdef ETHR_DEBUG
suggested_stack_size /= 2; /* Make sure we got margin */
#endif
#ifdef ETHR_STACK_GUARD_SIZE
/* The guard is at least on some platforms included in the stack size
passed when creating threads */
suggested_stack_size += ETHR_B2KW(ETHR_STACK_GUARD_SIZE);
#endif
if (suggested_stack_size < ethr_min_stack_size__)
stack_size = ETHR_KW2B(ethr_min_stack_size__);
else if (suggested_stack_size > ethr_max_stack_size__)
stack_size = ETHR_KW2B(ethr_max_stack_size__);
else
stack_size = ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size));
(void) pthread_attr_setstacksize(&attr, stack_size);
}
#ifdef ETHR_STACK_GUARD_SIZE
(void) pthread_attr_setguardsize(&attr, ETHR_STACK_GUARD_SIZE);
#endif
/* Detached or joinable... */
res = pthread_attr_setdetachstate(&attr,
(opts && opts->detached
? PTHREAD_CREATE_DETACHED
: PTHREAD_CREATE_JOINABLE));
if (res != 0)
goto error;
/* Call prepare func if it exist */
if (ethr_thr_prepare_func__)
twd.prep_func_res = ethr_thr_prepare_func__();
else
twd.prep_func_res = NULL;
res = pthread_create((pthread_t *) tid, &attr, thr_wrapper, (void*) &twd);
if (res == 0) {
int spin_count = child_wait_spin_count;
/* Wait for child to initialize... */
while (1) {
ethr_sint32_t result;
ethr_event_reset(&twd.tse->event);
result = ethr_atomic32_read(&twd.result);
if (result == 0)
break;
if (result > 0) {
res = (int) result;
goto error;
}
res = ethr_event_swait(&twd.tse->event, spin_count);
if (res != 0 && res != EINTR)
goto error;
spin_count = 0;
}
}
/* Cleanup... */
error:
dres = pthread_attr_destroy(&attr);
if (res == 0)
res = dres;
if (ethr_thr_parent_func__)
ethr_thr_parent_func__(twd.prep_func_res);
return res;
}
可以看出,线程创建过程是一个标准的pthread线程创建框架。
static void *erl_drv_thread_wrapper(void *vdtid)
{
int res;
struct ErlDrvTid_ *dtid = (struct ErlDrvTid_ *) vdtid;
res = ethr_tsd_set(tid_key, vdtid);
if (res != 0)
fatal_error(res, "erl_drv_thread_wrapper()");
return (*dtid->func)(dtid->arg);
}
int
ethr_tsd_set(ethr_tsd_key key, void *value)
{
#if ETHR_XCHK
if (ethr_not_inited__) {
ETHR_ASSERT(0);
return EACCES;
}
#endif
return pthread_setspecific((pthread_key_t) key, value);
}
外覆函数通过pthread_setspecific为线程设置kv私有数据结构,这个数据结构是线程的erlang线程描述符ErlDrvTid,然后以用户给出的参数调用用户的函数。
进入NIF世界后,就可以借助很多erlang虚拟机的功能来探索erlang世界了,此时既可以通过erlang来实现功能,也可以通过c来实现功能,可以将各式各样的c系统移植如erlang虚拟机,扩充和丰富erlang的功能,同时减少开发的难度,性能也将得到很大的提高。
分享到:
相关推荐
在Erlang生态系统中,Native Implemented Functions (NIFs) 是一种机制,允许开发者用其他语言(如C、C++或Rust)编写性能关键部分的代码,然后在Erlang虚拟机(VM)中调用。Rustler是一个库,专门用于简化使用Rust...
Erlang NIF(Native Implemented Functions)是Erlang虚拟机提供的一种机制,允许开发者用C语言或者其他低级语言编写性能关键部分的代码,并在Erlang系统中无缝调用。这种方式可以充分利用C语言的高效性,同时保持...
在Erlang中,`NIF (Native Implemented Functions)` 是一种机制,允许开发者使用其他语言(如C或Rust)...通过理解`rustler_macro`的过程宏和Erlang NIF的生命周期,开发者可以轻松地将Rust功能集成到Erlang系统中。
示例Rustler是一个用于以安全的Rust代码编写Erlang NIF的库。 这意味着应该没有任何办法。 入门指南 示例Rustler是一个用于以安全的Rust代码编写Erlang NIF的库。 这意味着应该没有办法使BEAM(Erlang VM)崩溃。 该...
Port Driver 可能与其他 Erlang 外部接口技术,如 NIF(Native Implemented Function)或 ETS(Erlang Term Storage)进行了对比。 标签 "erlang post driver test" 强调了测试的焦点是关于 Erlang 的 Port Driver...
在Erlang中,为了实现与C或其他低级语言的高效交互,Erlang提供了一个名为`erl_nif`的接口。本文将深入探讨`erl_nif`,了解它是如何扩展Erlang的功能,并讨论如何使用它来提升性能。 `erl_nif`(Erlang NIF,Native...
Erlang与C语言接口主要通过两种方式实现:一种是将C语言编写的代码直接嵌入到Erlang程序中;另一种是通过进程间通信(IPC)的方式让Erlang与C语言程序进行交互。Erlang倾向于采用第二种方式,即进程间通信,来与C语言...
Windows下使用NIF扩展Erlang完整例子,包含nif工程项目,erlang引用例子。 配套文章:http://blog.csdn.net/mycwq/article/details/17527485
Rust 中的 Erlang NIF 这是一个如何在 Rust 中实现 NIF 的示例。 它对我有用,也可能对你有用,但如果它吃掉了你的作业,请不要生气。 虽然这将是可行的写现实世界的代码下面这个例子,因为整个erl_nif.h接口可用...
ErlPuzzle - Erlang 的 libpuzzle NIF Puzzle 库旨在快速找到视觉上相似的图像(gif、png、jpg),即使它们已被调整大小、重新压缩、重新着色或稍微修改。 该库是免费的、轻量级的但非常快速、可配置、易于使用,...
这是第一卷。 在2008 CN Erlounge III的“Erlang应用程序接口”讲演的视频。PPT等其它资料在这里: http://blog.csdn.net/aimingoo/archive/2009/01/14/3777765.aspx 有关信息参见: ...
- **Erlang模块**:Erlang代码部分,定义了与NIF交互的接口函数,这些函数在Erlang代码中可以像普通函数一样调用。 - **NIF接口定义**:Erlang模块中会有`erlang:nifEXPORTS`列表,列出所有暴露给Erlang的NIF函数...
在Erlang NIF中实现的SHA-224,SHA-256,SHA-384,SHA-512。描述erlsha2库应用程序使用Erlang NIF实施SHA-2安全哈希标准(SHA-224,SHA-256,SHA-384,SHA-512)。 (它也提供纯的Erlang实现,尽管它们比C NIF实现慢...
该库以nif库的形式实现,可以最快地访问sqlite数据库。 这可能是有风险的,因为nif库或sqlite数据库中的错误可能会使整个Erlang VM崩溃。 如果您不想冒险,总是可以从单独的erlang节点访问sqlite nif。 特别注意...
**enif_protobuf** 是一个基于 **Erlang ...总之,enif_protobuf是Erlang社区对Google Protobuf的一种强大实现,通过Erlang NIF机制实现了高性能的数据序列化和反序列化,简化了Erlang系统与其他系统之间的数据交换。
在Erlang应用中,这些NIF函数可以通过标准的Erlang/Elixir接口调用,就像调用普通的Erlang模块一样。这样,开发者可以在保持Erlang/Elixir应用的并发性和容错性的同时,利用Rust的性能和安全性来处理计算密集型任务...
盗贼文档|入门|例子Rustler 是一个用安全的 Rust 代码编写 Erlang NIF 的库。这意味着应该没有办法让 BEAM (Erlang VM) 崩溃。该库提供了用于生成与 BEAM 交互的样板的工具,处理 Erlang 术语的编码和解码,并在它们...
我在Erlounge III大会上的讲演PPT。 相关的视频在这里: http://groups.google.com/group/erlang-china/browse_thread/thread/2154c39503795edc
`dizzyd-erlang-mysql-driver` 是一个Erlang库,实现了MySQL的驱动接口。它提供了丰富的API,支持执行SQL查询、事务处理、结果集处理等功能。这个库的版本号为 `a2ae450`,意味着它包含了某些特定的改进和修复。 ##...