轻作



重拾写作的乐趣

Erlang热更新的实现

2020.03.04

从一个基本调用开始

{function, call, 0, 2}.
  {label,1}.
    {line,[{location,"src/examples/test/test.erl",9}]}.
    {func_info,{atom,test},{atom,call},0}.
  {label,2}.
    {move,{atom,c},{x,0}}.
    {line,[{location,"src/examples/test/test.erl",10}]}.
    {call_ext_only,1,{extfunc,a,b,1}}.

call_ext_only指令位于beam_hot.h文件,在编译时使用ops.tab文件生成

接下来看下指令代码

OpCase(i_call_ext_last_eQ):
{
  E = ADD_BYTE_OFFSET(E, I[2]);;
  do {
    BeamInstr dis_next;
    Export *ep;

    ep = (Export*)(I[1]);

    DTRACE_GLOBAL_CALL_FROM_EXPORT(c_p, ep);

    SET_I(ep->dispatch.addresses[erts_active_code_ix()]);
    CHECK_ARGS(I);
    dis_next = *I;

    if (ERTS_UNLIKELY(FCALLS <= 0)) {
      if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p) && FCALLS > neg_o_reds) {
        save_calls(c_p, ep);
      } else {
        goto context_switch;
      }
    }

    FCALLS--;
    Goto(dis_next);
  } while (0);ASSERT(!"Fell through 'i_call_ext_last' (-no_next)");
}

Export导出结构和erts_active_code_ix激活代码地址索引是我们想要了解的

两个代码相关的核心模块

erts_code_purger.erl

清理接口主要检测是否有进程正在占用当前代码

清理主要分两步,prepare和abort/complete

硬清理和软清理区别在于是否终止正在使用此代码的进程

code.erl

两个核心函数

erlang:prepare_loading/2

加载阶段主要就是检查字节码有效性并加载到内存中

erlang:finish_loading/1

代码beam_make_current_old是把当前数据移动到旧数据

代码export_list正是导出函数功能

代码trampoline是切换暂存地址到激活地址

同一个模块有两份数据,一份正在(激活)使用,一份旧(副本)数据。如果旧数据正在被进程占用,soft_purge不能清理旧代码,也就说无法进行热更新新的代码

发表评论