标签:
send_generic_cmd(Socket, Cmd) -> gen_tcp:send(Socket, <<Cmd/binary, "\r\n">>), Reply = recv_simple_reply(), Reply. recv_simple_reply() -> receive {tcp,_,Data} -> string:tokens(binary_to_list(Data), "\r\n"); {error, closed} -> connection_closed after ?TIMEOUT -> timeout end. |
send(S, Data, OptList) when is_port(S), is_list(OptList) -> try erlang:port_command(S, Data, OptList) of false -> % Port busy and nosuspend option passed {error,busy}; true -> receive {inet_reply,S,Status} -> Status end catch error:_Error -> {error,einval} end. |
选择性接收: receive {ok, Result} -> Result end. 非选择性接收: receive Info -> Info end. |
getkey | getkey | getkey | ... | getkey | {tcp,_,Data} | ... |
getkey | getkey | {tcp,_,Data} | ... |
When there is no way to match a given message, it is put in a save queue and the next message is tried. If the second message matches, the first message is put back on top of the mailbox to be retried later. |
-module(test). -compile(export_all). t() -> receive ok -> ok end. |
1> c(test). {ok,test} 2> erts_debug:df(test). ok |
04BE84B0: i_func_info_IaaI 0 test t 0 04BE84C4: i_loop_rec_fr f(04BE84EC) x(0) 04BE84CC: i_is_eq_exact_immed_frc f(04BE84E4) x(0) ok 04BE84D8: remove_message 04BE84DC: move_return_cr ok x(0) 04BE84E4: loop_rec_end_f test:t/0 04BE84EC: wait_locked_f test:t/0 |
i_loop_rec_fr | receive接收信息,如果有信息放到 x(0) 寄存器,继续下一条指令;没有消息就跳到地址 04BE84EC,即 wait_locked_f |
i_is_eq_exact_immed_frc | 匹配 x(0)寄存器的值和ok是否相等,如果相等继续下一条指令;否则跳到04BE84E4,即 loop_rec_end_f |
remove_message | 移除进程消息队列中“当前”的信息(也就是上一行匹配到的信息) |
move_return_cr | 将 ok 送到 x(0)寄存器并返回结果 |
loop_rec_end_f | 将“当前消息”指针指向下一个位置,如果指向位置有消息,则跳到test:t/0第一段代码地址继续执行,即 04BE84C4;否则继续执行下一条指令 04BE84EC,即 wait_locked_f |
wait_locked_f | 阻塞当前进程,等待下一次调度,再检查是否有新的消息到达 |
/* * beam_emu.c process_main() 线程入口函数,实现VM调度 * 以下截取 i_loop_rec_fr 处理过程 * 作用是从信箱取出一条消息放到 x(0) 寄存器;没消息则跳到 wait或者 wait_timeout指令 */ OpCase(i_loop_rec_fr): { BeamInstr *next; ErlMessage* msgp; loop_rec__: PROCESS_MAIN_CHK_LOCKS(c_p); // 取出“当前位置”的消息 msgp = PEEK_MESSAGE(c_p); if (!msgp) { //如果消息不存在,尝试从SMP下public queue获取消息 #ifdef ERTS_SMP erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); if (ERTS_PROC_PENDING_EXIT(c_p)) { // 如果进程准备退出,则不处理消息了 erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); SWAPOUT; goto do_schedule; // 等待下一次调度 } // SMP下把消息移到进程私有堆尾部(纯指针操作) ERTS_SMP_MSGQ_MV_INQ2PRIVQ(c_p); // 再尝试取出“当前位置”的消息 msgp = PEEK_MESSAGE(c_p); if (msgp) erts_smp_proc_unlock(c_p, ERTS_PROC_LOCKS_MSG_RECEIVE); else #endif { // 信箱没消息则跳到 wait或者 wait_timeout指令(实际上就是执行下一条执行) SET_I((BeamInstr *) Arg(0)); Goto(*I); } } // 解析分布式消息,把消息附加的数据复制到进程私有堆 ErtsMoveMsgAttachmentIntoProc(msgp, c_p, E, HTOP, FCALLS, { SWAPOUT; reg[0] = r(0); PROCESS_MAIN_CHK_LOCKS(c_p); }, { ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); r(0) = reg[0]; SWAPIN; }); if (is_non_value(ERL_MESSAGE_TERM(msgp))) { /* * 如果消息损坏就移除(出现这种情况是分布式消息解码出现错误) */ ASSERT(!msgp->data.attached); UNLINK_MESSAGE(c_p, msgp); // 移除消息,侧重将“当前”位置指向下一条消息 free_message(msgp); // 销毁消息 goto loop_rec__; // 跳到上面继续 } PreFetch(1, next); // 标记下一条指令位置 r(0) = ERL_MESSAGE_TERM(msgp); NextPF(1, next); // 执行下一条指令 }来看下这两个宏定义:
/* Get "current" message */ #define PEEK_MESSAGE(p) (*(p)->msg.save)从字面上就知道这个宏是取"当前的"消息,取了 msg.save 的值
#define UNLINK_MESSAGE(p,msgp) do { ErlMessage* __mp = (msgp)->next; *(p)->msg.save = __mp; (p)->msg.len--; if (__mp == NULL) (p)->msg.last = (p)->msg.save; (p)->msg.mark = 0; } while(0)这个宏就是移除消息操作,消息队列长度-1,把 msg.save 指向了 msgp的下一条消息;如果 msgp->next 为 NULL,表示这是最后一条消息,就把 msg.last 等于了 msg.save
/* * beam_emu.c process_main() 线程入口函数,实现VM调度 * 以下截取 remove_message 处理过程(已删除不必要的代码) * 作用是将消息从信箱队列中移除 */ OpCase(remove_message): { BeamInstr *next; ErlMessage* msgp; PROCESS_MAIN_CHK_LOCKS(c_p); PreFetch(0, next); msgp = PEEK_MESSAGE(c_p); // 取出当前的消息 if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)) { save_calls(c_p, &exp_receive); } if (ERL_MESSAGE_TOKEN(msgp) == NIL) { SEQ_TRACE_TOKEN(c_p) = NIL; } else if (ERL_MESSAGE_TOKEN(msgp) != am_undefined) { // 追踪调试内容,可以忽略 Eterm msg; SEQ_TRACE_TOKEN(c_p) = ERL_MESSAGE_TOKEN(msgp); c_p->seq_trace_lastcnt = unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p)); if (c_p->seq_trace_clock < unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p))) { c_p->seq_trace_clock = unsigned_val(SEQ_TRACE_TOKEN_SERIAL(c_p)); } msg = ERL_MESSAGE_TERM(msgp); seq_trace_output(SEQ_TRACE_TOKEN(c_p), msg, SEQ_TRACE_RECEIVE, c_p->common.id, c_p); } UNLINK_MESSAGE(c_p, msgp); // 移除消息,侧重队列长度-1 JOIN_MESSAGE(c_p); // 重置“当前”位置,指向了队列第一条消息 CANCEL_TIMER(c_p); free_message(msgp); // 销毁消息 ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p); PROCESS_MAIN_CHK_LOCKS(c_p); NextPF(0, next); // 执行下一条指令 }所以,当消息匹配时,就会重新指向了信箱第一条消息,这样,第3个问题就有了答案,会重新扫描信箱。
/* Reset message save point (after receive match) */ #define JOIN_MESSAGE(p) (p)->msg.save = &(p)->msg.first这个宏就是讲 msg.save 指向了 msg.first ,就是第一个消息
/* * beam_emu.c process_main() 线程入口函数,实现VM调度 * 以下截取 loop_rec_end_f 处理过程 * 作用是继续取出最新的消息匹配 */ /* * Advance the save pointer to the next message (the current * message didn‘t match), then jump to the loop_rec instruction. */ OpCase(loop_rec_end_f): { SET_I((BeamInstr *) Arg(0)); SAVE_MESSAGE(c_p); // “当前”位置指向下一个位置 goto loop_rec__; // 继续取出消息匹配 }这个opcode实现了不断取消息出来匹配的过程,直到失去调度机会,等待下一次调度。
/* Save current message */ #define SAVE_MESSAGE(p) (p)->msg.save = &(*(p)->msg.save)->next这个宏就是将 msg.save 指向了下一个位置。
标签:
原文地址:http://blog.csdn.net/mycwq/article/details/44049749