`
wqtn22
  • 浏览: 101545 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

erlang NIF部分接口实现(四)消息发送

    博客分类:
  • erts
阅读更多

erlang中不能没有消息和异步过程,NIF也必须有此项能力,这个能力是通过enif_send实现的,它可以在NIF中向一个进程发送消息,但由于消息本身需要跨进程传递,消息的生命周期可能很长,而在erlang NIF部分接口实现(一)中可以看到,NIF每次调用所使用的ErlNifEnv结构是位于process_main函数的栈上的,由这个ErlNifEnv结构分配消息所占用的内存是不可能的,因此需要一个长期存在的ErlNifEnv结构来回收消息的内存,而ErlNifEnv结构是附着于一个进程的,同时也需要一个Process结构,产生分配内存的堆。

为了构建这个长期存在的ErlNifEnv结构,需要能够动态的分配ErlNifEnv结构:

 

struct enif_msg_environment_t

{

    ErlNifEnv env;

    Process phony_proc;

};

 

 

ErlNifEnv* enif_alloc_env(void)

{

    struct enif_msg_environment_t* msg_env =

erts_alloc_fnf(ERTS_ALC_T_NIF, sizeof(struct enif_msg_environment_t));

    Eterm* phony_heap = (Eterm*) msg_env; /* dummy non-NULL ptr */

    msg_env->env.hp = phony_heap; 

    msg_env->env.hp_end = phony_heap;

    msg_env->env.heap_frag = NULL;

    msg_env->env.mod_nif = NULL;

    msg_env->env.tmp_obj_list = NULL;

    msg_env->env.proc = &msg_env->phony_proc;

    memset(&msg_env->phony_proc, 0, sizeof(Process));

    HEAP_START(&msg_env->phony_proc) = phony_heap;

    HEAP_TOP(&msg_env->phony_proc) = phony_heap;

    HEAP_LIMIT(&msg_env->phony_proc) = phony_heap;

    HEAP_END(&msg_env->phony_proc) = phony_heap;

    MBUF(&msg_env->phony_proc) = NULL;

    msg_env->phony_proc.id = ERTS_INVALID_PID;

#ifdef FORCE_HEAP_FRAGS

    msg_env->phony_proc.space_verified = 0;

    msg_env->phony_proc.space_verified_from = NULL;

#endif

    return &msg_env->env;

}

该函数将在内存中产生一个enif_msg_environment_t结构,它包含两个成员,env和 phony_proc,env即为长期ErlNifEnv结构,而phony_proc即为env附着的伪Process结构,env借助phony_proc的堆分配消息所占的内存。
任何需要发送的消息的term,都必须通过这个动态产生的env分配,而之后调用enif_send发送消息时,消息及其动态env必须一致。
可以通过enif_free_env来释放enif_msg_environment_t结构:
void enif_free_env(ErlNifEnv* env)
{
    enif_clear_env(env);
    erts_free(ERTS_ALC_T_NIF, env);
}

 

也可以通过enif_clear_env来清洗一个ErlNifEnv结构以重用:

 

void enif_clear_env(ErlNifEnv* env)

{

    struct enif_msg_environment_t* menv = (struct enif_msg_environment_t*)env;

    Process* p = &menv->phony_proc;

    ASSERT(p == menv->env.proc);

    ASSERT(p->id == ERTS_INVALID_PID);

    ASSERT(MBUF(p) == menv->env.heap_frag);

    if (MBUF(p) != NULL) {

erts_cleanup_offheap(&MSO(p));

clear_offheap(&MSO(p));

free_message_buffer(MBUF(p));

MBUF(p) = NULL;

menv->env.heap_frag = NULL;

    }

    ASSERT(HEAP_TOP(p) == HEAP_END(p));

    menv->env.hp = menv->env.hp_end = HEAP_TOP(p);

 

    ASSERT(!is_offheap(&MSO(p)));

    free_tmp_objs(env);

}

有了这个长期存在的ErlNifEnv结构,就可以利用它来产生消息所需要的内存并发送该消息了:

 

 

int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, ErlNifEnv* msg_env, ERL_NIF_TERM msg)

{

    struct enif_msg_environment_t* menv = (struct enif_msg_environment_t*)msg_env;

    ErtsProcLocks rp_locks = 0;

    Process* rp;

    Process* c_p;

    ErlHeapFragment* frags;

#if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP)

    ErtsProcLocks rp_had_locks;

#endif

    Eterm receiver = to_pid->pid;

    int flush_me = 0;

 

    if (env != NULL) {

c_p = env->proc;

if (receiver == c_p->id) {

   rp_locks = ERTS_PROC_LOCK_MAIN;

   flush_me = 1;

}

    }

    else {

#ifdef ERTS_SMP

c_p = NULL;

#else

erl_exit(ERTS_ABORT_EXIT,"enif_send: env==NULL on non-SMP VM");

#endif

    }    

 

#if defined(ERTS_ENABLE_LOCK_CHECK) && defined(ERTS_SMP)

    rp_had_locks = rp_locks;

#endif

    rp = erts_pid2proc_opt(c_p, ERTS_PROC_LOCK_MAIN,

  receiver, rp_locks, ERTS_P2P_FLG_SMP_INC_REFC);

 

    /* 临时增加消息目的进程的引用计数,防止在发送途中目的进程被销毁。 */

 

    if (rp == NULL) {

ASSERT(env == NULL || receiver != c_p->id);

return 0;

    }

    flush_env(msg_env);

    frags = menv->env.heap_frag; 

    ASSERT(frags == MBUF(&menv->phony_proc));

    if (frags != NULL) {

/* Move all offheap's from phony proc to the first fragment.

  Quick and dirty, but erts_move_msg_mbuf_to_heap doesn't care. */

ASSERT(!is_offheap(&frags->off_heap));

frags->off_heap = MSO(&menv->phony_proc);

clear_offheap(&MSO(&menv->phony_proc));

menv->env.heap_frag = NULL; 

MBUF(&menv->phony_proc) = NULL;

    }

    ASSERT(!is_offheap(&MSO(&menv->phony_proc)));

 

    if (flush_me) {

flush_env(env); /* Needed for ERTS_HOLE_CHECK */ 

    }

    erts_queue_message(rp, &rp_locks, frags, msg, am_undefined

#ifdef USE_VM_PROBES

      , NIL

#endif

      );


    /* 这是erlang内部由于将消息投递到目的进程消息队列的函数 */

 

    if (rp_locks) {

ERTS_SMP_LC_ASSERT(rp_locks == (rp_had_locks | (ERTS_PROC_LOCK_MSGQ | 

ERTS_PROC_LOCK_STATUS)));

erts_smp_proc_unlock(rp, (ERTS_PROC_LOCK_MSGQ | ERTS_PROC_LOCK_STATUS));

    }

    erts_smp_proc_dec_refc(rp);

    if (flush_me) {

cache_env(env);

    }

    return 1;

}

该接口的to_pid参数即为消息的目的进程,msg_env即为通过enif_alloc_env所产生的长期ErlNifEnv,通过前面的代码分析可以发现,该结构实际嵌入一个enif_msg_environment_t结构,msg参数是需要发送的消息,它是由msg_env所分配的term,消息将通过erts_queue_message转移到目的进程的消息队列中。

在有了异步消息投递能力后,NIF可以的功能将极大的丰富。

分享到:
评论

相关推荐

    rustler编写erlang nif

    在Erlang生态系统中,Native Implemented Functions (NIFs) 是一种机制,允许开发者用其他语言(如C、C++或Rust)编写性能关键部分的代码,然后在Erlang虚拟机(VM)中调用。Rustler是一个库,专门用于简化使用Rust...

    erlang nif test

    Erlang NIF(Native Implemented Functions)是Erlang虚拟机提供的一种机制,允许开发者用C语言或者其他低级语言编写性能关键部分的代码,并在Erlang系统中无缝调用。这种方式可以充分利用C语言的高效性,同时保持...

    erl_nif_rustler_过程宏写法

    在Erlang中,`NIF (Native Implemented Functions)` 是一种机制,允许开发者使用其他语言(如C或Rust)编写高效性能的代码,并在Erlang虚拟机中调用。本篇主要介绍如何利用Rust语言来开发Erlang NIF,并探讨`erl_nif...

    rustler —用于创建Erlang NIF函数的安全Rust桥-Rust开发

    示例Rustler是一个用于以安全的Rust代码编写Erlang NIF的库。 这意味着应该没有任何办法。 入门指南 示例Rustler是一个用于以安全的Rust代码编写Erlang NIF的库。 这意味着应该没有办法使BEAM(Erlang VM)崩溃。 该...

    erl_nif 扩展erlang的另外一种方法

    在Erlang中,为了实现与C或其他低级语言的高效交互,Erlang提供了一个名为`erl_nif`的接口。本文将深入探讨`erl_nif`,了解它是如何扩展Erlang的功能,并讨论如何使用它来提升性能。 `erl_nif`(Erlang NIF,Native...

    Windows下使用NIF扩展Erlang完整例子

    Windows下使用NIF扩展Erlang完整例子,包含nif工程项目,erlang引用例子。 配套文章:http://blog.csdn.net/mycwq/article/details/17527485

    erlang -c语言程序接口.pdf

    Erlang与C语言接口主要通过两种方式实现:一种是将C语言编写的代码直接嵌入到Erlang程序中;另一种是通过进程间通信(IPC)的方式让Erlang与C语言程序进行交互。Erlang倾向于采用第二种方式,即进程间通信,来与C语言...

    erlang-rust-nif:在 Rust 中实现的 Erlang NIF 示例

    Rust 中的 Erlang NIF 这是一个如何在 Rust 中实现 NIF 的示例。 它对我有用,也可能对你有用,但如果它吃掉了你的作业,请不要生气。 虽然这将是可行的写现实世界的代码下面这个例子,因为整个erl_nif.h接口可用...

    erlpuzzle:Erlang NIF 到 libpuzzle,一个快速查找视觉相似图像的库

    ErlPuzzle - Erlang 的 libpuzzle NIF Puzzle 库旨在快速找到视觉上相似的图像(gif、png、jpg),即使它们已被调整大小、重新压缩、重新着色或稍微修改。 该库是免费的、轻量级的但非常快速、可配置、易于使用,...

    erlang的timer和实现机制

    Erlang的轻量级进程模型和消息传递机制为实现高效、可靠的定时器提供了基础。由于进程间的通信是异步的,因此定时器不会阻塞当前进程,提高了系统的整体性能。 在学习Erlang的timer模块时,还需要了解如何处理并发...

    enif_protobuf:使用enif(Erlang nif)的Google Protobuf实现

    **enif_protobuf** 是一个基于 **Erlang NIF (Native Implemented Functions)** 的库,用于集成 **Google Protobuf**,使得在Erlang环境中能够方便地处理和序列化protobuf消息。Erlang NIF是一种机制,允许Erlang...

    esqlite:sqlite的Erlang NIF

    该库以nif库的形式实现,可以最快地访问sqlite数据库。 这可能是有风险的,因为nif库或sqlite数据库中的错误可能会使整个Erlang VM崩溃。 如果您不想冒险,总是可以从单独的erlang节点访问sqlite nif。 特别注意...

    erlsha2:在Erlang NIF中实现的SHA-224,SHA-256,SHA-384,SHA-512

    在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实现慢...

    erlang-tc:Erlang NIF用于threshold_crypto

    - **Erlang模块**:Erlang代码部分,定义了与NIF交互的接口函数,这些函数在Erlang代码中可以像普通函数一样调用。 - **NIF接口定义**:Erlang模块中会有`erlang:nifEXPORTS`列表,列出所有暴露给Erlang的NIF函数...

    Erlang应用程序接口(视频,1/4)

    这是第一卷。 在2008 CN Erlounge III的“Erlang应用程序接口”讲演的视频。PPT等其它资料在这里: http://blog.csdn.net/aimingoo/archive/2009/01/14/3777765.aspx 有关信息参见: ...

    rustler:用于创建Erlang NIF函数的Safe Rust桥

    在Erlang应用中,这些NIF函数可以通过标准的Erlang/Elixir接口调用,就像调用普通的Erlang模块一样。这样,开发者可以在保持Erlang/Elixir应用的并发性和容错性的同时,利用Rust的性能和安全性来处理计算密集型任务...

    用于创建 Erlang NIF 函数的安全 Rust 桥

    盗贼文档|入门|例子Rustler 是一个用安全的 Rust 代码编写 Erlang NIF 的库。这意味着应该没有办法让 BEAM (Erlang VM) 崩溃。该库提供了用于生成与 BEAM 交互的样板的工具,处理 Erlang 术语的编码和解码,并在它们...

    erlang版本的protobuf(erl_protobuffs)

    在Erlang社区,为了利用protobuf的优势,出现了`erl_protobuffs`,这是一个针对Erlang实现的protobuf库。 **erl_protobuffs的优势** 1. **性能提升**:`erl_protobuffs`经过优化,相比其他Erlang的protobuf实现,...

Global site tag (gtag.js) - Google Analytics