Analyze the implementation of erlang process monitoring and erlang Process Monitoring

Source: Internet
Author: User

Analyze the implementation of erlang process monitoring and erlang Process Monitoring
Erlang supports two monitoring methods: Monitor and Link, so that all processes can be integrated. When a process exits due to an error, the monitoring process receives a message indicating that the process exits. With these features, using Erlang to build a simple and robust system is not difficult. The previous article analyzed the usage of the two methods. Here we will analyze the implementation of monitor and link.
Source code analysis: the implementation of monitor and link is similar. The following uses monitor as an example to describe the implementation of erlang: monitor/2 (erlang R16B02 ).

// Bif. c implementation erlang: monitor/2BIF_RETTYPE monitor_2 (BIF_ALIST_2) {Eterm target = BIF_ARG_2; BIF_RETTYPE ret; DistEntry * dep = NULL; int deref_de = 0;/* currently only erlang: monitor (process, Target) */if (BIF_ARG_1! = Am_process) {goto error;} if (is_internal_pid (target) {// if it is the local node process local_pid: ret = local_pid_monitor (BIF_P, target ); // process the current node process} else if (is_external_pid (target) {// if it is another node process dep = external_pid_dist_entry (target); if (dep = erts_this_dist_entry) // if the process belongs to the current node, jump to the current node to process goto local_pid; ret = remote_monitor (BIF_P, BIF_ARG_1, BIF_ARG_2, dep, target, 0 ); // process other node processes} else if (is_atom (target )){ // Target is atom processing ret = local_name_monitor (BIF_P, target);} else if (is_tuple (target) {// Target is tuple processing Eterm * tp = tuple_val (target ); eterm remote_node; Eterm name; if (arityval (* tp )! = 2) goto error; remote_node = tp [2]; name = tp [1]; if (! Is_atom (remote_node) |! Is_atom (name) {goto error;} if (! Erts_is_alive & remote_node! = Am_Noname) {goto error;/* Remote monitor from (this) undistributed node */} dep = partition (remote_node); if (dep = erts_this_dist_entry) {deref_de = 1; ret = local_name_monitor (BIF_P, name);} else {if (dep) deref_de = 1; ret = remote_monitor (BIF_P, BIF_ARG_1, BIF_ARG_2, dep, name, 1 );}} else {error: ERTS_BIF_PREP_ERROR (ret, BIF_P, BADARG);} if (deref_de) {deref_de = 0; erts_deref_dist_entry (dep);} return ret ;}
Now, let's take a look at the monitoring process of the current node process:
// Bif. c. Implement local node Process Monitoring and Handling static BIF_RETTYPE local_pid_monitor (Process * p, Eterm target) {BIF_RETTYPE ret; Eterm mon_ref; Process * rp; ErtsProcLocks p_locks = ERTS_PROC_LOCK_MAIN | unlock; mon_ref = erts_make_ref (p); ERTS_BIF_PREP_RET (ret, mon_ref); if (target = p-> common. id) {// if the process monitors its own return ret;} erts_smp_proc_lock (p, ERTS_PROC_LOCK_LINK); // lock the process link operation to avoid dirty write of Process Monitoring Data rp = erts_pid2proc_o Pt (p, p_locks, target, ERTS_PROC_LOCK_LINK, // the same link lock ERTS_P2P_FLG_ALLOW_OTHER_X); if (! Rp) {erts_smp_proc_unlock (p, ERTS_PROC_LOCK_LINK); p_locks & = ~ ERTS_PROC_LOCK_LINK; erts_queue_monitor_message (p, & p_locks, mon_ref, am_process, target, am_noproc);} else {ASSERT (rp! = P); // the current process adds the monitoring data erts_add_monitor (& ERTS_P_MONITORS (p), MON_ORIGIN, mon_ref, target, NIL ); // Add the monitored data erts_add_monitor (& ERTS_P_MONITORS (rp), MON_TARGET, mon_ref, p-> common to the target process. id, NIL); erts_smp_proc_unlock (rp, ERTS_PROC_LOCK_LINK);} erts_smp_proc_unlock (p, p_locks &~ ERTS_PROC_LOCK_MAIN); return ret ;}
In fact, only the monitoring data of the process is modified here, and both the monitor and the monitored data are copied. Let's take a look at the implementation of erts_add_monitor:
// The erl_monitors.c implementation process adds the monitoring information void erts_add_monitor (ErtsMonitor ** root, Uint type, Eterm ref, Eterm pid, Eterm name) {void * tstack [STACK_NEED]; int tpos = 0; int dstack [STACK_NEED + 1]; int dpos = 1; int state = 0; ErtsMonitor ** this = root; Sint c; dstack [0] = DIR_END; for (;) {if (! * This) {/* Found our place */state = 1; * this = create_monitor (type, ref, pid, name); break ;} else if (c = CMP_MON_REF (ref, (* this)-> ref) <0) {/* go left */dstack [dpos ++] = DIR_LEFT; tstack [tpos ++] = this; this = & (* this)-> left);} else if (c> 0) {/* go right */dstack [dpos ++] = DIR_RIGHT; tstack [tpos ++] = this; this = & (* this)-> right );} else {/* Equal key is an error for monitors */erl_exi T (1, "Insertion of already present monitor! "); Break ;}} insertion_rotation (dstack, dpos, tstack, tpos, state );}
Let's take a look at this macro and take the monitoring data of the process structure. That is to say, each process has a monitoring data that records the monitoring and monitored information and is saved as an AVL tree structure.
#define ERTS_P_MONITORS(P)((P)->common.u.alive.monitors)

In the previous analysis of process monitoring, the monitoring process is only marked by the monitored process. What should I do when the process exits?
// Erl_monitor.c triggers all monitors (traversing the monitor data and executing the doit function callback) void erts_sweep_monitors (ErtsMonitor * root, void (* doit) (ErtsMonitor *, void *), void * context) {ErtsMonitor * tstack [STACK_NEED]; int tpos = 0; int dstack [STACK_NEED + 1]; int dpos = 1; int dir; dstack [0] = DIR_END; for (;) {if (root = NULL) {if (dir = dstack [dpos-1]) = DIR_END) {return;} if (dir = DIR_LEFT) {/* Still has DIR_RIGHT to do */dstack [dpos-1] = DIR_RIGHT; root = (tstack [tpos-1])-> right ;} else {/* stacktop is an object to be deleted */(* doit) (tstack [-- tpos], context); // execute callback -- dpos; root = NULL ;}} else {dstack [dpos ++] = DIR_LEFT; tstack [tpos ++] = root; root = root-> left ;}}}
When will the monitoring callback be triggered? 1. Process disabling 2. Distributed port disabling
The above will trigger the monitoring callback. Here we will describe the process shutdown:
// Erl_process.c Process close processing (with strikethrough) void erts_continue_exit_process (Process * p ){//... mon = ERTS_P_MONITORS (p); lnk = ERTS_P_LINKS (p );//... if (lnk) {// link processing DeclareTmpHeap (tmp_heap, 4, p); Eterm exit_tuple; Uint exit_tuple_sz; Eterm * hp; UseTmpHeap (4, p ); hp = & tmp_heap [0]; exit_tuple = TUPLE3 (hp, am_EXIT, p-> common. id, reason); region = size_object (exit_tuple); {ExitLinkContext context = {p, reason, exit_tuple, callback}; erts_sweep_links (lnk, & doit_exit_link, & context );} unUseTmpHeap (4, p) ;}{// monitor processing ExitMonitorContext context = {reason, p}; erts_sweep_monitors (mon, & doit_exit_monitor, & context);/* Allocates TmpHeap, but we have none here */}//...}
Check the processing of the callback function in the above Code.
// The erl_process.c Process disables monitoring and processes static void Merge (ErtsMonitor * mon, void * vpcontext) {ExitMonitorContext * pcontext = vpcontext; DistEntry * dep; ErtsMonitor * rmon; Process * rp; if (mon-> type = MON_ORIGIN) {// if the process monitors other processes, delete the monitored information of other processes/* We are monitoring someone else, we need to demonitor that one .. */if (is_atom (mon-> pid) {/* remote by name */ASSERT (is_node_name_atom (mon-> pid); dep = erts _ Sysname_to_connected_dist_entry (mon-> pid); if (dep) {// if the process monitors the remote node process erts_smp_de_links_lock (dep ); // Delete the DistEntry monitoring information rmon = erts_remove_monitor (& (dep-> monitors), mon-> ref); erts_smp_de_links_unlock (dep); if (rmon) {// then notify the remote node to remove the monitored information ErtsDSigData dsd; int code = erts_dsig_prepare (& dsd, dep, NULL, ERTS_DSP_NO_LOCK, 0); if) {code = erts_dsig_send_demonitor (& dsd, rm On-> pid, mon-> name, mon-> ref, 1); ASSERT (code = ERTS_DSIG_SEND_ OK);} erts_destroy_monitor (rmon);} erts_deref_dist_entry (dep );}} else {ASSERT (is_pid (mon-> pid); if (is_internal_pid (mon-> pid) {// if the node process rp = erts_pid2proc (NULL, 0, mon-> pid, ERTS_PROC_LOCK_LINK); if (! Rp) {goto done;} // Delete monitoring information of monitored processes rmon = erts_remove_monitor (& ERTS_P_MONITORS (rp), mon-> ref); erts_smp_proc_unlock (rp, ERTS_PROC_LOCK_LINK ); if (rmon = NULL) {goto done;} erts_destroy_monitor (rmon);} else {/* remote by pid */ASSERT (is_external_pid (mon-> pid )); dep = external_pid_dist_entry (mon-> pid); ASSERT (dep! = NULL); if (dep) {erts_smp_de_links_lock (dep); // Delete the DistEntry monitoring information rmon = erts_remove_monitor (& (dep-> monitors), mon-> ref ); destroy (dep); if (rmon) {// then notify the remote node to remove the monitored information ErtsDSigData dsd; int code = erts_dsig_prepare (& dsd, dep, NULL, ERTS_DSP_NO_LOCK, 0 ); if (code = ERTS_DSIG_PREP_CONNECTED) {code = erts_dsig_send_demonitor (& dsd, rmon-> pid, mon-> pid, mon-> ref, 1); ASSERT (code = ERTS _ DSIG_SEND_ OK);} erts_destroy_monitor (rmon) ;}}} else {// if a process monitors the process, the monitoring process ASSERT (mon-> type = MON_TARGET) is notified ); ASSERT (is_pid (mon-> pid) | is_internal_port (mon-> pid); if (is_internal_port (mon-> pid )) {// if the monitoring process is the current node Port * prt = erts_id2port (mon-> pid); if (prt = NULL) {goto done;} erts_fire_port_monitor (prt, mon-> ref); erts_port_release (prt);} else if (is_internal_pid (mon-> pid) {// if the monitoring process is a local node Process Eterm watched; blocks (lhp, 3); ErtsProcLocks rp_locks = (ERTS_PROC_LOCK_LINK | blocks); rp = erts_pid2proc (NULL, 0, mon-> pid, rp_locks ); if (rp = NULL) {goto done;} UseTmpHeapNoproc (3); // remove the monitoring information of the monitoring process rmon = erts_remove_monitor (& ERTS_P_MONITORS (rp ), mon-> ref); if (rmon) {erts_destroy_monitor (rmon); watched = (is_atom (mon-> name )? TUPLE2 (lhp, mon-> name, erts_this_dist_entry-> sysname): pcontext-> p-> common. id); // then, the process closing information is sent to the monitoring process {'down ', Ref, process, Pid, Reason} erts_queue_monitor_message (rp, & rp_locks, mon-> ref, am_process, watched, pcontext-> reason);} UnUseTmpHeapNoproc (3);/* else: demonitor while we exited, I. e. do nothing... */erts_smp_proc_unlock (rp, rp_locks);} else {// If the monitored process is a remote node process ASSERT (is_external_pid (mon-> pid ); Dep = external_pid_dist_entry (mon-> pid); ASSERT (dep! = NULL); if (dep) {erts_smp_de_links_lock (dep); // Delete the DistEntry monitoring information rmon = erts_remove_monitor (& (dep-> monitors), mon-> ref ); terminate (dep); if (rmon) {// then notify the remote node that the process exits. ErtsDSigData dsd; int code = erts_dsig_prepare (& dsd, dep, NULL, ERTS_DSP_NO_LOCK, 0 ); if (code = ERTS_DSIG_PREP_CONNECTED) {code = erts_dsig_send_m_exit (& dsd, mon-> pid, (rmon-> name! = NIL? Rmon-> name: rmon-> pid), mon-> ref, pcontext-> reason); ASSERT (code = ERTS_DSIG_SEND_ OK);} erts_destroy_monitor (rmon );}}}} done:/* As the monitors are previusly removed from the process, distribution operations will not cause monitors to disappear, we can safely delete it. */erts_destroy_monitor (mon );}


The implementation of cross-node Process Monitoring refers to the processing of the current node. How is cross-node Process Monitoring implemented? What is the difference?
// Bif. c cross-node Process Monitoring processing static BIF_RETTYPE remote_monitor (Process * p, Eterm bifarg1, Eterm bifarg2, DistEntry * dep, Eterm target, int byname) {ErtsDSigData dsd; BIF_RETTYPE ret; int code; erts_smp_proc_lock (p, ERTS_PROC_LOCK_LINK); code = erts_dsig_prepare (& dsd, dep, p, ERTS_DSP_RLOCK, 0); // get the status switch (code) of the distributed Port) {case ERTS_DSIG_PREP_NOT_ALIVE: // the port is not activated yet. Use Trap to process/* Let the dmonitor_p trap handle It */case when: // The port is not connected. Use Trap to process erts_smp_proc_unlock (p, ERTS_PROC_LOCK_LINK); Forward (ret, dmonitor_p_trap, p, bifarg1, bifarg2 ); // use Trap to process data. In the next scheduling, call erlang: dmonitor_p/2 break; case ERTS_DSIG_PREP_CONNECTED: // The port is connected and data can be sent if (! (Dep-> flags & DFLAG_DIST_MONITOR) | (byname &&! (Dep-> flags & tags) {values (dep); values (p, ERTS_PROC_LOCK_LINK); ERTS_BIF_PREP_ERROR (ret, p, BADARG);} else {Eterm p_trgt, p_name, d_name, mon_ref; mon_ref = erts_make_ref (p); if (byname) {p_trgt = dep-> sysname; p_name = target; d_name = target;} else {p_trgt = target; p_name = NIL; d_name = NIL;} erts_smp_de_links_lock (dep); // Add monitoring data erts_add_mon to the current process Itor (& ERTS_P_MONITORS (p), MON_ORIGIN, mon_ref, p_trgt, p_name); // DistEntry add monitored data erts_add_monitor (& (dep-> monitors), MON_TARGET, mon_ref, p-> common. id, d_name); Second (dep); erts_smp_proc_unlock (p, ERTS_PROC_LOCK_LINK); // send a monitoring message to the remote node code = erts_dsig_send_monitor (& dsd, p-> common. id, target, mon_ref); if (code = ERTS_DSIG_SEND_YIELD) ERTS_BIF_PREP_YIELD_R ETURN (ret, p, mon_ref); elseERTS_BIF_PREP_RET (ret, mon_ref);} break; default: // other port statuses, such as the port will be suspended ASSERT (! "Invalid dsig prepare result"); ERTS_BIF_PREP_ERROR (ret, p, EXC_INTERNAL_ERROR); break;} return ret ;}
Next, let's see how to process the message sent to a remote node.
// Dist. c send monitoring messages to remote node int erts_dsig_send_monitor (ErtsDSigData * dsdp, Eterm watcher, Eterm watched, Eterm ref) {Eterm ctl; DeclareTmpHeapNoproc (ctl_heap, 5); int res; messages (5); ctl = TUPLE4 (& ctl_heap [0], make_small (DOP_MONITOR_P), watcher, watched, ref); // construct the message {DOP_MONITOR_P, LocalPid, RemotePidOrName, ref} Send to remote node res = dsig_send (dsdp, ctl, THE_NON_VALUE, 0); UnUseTmpHeapNoproc (5); return res ;}
Check the processing after the message is received remotely.
// Dist. c. process messages sent from other nodes (with deletions) int erts_net_message (Port * prt, DistEntry * dep, byte * hbuf, ErlDrvSizeT hlen, byte * buf, ErlDrvSizeT len) {//... switch (type = unsigned_val (tuple [1]) {//... // process {DOP_MONITOR_P, Remote pid, local pid or name, ref} case DOP_MONITOR_P: {/* A remote process wants to monitor us, we get: {DOP_MONITOR_P, Remote pid, local pid or name, ref} */Eterm name; if (tuple_arity! = 4) {goto invalid_message;} watcher = tuple [2]; watched = tuple [3];/* local proc to monitor */ref = tuple [4]; if (is_not_ref (ref) {goto invalid_message;} if (is_atom (watched) {name = watched; rp = callback (NULL, 0, watched, ERTS_PROC_LOCK_LINK, callback );} else {name = NIL; rp = erts_pid2proc_opt (NULL, 0, watched, ERTS_PROC_LOCK_LINK, ERTS_P2P_FLG_ALLOW_OTHER_X);} if (! Rp) {// If the monitored process does not exist, the ErtsDSigData dsd; int code; code = erts_dsig_prepare (& dsd, dep, NULL, ERTS_DSP_NO_LOCK, 0) is returned ); if (code = ERTS_DSIG_PREP_CONNECTED) {code = erts_dsig_send_m_exit (& dsd, watcher, watched, ref, am_noproc); ASSERT (code = ERTS_DSIG_SEND_ OK );}} else {if (is_atom (watched) watched = rp-> common. id; erts_smp_de_links_lock (dep); // DistEntry add monitoring data erts_add_monitor (& (dep-> monitors), MON_ORIGIN, ref, watched, name ); // process add monitored data erts_add_monitor (& ERTS_P_MONITORS (rp), MON_TARGET, ref, watcher, name); terminate (dep); terminate (rp, ERTS_PROC_LOCK_LINK);} break ;} //...}

Compare local and cross-node ProcessingProcess Monitoring on this node is as follows: (process X monitoring process Y)
/********************************************************************** *        Process X          Process Y *       +-------------+    +-------------+ * Type: | MON_ORIGIN  |    | MON_TARGET  | *       +-------------+    +-------------+ * Pid:  | Pid(Y)      |    | Pid(X)      | *       +-------------+    +-------------+ **********************************************************************/
Cross-node processing: (process X of node A monitors process Y of Node B)
/********************************************************************** *                    Node A              |           Node B *       ---------------------------------+---------------------------------- *        Process X (@A)   Distentry @A       Distentry @B     Process Y (@B) *                         for node B         for node A        *       +-------------+  +-------------+    +-------------+  +-------------+ * Type: | MON_ORIGIN  |  | MON_TARGET  |    | MON_ORIGIN  |  | MON_TARGET  | *       +-------------+  +-------------+    +-------------+  +-------------+ * Pid:  | Atom(node B)|  | Pid(X)      |    | Pid(Y)      |  | Pid(X)      | *       +-------------+  +-------------+    +-------------+  +-------------+ **********************************************************************/
The comparison involves One step more DistEntry processing, which is determined by the instability of the Cross-node network. A remote process exception may occur because the process is down or the node connection fails. When a remote node encounters an exception, the associated process of the node is triggered.

Summary from the above analysis, we can understand that process monitoring only marks the monitored process, and then processes all the monitored processes when the monitored process encounters an exception.

Reference: http://blog.csdn.net/mycwq/article/details/46961489

Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.