1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 2001-2011. All Rights Reserved.
    5: %% 
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %% 
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %% 
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: %%%----------------------------------------------------------------------
   21: %%% File    : erl_link_SUITE.erl
   22: %%% Author  : Rickard Green <rickard.green@uab.ericsson.se>
   23: %%% Purpose : Test erlang links
   24: %%% Created : 13 Dec 2001 by Rickard Green <rickard.green@uab.ericsson.se>
   25: %%%----------------------------------------------------------------------
   26: 
   27: -module(erl_link_SUITE).
   28: -author('rickard.green@uab.ericsson.se').
   29: 
   30: %-define(line_trace, 1).
   31: -include_lib("test_server/include/test_server.hrl").
   32: 
   33: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   34: 	 init_per_group/2,end_per_group/2]).
   35: 
   36: % Test cases
   37: -export([links/1,
   38: 	 dist_links/1,
   39: 	 monitor_nodes/1,
   40: 	 process_monitors/1,
   41: 	 dist_process_monitors/1,
   42: 	 busy_dist_port_monitor/1,
   43: 	 busy_dist_port_link/1,
   44: 	 otp_5772_link/1,
   45: 	 otp_5772_dist_link/1,
   46: 	 otp_5772_monitor/1,
   47: 	 otp_5772_dist_monitor/1,
   48: 	 otp_7946/1]).
   49: 
   50: -export([init_per_testcase/2, end_per_testcase/2]).
   51: 
   52: % Internal exports
   53: -export([test_proc/0]).
   54: 
   55: 
   56: -define(LINK_UNDEF, 0).
   57: -define(LINK_PID,   1).
   58: -define(LINK_NODE,  3).
   59: 
   60: 
   61: % These are to be kept in sync with erl_monitors.h 
   62: -define(MON_ORIGIN, 1).
   63: -define(MON_TARGET, 3).
   64: 
   65: 
   66: -record(erl_link, {type = ?LINK_UNDEF,
   67: 		   pid = [],
   68: 		   targets = []}).
   69: 
   70: % This is to be kept in sync with erl_bif_info.c (make_monitor_list)
   71: 
   72: -record(erl_monitor, {
   73:             type, % MON_ORIGIN or MON_TARGET (1 or 3)
   74: 	    ref,
   75: 	    pid, % Process or nodename
   76: 	    name = [] % registered name or []
   77:           }).
   78: 
   79: 
   80: 
   81: suite() -> [{ct_hooks,[ts_install_cth]}].
   82: 
   83: all() -> 
   84:     [links, dist_links, monitor_nodes, process_monitors,
   85:      dist_process_monitors, busy_dist_port_monitor,
   86:      busy_dist_port_link, otp_5772_link, otp_5772_dist_link,
   87:      otp_5772_monitor, otp_5772_dist_monitor, otp_7946].
   88: 
   89: groups() -> 
   90:     [].
   91: 
   92: init_per_suite(Config) ->
   93:     Config.
   94: 
   95: end_per_suite(_Config) ->
   96:     catch erts_debug:set_internal_state(available_internal_state, false).
   97: 
   98: init_per_group(_GroupName, Config) ->
   99:     Config.
  100: 
  101: end_per_group(_GroupName, Config) ->
  102:     Config.
  103: 
  104: 
  105: links(doc) -> ["Tests node local links"];
  106: links(suite) -> [];
  107: links(Config) when is_list(Config) ->
  108:     ?line common_link_test(node(), node()),
  109:     ?line true = link(self()),
  110:     ?line [] = find_erl_link(self(), ?LINK_PID, self()),
  111:     ?line true = unlink(self()),
  112:     ?line ok.
  113: 
  114: dist_links(doc) -> ["Tests distributed links"];
  115: dist_links(suite) -> [];
  116: dist_links(Config) when is_list(Config) ->
  117:     ?line [NodeName] = get_names(1, dist_link),
  118:     ?line {ok, Node} = start_node(NodeName),
  119:     ?line common_link_test(node(), Node),
  120:     ?line TP4 = spawn(?MODULE, test_proc, []),
  121:     ?line TP5 = spawn(?MODULE, test_proc, []),
  122:     ?line TP6 = spawn(Node, ?MODULE, test_proc, []),
  123:     ?line true = tp_call(TP6, fun() -> link(TP4) end),
  124:     ?line check_link(TP4, TP6),
  125:     ?line true = tp_call(TP5,
  126: 			 fun() ->
  127: 				 process_flag(trap_exit,true),
  128: 				 link(TP6)
  129: 			 end),
  130:     ?line check_link(TP5, TP6),
  131:     ?line rpc:cast(Node, erlang, halt, []),
  132:     ?line wait_until(fun () -> ?line is_proc_dead(TP4) end),
  133:     ?line check_unlink(TP4, TP6),
  134:     ?line true = tp_call(TP5,
  135: 			 fun() ->
  136: 				 receive
  137: 				     {'EXIT', TP6, noconnection} ->
  138: 					 true
  139: 				 end
  140: 			 end),
  141:     ?line check_unlink(TP5, TP6),
  142:     ?line tp_cast(TP5, fun() -> exit(normal) end),
  143:     ?line ok.
  144: 
  145: common_link_test(NodeA, NodeB) ->
  146:     ?line TP1 = spawn(NodeA, ?MODULE, test_proc, []),
  147:     ?line check_unlink(TP1, self()),
  148:     ?line TP2 = tp_call(TP1,
  149: 			fun () ->
  150: 				spawn_link(NodeB, ?MODULE, test_proc, [])
  151: 			end),
  152:     ?line check_link(TP1, TP2),
  153:     ?line true = tp_call(TP2, fun() -> unlink(TP1) end),
  154:     ?line check_unlink(TP1, TP2),
  155:     ?line true = tp_call(TP2, fun() -> link(TP1) end),
  156:     ?line check_link(TP1, TP2),
  157:     ?line false = tp_call(TP2, fun() -> process_flag(trap_exit, true) end),
  158:     ?line tp_cast(TP1, fun () -> exit(died) end),
  159:     ?line true = tp_call(TP2, fun() ->
  160: 				      receive 
  161: 					  {'EXIT', TP1, died} ->
  162: 					      true
  163: 				      end
  164: 			      end),
  165:     ?line check_unlink(TP1, TP2),
  166:     ?line TP3 = tp_call(TP2,
  167: 			fun () ->
  168: 				spawn_link(NodeA, ?MODULE, test_proc, [])
  169: 			end),
  170:     ?line check_link(TP3, TP2),
  171:     ?line tp_cast(TP2, fun() -> exit(died) end),
  172:     ?line wait_until(fun () -> ?line is_proc_dead(TP3) end),
  173:     ?line check_unlink(TP3, TP2),
  174:     ?line ok.
  175: 
  176: monitor_nodes(doc) -> ["Tests monitor of nodes"];
  177: monitor_nodes(suite) -> [];
  178: monitor_nodes(Config) when is_list(Config) ->
  179:     ?line [An, Bn, Cn, Dn] = get_names(4, dist_link),
  180:     ?line {ok, A} = start_node(An),
  181:     ?line {ok, B} = start_node(Bn),
  182:     ?line C = list_to_atom(lists:concat([Cn, "@", hostname()])),
  183:     ?line D = list_to_atom(lists:concat([Dn, "@", hostname()])),
  184:     ?line 0 = no_of_monitor_node(self(), A),
  185:     ?line 0 = no_of_monitor_node(self(), B),
  186:     ?line monitor_node(A, true),
  187:     ?line monitor_node(B, true),
  188:     ?line monitor_node(D, true),
  189:     ?line monitor_node(D, true),
  190: 
  191:     %% Has been known to crash the emulator.
  192:     ?line {memory,_} = process_info(self(), memory),
  193: 
  194:     ?line monitor_node(A, false),
  195:     ?line monitor_node(B, true),
  196:     ?line monitor_node(C, true),
  197:     ?line monitor_node(C, false),
  198:     ?line monitor_node(C, true),
  199:     ?line monitor_node(B, true),
  200:     ?line monitor_node(A, false),
  201:     ?line monitor_node(B, true),
  202:     ?line monitor_node(B, false),
  203:     ?line monitor_node(A, true),
  204:     ?line check_monitor_node(self(), A, 1),
  205:     ?line check_monitor_node(self(), B, 3),
  206:     ?line check_monitor_node(self(), C, 0),
  207:     ?line check_monitor_node(self(), D, 0),
  208:     ?line receive {nodedown, C} -> ok end,
  209:     ?line receive {nodedown, C} -> ok end,
  210:     ?line receive {nodedown, C} -> ok end,
  211:     ?line receive {nodedown, D} -> ok end,
  212:     ?line receive {nodedown, D} -> ok end,
  213:     ?line stop_node(A),
  214:     ?line receive {nodedown, A} -> ok end,
  215:     ?line check_monitor_node(self(), A, 0),
  216:     ?line check_monitor_node(self(), B, 3),
  217:     ?line stop_node(B),
  218:     ?line receive {nodedown, B} -> ok end,
  219:     ?line receive {nodedown, B} -> ok end,
  220:     ?line receive {nodedown, B} -> ok end,
  221:     ?line check_monitor_node(self(), B, 0),
  222:     ?line receive
  223: 	      {nodedown, X} ->
  224: 		  ?line ?t:fail({unexpected_nodedown, X})
  225: 	  after 0 ->
  226: 		  ?line ok
  227: 	  end,
  228:     ?line ok.
  229:     
  230: 
  231: process_monitors(doc) -> ["Tests node local process monitors"];
  232: process_monitors(suite) -> [];
  233: process_monitors(Config) when is_list(Config) ->
  234:     ?line common_process_monitors(node(), node()),
  235:     ?line Mon1 = erlang:monitor(process,self()),
  236:     ?line [] = find_erl_monitor(self(), Mon1),
  237:     ?line [Name] = get_names(1, process_monitors),
  238:     ?line true = register(Name, self()),
  239:     ?line Mon2 = erlang:monitor(process, Name),
  240:     ?line [] = find_erl_monitor(self(), Mon2),
  241:     ?line receive
  242: 	      {'DOWN', Mon1, _, _, _} = Msg ->
  243: 		  ?line ?t:fail({unexpected_down_msg, Msg});
  244: 	      {'DOWN', Mon2, _, _, _} = Msg ->
  245: 		  ?line ?t:fail({unexpected_down_msg, Msg})
  246: 	  after 500 ->
  247: 		  ?line true = erlang:demonitor(Mon1),
  248: 		  ?line true = erlang:demonitor(Mon2),
  249: 		  ?line ok
  250: 	  end.
  251: 
  252: dist_process_monitors(doc) -> ["Tests distributed process monitors"];
  253: dist_process_monitors(suite) -> [];
  254: dist_process_monitors(Config) when is_list(Config) -> 
  255:     ?line [Name] = get_names(1,dist_process_monitors),
  256:     ?line {ok, Node} = start_node(Name),
  257:     ?line common_process_monitors(node(), Node),
  258:     ?line TP1 = spawn(Node, ?MODULE, test_proc, []),
  259:     ?line R1 = erlang:monitor(process, TP1),
  260:     ?line TP1O = get_down_object(TP1, self()),
  261:     ?line check_process_monitor(self(), TP1, R1),
  262:     ?line tp_cast(TP1, fun () -> halt() end),
  263:     ?line receive
  264: 	      {'DOWN',R1,process,TP1O,noconnection} ->
  265: 		  ?line ok
  266: 	  end,
  267:     ?line check_process_demonitor(self(), TP1, R1),
  268:     ?line R2 = erlang:monitor(process, TP1),
  269:     ?line receive
  270: 	      {'DOWN',R2,process,TP1O,noconnection} ->
  271: 		  ?line ok
  272: 	  end,
  273:     ?line check_process_demonitor(self(), TP1, R2),
  274:     ?line ok.
  275: 
  276: 
  277: common_process_monitors(NodeA, NodeB) ->
  278:     ?line TP1 = spawn(NodeA, ?MODULE, test_proc, []),
  279:     ?line TP2 = spawn(NodeB, ?MODULE, test_proc, []),
  280:     ?line run_common_process_monitors(TP1, TP2),
  281:     ?line TP3 = spawn(NodeA, ?MODULE, test_proc, []),
  282:     ?line TP4 = spawn(NodeB, ?MODULE, test_proc, []),
  283:     ?line [TP4N] = get_names(1, common_process_monitors),
  284:     ?line true = tp_call(TP4, fun () -> register(TP4N,self()) end),
  285:     ?line run_common_process_monitors(TP3,
  286: 				      case node() == node(TP4) of
  287: 					  true -> TP4N;
  288: 					  false -> {TP4N, node(TP4)}
  289: 				      end),
  290:     ?line ok.
  291: 
  292: run_common_process_monitors(TP1, TP2) ->
  293:     ?line R1 = tp_call(TP1, fun () -> erlang:monitor(process, TP2) end),
  294:     ?line check_process_monitor(TP1, TP2, R1),
  295: 
  296:     ?line tp_call(TP2, fun () -> catch erlang:demonitor(R1) end),
  297:     ?line check_process_monitor(TP1, TP2, R1),
  298: 
  299:     ?line true = tp_call(TP1, fun () -> erlang:demonitor(R1) end),
  300:     ?line check_process_demonitor(TP1, TP2, R1),
  301: 
  302:     ?line R2 = tp_call(TP1, fun () -> erlang:monitor(process, TP2) end),
  303:     ?line TP2O = get_down_object(TP2, TP1),
  304:     ?line check_process_monitor(TP1, TP2, R2),
  305:     ?line tp_cast(TP2, fun () -> exit(bye) end),
  306:     ?line wait_until(fun () -> ?line is_proc_dead(TP2) end),
  307:     ?line ok = tp_call(TP1, fun () ->
  308: 				    ?line receive
  309: 					      {'DOWN',R2,process,TP2O,bye} ->
  310: 						  ?line ok
  311: 				    end
  312: 			    end),
  313:     ?line check_process_demonitor(TP1, TP2, R2),
  314:     
  315:     ?line R3 = tp_call(TP1, fun () -> erlang:monitor(process, TP2) end),
  316:     ?line ok = tp_call(TP1, fun () ->
  317: 				    ?line receive
  318: 					      {'DOWN',R3,process,TP2O,noproc} ->
  319: 						  ?line ok
  320: 				    end
  321: 			    end),
  322:     ?line check_process_demonitor(TP1, TP2, R3),
  323: 
  324:     ?line tp_cast(TP1, fun () -> exit(normal) end),
  325:     ?line wait_until(fun () -> ?line is_proc_dead(TP1) end),
  326:     ?line ok.
  327:     
  328: 
  329: busy_dist_port_monitor(doc) -> ["Tests distributed monitor/2, demonitor/1, "
  330: 				"and 'DOWN' message over busy distribution "
  331: 				"port"];
  332: busy_dist_port_monitor(suite) -> [];
  333: busy_dist_port_monitor(Config) when is_list(Config) ->
  334: 
  335:     ?line Tracer = case os:getenv("TRACE_BUSY_DIST_PORT") of
  336: 		       "true" -> start_busy_dist_port_tracer();
  337: 		       _ -> false
  338: 		   end,
  339: 
  340:     ?line [An] = get_names(1, busy_dist_port_monitor),
  341:     ?line {ok, A} = start_node(An),
  342:     ?line TP1 = spawn(A, ?MODULE, test_proc, []),
  343:     %% Check monitor over busy port
  344:     ?line M1 = suspend_on_busy_test(A,
  345: 				    "erlang:monitor(process, TP1)",
  346: 				    fun () -> erlang:monitor(process, TP1) end),
  347:     ?line check_process_monitor(self(), TP1, M1),
  348:     %% Check demonitor over busy port
  349:     ?line suspend_on_busy_test(A,
  350: 			       "erlang:demonitor(M1)",
  351: 			       fun () -> erlang:demonitor(M1) end),
  352:     ?line check_process_demonitor(self(), TP1, M1),
  353:     %% Check down message over busy port
  354:     ?line TP2 = spawn(?MODULE, test_proc, []),
  355:     ?line M2 = tp_call(TP1, fun () -> erlang:monitor(process, TP2) end),
  356:     ?line check_process_monitor(TP1, TP2, M2),
  357:     ?line Ref = make_ref(),
  358:     ?line Busy = make_busy(A, 1000),
  359:     ?line receive after 100 -> ok end,
  360:     ?line tp_cast(TP2, fun () -> exit(Ref) end),
  361:     ?line receive after 100 -> ok end,
  362:     ?line unmake_busy(Busy),
  363:     ?line Ref = tp_call(TP1, fun () ->
  364: 				     receive
  365: 					 {'DOWN', M2, process, TP2, Ref} ->
  366: 					     Ref
  367: 				     end
  368: 			     end),
  369:     ?line tp_cast(TP1, fun () -> exit(normal) end),
  370:     ?line stop_node(A),
  371:     ?line stop_busy_dist_port_tracer(Tracer),
  372:     ?line ok.
  373: 
  374: busy_dist_port_link(doc) -> ["Tests distributed link/1, unlink/1, and 'EXIT'",
  375: 			     " message over busy distribution port"];
  376: busy_dist_port_link(suite) -> [];
  377: busy_dist_port_link(Config) when is_list(Config) ->
  378:     ?line Tracer = case os:getenv("TRACE_BUSY_DIST_PORT") of
  379: 		       "true" -> start_busy_dist_port_tracer();
  380: 		       _ -> false
  381: 		   end,
  382: 
  383:     ?line [An] = get_names(1, busy_dist_port_link),
  384:     ?line {ok, A} = start_node(An),
  385:     ?line TP1 = spawn(A, ?MODULE, test_proc, []),
  386:     %% Check link over busy port
  387:     ?line suspend_on_busy_test(A,
  388: 			       "link(TP1)",
  389: 			       fun () -> link(TP1) end),
  390:     ?line check_link(self(), TP1),
  391:     %% Check unlink over busy port
  392:     ?line suspend_on_busy_test(A,
  393: 			       "unlink(TP1)",
  394: 			       fun () -> unlink(TP1) end),
  395:     ?line check_unlink(self(), TP1),
  396:     %% Check trap exit message over busy port
  397:     ?line TP2 = spawn(?MODULE, test_proc, []),
  398:     ?line ok = tp_call(TP1, fun () ->
  399: 				    process_flag(trap_exit, true),
  400: 				    link(TP2),
  401: 				    ok
  402: 			    end),
  403:     ?line check_link(TP1, TP2),
  404:     ?line Ref = make_ref(),
  405:     ?line Busy = make_busy(A, 1000),
  406:     ?line receive after 100 -> ok end,
  407:     ?line tp_cast(TP2, fun () -> exit(Ref) end),
  408:     ?line receive after 100 -> ok end,
  409:     ?line unmake_busy(Busy),
  410:     ?line Ref = tp_call(TP1, fun () ->
  411: 				     receive
  412: 					 {'EXIT', TP2, Ref} ->
  413: 					     Ref
  414: 				     end
  415: 			     end),
  416:     ?line tp_cast(TP1, fun () -> exit(normal) end),
  417:     ?line stop_node(A),
  418:     ?line stop_busy_dist_port_tracer(Tracer),
  419:     ?line ok.
  420: 
  421: 
  422: otp_5772_link(doc) -> [];
  423: otp_5772_link(suite) -> [];
  424: otp_5772_link(Config) when is_list(Config) ->
  425:     ?line otp_5772_link_test(node()).
  426: 
  427: otp_5772_dist_link(doc) -> [];
  428: otp_5772_dist_link(suite) -> [];
  429: otp_5772_dist_link(Config) when is_list(Config) ->
  430:     ?line [An] = get_names(1, otp_5772_dist_link),
  431:     ?line {ok, A} = start_node(An),
  432:     ?line otp_5772_link_test(A),
  433:     ?line stop_node(A).
  434: 
  435: otp_5772_link_test(Node) ->
  436:     ?line Prio = process_flag(priority, high),
  437:     ?line TE = process_flag(trap_exit, true),
  438:     ?line TP1 = spawn_opt(Node, ?MODULE, test_proc, [],
  439: 			  [link, {priority, low}]),
  440:     exit(TP1, bang),
  441:     unlink(TP1),
  442:     ?line receive
  443: 	      {'EXIT', TP1, _} ->
  444: 		  ?line ok
  445: 	  after 0 ->
  446: 		  ?line ok
  447: 	  end,
  448:     ?line receive
  449: 	      {'EXIT', TP1, _} = Exit ->
  450: 		  ?line ?t:fail({got_late_exit_message, Exit})
  451: 	  after 1000 ->
  452: 		  ?line ok
  453: 	  end,
  454:     ?line process_flag(trap_exit, TE),
  455:     ?line process_flag(priority, Prio),
  456:     ?line ok.
  457: 
  458: otp_5772_monitor(doc) -> [];
  459: otp_5772_monitor(suite) -> [];
  460: otp_5772_monitor(Config) when is_list(Config) ->
  461:     ?line otp_5772_monitor_test(node()).
  462: 
  463: otp_5772_dist_monitor(doc) -> [];
  464: otp_5772_dist_monitor(suite) -> [];
  465: otp_5772_dist_monitor(Config) when is_list(Config) ->
  466:     ?line [An] = get_names(1, otp_5772_dist_monitor),
  467:     ?line {ok, A} = start_node(An),
  468:     ?line otp_5772_monitor_test(A),
  469:     ?line stop_node(A),
  470:     ?line ok.
  471: 
  472: otp_5772_monitor_test(Node) ->
  473:     ?line Prio = process_flag(priority, high),
  474:     ?line TP1 = spawn_opt(Node, ?MODULE, test_proc, [], [{priority, low}]),
  475:     ?line M1 = erlang:monitor(process, TP1),
  476:     ?line exit(TP1, bang),
  477:     ?line erlang:demonitor(M1),
  478:     ?line receive
  479: 	      {'DOWN', M1, _, _, _} ->
  480: 		  ?line ok
  481: 	  after 0 ->
  482: 		  ?line ok
  483: 	  end,
  484:     ?line receive
  485: 	      {'DOWN', M1, _, _, _} = Down ->
  486: 		  ?line ?t:fail({got_late_down_message, Down})
  487: 	  after 1000 ->
  488: 		  ?line ok
  489: 	  end,
  490:     ?line process_flag(priority, Prio),
  491:     ?line ok.
  492: 
  493: otp_7946(Config) when is_list(Config) ->
  494:     ?line [NodeName] = get_names(1, otp_7946),
  495:     ?line {ok, Node} = start_node(NodeName),
  496:     ?line Proc = rpc:call(Node, erlang, whereis, [net_kernel]),
  497:     ?line Mon = erlang:monitor(process, Proc),
  498:     ?line rpc:cast(Node, erlang, halt, []),
  499:     ?line receive {'DOWN', Mon, process, Proc , _} -> ok end,
  500:     ?line {Linker, LMon} = spawn_monitor(fun () ->
  501: 						 link(Proc),
  502: 						 receive
  503: 						 after infinity -> ok
  504: 						 end
  505: 					 end),
  506:     ?line receive
  507: 	      {'DOWN', LMon, process, Linker, Reason} ->
  508: 		  ?line ?t:format("Reason=~p~n", [Reason]),
  509: 		  ?line Reason = noconnection
  510: 	  end.
  511: 
  512: %%
  513: %% -- Internal utils --------------------------------------------------------
  514: %%
  515: 
  516: -define(BUSY_DATA_KEY, '__busy__port__data__').
  517: -define(BUSY_DATA_SIZE, 1024*1024).
  518: 
  519: busy_data() ->
  520:     case get(?BUSY_DATA_KEY) of
  521: 	undefined ->
  522: 	    set_busy_data([]);
  523: 	Data ->
  524: 	    true = is_binary(Data),
  525: 	    true = size(Data) == ?BUSY_DATA_SIZE,
  526: 	    Data
  527:     end.
  528: 
  529: set_busy_data(SetData) ->
  530:     case get(?BUSY_DATA_KEY) of
  531: 	undefined ->
  532: 	    Data = case SetData of
  533: 		       D when is_binary(D), size(D) == ?BUSY_DATA_SIZE ->
  534: 			   SetData;
  535: 		       _ ->
  536: 			   list_to_binary(lists:duplicate(?BUSY_DATA_SIZE, 253))
  537: 		   end,
  538: 	    put(?BUSY_DATA_KEY, Data),
  539: 	    Data;
  540: 	OldData ->
  541: 	    OldData
  542:     end.
  543: 
  544: freeze_node(Node, MS) ->
  545:     Own = 500,
  546:     DoingIt = make_ref(),
  547:     Freezer = self(),
  548:     spawn_link(Node,
  549: 	       fun () ->
  550: 		       erts_debug:set_internal_state(available_internal_state,
  551: 						     true),
  552: 		       dport_send(Freezer, DoingIt),
  553: 		       receive after Own -> ok end,
  554: 		       erts_debug:set_internal_state(block, MS+Own)
  555: 	       end),
  556:     receive DoingIt -> ok end,
  557:     receive after Own -> ok end.
  558: 
  559: make_busy(Node, Time) when is_integer(Time) ->
  560:     Own = 500,
  561:     freeze_node(Node, Time+Own), 
  562:     Data = busy_data(),
  563:     %% first make port busy
  564:     Pid = spawn_link(fun () ->
  565: 			     forever(fun () ->
  566: 					     dport_reg_send(Node,
  567: 							    '__noone__',
  568: 							    Data)
  569: 				     end)
  570: 		     end),
  571:     receive after Own -> ok end,
  572:     wait_until(fun () ->
  573: 		       case process_info(Pid, status) of
  574: 			   {status, suspended} -> true;
  575: 			   _ -> false
  576: 		       end
  577: 	       end),
  578:     %% then dist entry
  579:     make_busy(Node, [nosuspend], Data),
  580:     Pid.
  581: 
  582: make_busy(Node, Opts, Data) ->
  583:     case erlang:send({'__noone__', Node}, Data, Opts) of
  584: 	nosuspend -> nosuspend;
  585: 	_ -> make_busy(Node, Opts, Data)
  586:     end.
  587: 
  588: unmake_busy(Pid) ->
  589:     unlink(Pid),
  590:     exit(Pid, bang).
  591: 
  592: suspend_on_busy_test(Node, Doing, Fun) ->
  593:     Tester = self(),
  594:     DoIt = make_ref(),
  595:     Done = make_ref(),
  596:     Data = busy_data(),
  597:     spawn_link(fun () ->
  598: 		       set_busy_data(Data),
  599: 		       Busy = make_busy(Node, 1000),
  600: 		       Tester ! DoIt,
  601: 		       receive after 100 -> ok end,
  602: 		       Info = process_info(Tester, [status, current_function]),
  603: 		       unmake_busy(Busy),
  604: 		       ?t:format("~p doing ~s: ~p~n", [Tester, Doing, Info]),
  605: 		       Tester ! {Done, Info}
  606: 	       end),
  607:     receive DoIt -> ok end,
  608:     Res = Fun(),
  609:     receive
  610: 	{Done, MyInfo} ->
  611: 	    %% Don't match arity; it is different in
  612: 	    %% debug and optimized emulator
  613: 	    [{status, suspended},
  614: 	     {current_function, {erlang, bif_return_trap, _}}] = MyInfo,
  615: 	    ok
  616:     end,
  617:     Res.
  618: 
  619: % get_node(Name) when is_atom(Name) ->
  620: %     ?line node();
  621: % get_node({Name, Node}) when is_atom(Name) ->
  622: %     ?line Node;
  623: % get_node(NC) when is_pid(NC); is_port(NC); is_reference(NC) ->
  624: %     ?line node(NC).
  625: 
  626: get_down_object(Item, _) when is_pid(Item) ->
  627:     Item;
  628: get_down_object({Name, Node} = Item, _) when is_atom(Name); is_atom(Node) ->
  629:     Item;
  630: get_down_object(Item, Watcher) when is_atom(Item), is_pid(Watcher) ->
  631:     {Item, node(Watcher)};
  632: get_down_object(Item, {_,Node}) when is_atom(Item), is_atom(Node) ->
  633:     {Item, Node};
  634: get_down_object(Item, Watcher) when is_atom(Item), is_atom(Watcher) ->
  635:     {Item, node()}.
  636: 
  637: is_proc_dead(P) ->
  638:     case is_proc_alive(P) of
  639: 	true -> false;
  640: 	false -> true
  641:     end.
  642: 
  643: is_proc_alive(Pid) when is_pid(Pid), node(Pid) == node() ->
  644:     ?line is_process_alive(Pid);
  645: is_proc_alive(Name) when is_atom(Name) ->
  646:     ?line case catch whereis(Name) of
  647: 	      Pid when is_pid(Pid) ->
  648: 		  ?line is_proc_alive(Pid);
  649: 	      _ ->
  650: 		  ?line false
  651: 	  end;
  652: is_proc_alive({Name, Node}) when is_atom(Name), Node == node() ->
  653:     ?line is_proc_alive(Name);
  654: is_proc_alive(Proc) ->
  655:     ?line is_remote_proc_alive(Proc).
  656: 
  657: is_remote_proc_alive({Name, Node}) when is_atom(Name), is_atom(Node) ->
  658:     ?line is_remote_proc_alive(Name, Node);
  659: is_remote_proc_alive(Pid) when is_pid(Pid) ->
  660:     ?line is_remote_proc_alive(Pid, node(Pid));
  661: is_remote_proc_alive(_) ->
  662:     ?line false.
  663: 
  664: is_remote_proc_alive(PN, Node) ->		 
  665:     ?line S = self(),
  666:     ?line R = make_ref(),
  667:     ?line monitor_node(Node, true),
  668:     ?line _P = spawn(Node, fun () -> S ! {R, is_proc_alive(PN)} end),
  669:     ?line receive
  670: 	      {R, Bool} ->
  671: 		  ?line monitor_node(Node, false),
  672: 		  ?line Bool;
  673: 	      {nodedown, Node} ->
  674: 		  ?line false
  675: 	  end.
  676: 
  677: wait_until(Fun) ->
  678:     ?line case Fun() of
  679: 	      true ->
  680: 		  ?line ok;
  681: 	      _ ->
  682: 		  ?line receive
  683: 			after 100 ->
  684: 				?line wait_until(Fun)
  685: 			end
  686: 	  end.
  687: 
  688: forever(Fun) ->
  689:     Fun(),
  690:     forever(Fun).
  691: 
  692: init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
  693:     ?line Dog = ?t:timetrap(?t:minutes(1)),
  694:     case catch erts_debug:get_internal_state(available_internal_state) of
  695: 	true -> ok;
  696: 	_ -> erts_debug:set_internal_state(available_internal_state, true)
  697:     end,
  698:     ?line [{watchdog, Dog}|Config].
  699: 
  700: end_per_testcase(_Func, Config) ->
  701:     ?line Dog = ?config(watchdog, Config),
  702:     ?line ?t:timetrap_cancel(Dog).
  703: 
  704: tp_call(Tp, Fun) ->
  705:     ?line R = make_ref(),
  706:     ?line Tp ! {call, self(), R, Fun},
  707:     ?line receive
  708: 	      {R, Res} ->
  709: 		  ?line Res
  710: 	  end.
  711: 
  712: tp_cast(Tp, Fun) ->
  713:     ?line Tp ! {cast, Fun}.
  714: 
  715: test_proc() ->
  716:     ?line receive
  717: 	      {call, From, Ref, Fun} ->
  718: 		  ?line From ! {Ref, Fun()};
  719: 	      {cast, Fun} ->
  720: 		  ?line Fun()
  721: 	  end,
  722:     ?line test_proc().
  723: 
  724: expand_link_list([#erl_link{type = ?LINK_NODE, targets = N} = Rec | T]) ->
  725:     lists:duplicate(N,Rec#erl_link{targets = []}) ++ expand_link_list(T);
  726: expand_link_list([#erl_link{targets = [#erl_link{pid = Pid}]} = Rec | T]) ->
  727:     [Rec#erl_link{targets = [Pid]} | expand_link_list(T)];
  728: expand_link_list([#erl_link{targets = [#erl_link{pid = Pid}|TT]} = Rec | T]) ->
  729:     [ Rec#erl_link{targets = [Pid]} | expand_link_list( 
  730: 				       [Rec#erl_link{targets = TT} | T])]; 
  731: expand_link_list([#erl_link{targets = []} = Rec | T]) ->
  732:     [Rec | expand_link_list(T)];
  733: expand_link_list([]) ->
  734:     [].
  735: 
  736: get_local_link_list(Obj) ->
  737:     case catch erts_debug:get_internal_state({link_list, Obj}) of
  738: 	LL when is_list(LL) ->
  739: 	    expand_link_list(LL);
  740: 	_ ->
  741: 	    []
  742:     end.
  743: 
  744: get_remote_link_list(Node, Obj) ->
  745:     case catch rpc:call(Node, erts_debug, get_internal_state,
  746: 			[{link_list, Obj}]) of
  747: 	LL when is_list(LL) ->
  748: 	    expand_link_list(LL);
  749: 	_ ->
  750: 	    []
  751:     end.
  752: 
  753: 
  754: get_link_list({Node, DistEntry}) when Node == node(), is_atom(DistEntry) ->
  755:     get_local_link_list(DistEntry);
  756: get_link_list({Node, DistEntry}) when is_atom(Node), is_atom(DistEntry) ->
  757:     get_remote_link_list(Node, DistEntry);
  758: get_link_list(P) when is_pid(P); is_port(P) ->
  759:     case node(P) of
  760: 	      Node when Node == node() ->
  761: 		  get_local_link_list(P);
  762: 	      Node ->
  763: 		  get_remote_link_list(Node, P)
  764: 	  end;
  765: get_link_list(undefined) ->
  766:     [].
  767: 
  768: get_local_monitor_list(Obj) ->
  769:     case catch erts_debug:get_internal_state({monitor_list, Obj}) of
  770: 	      LL when is_list(LL) ->
  771: 		  LL;
  772: 	      _ ->
  773: 		  []
  774: 	  end.
  775: 
  776: get_remote_monitor_list(Node, Obj) ->
  777:     case catch rpc:call(Node, erts_debug, get_internal_state,
  778: 			[{monitor_list, Obj}]) of
  779: 	      LL when is_list(LL) ->
  780: 		  LL;
  781: 	      _ ->
  782: 		  []
  783: 	  end.
  784: 
  785: 
  786: get_monitor_list({Node, DistEntry}) when Node == node(), is_atom(DistEntry) ->
  787:     get_local_monitor_list(DistEntry);
  788: get_monitor_list({Node, DistEntry}) when is_atom(Node), is_atom(DistEntry) ->
  789:     get_remote_monitor_list(Node, DistEntry);
  790: get_monitor_list(P) when is_pid(P) ->
  791:     case node(P) of
  792: 	      Node when Node == node() ->
  793: 		  get_local_monitor_list(P);
  794: 	      Node ->
  795: 		  get_remote_monitor_list(Node, P)
  796: 	  end;
  797: get_monitor_list(undefined) ->
  798:     [].
  799: 
  800: 
  801: find_erl_monitor(Pid, Ref) when is_reference(Ref) ->
  802:     lists:foldl(fun (#erl_monitor{ref = R} = EL, Acc) when R == Ref ->
  803: 			      [EL|Acc];
  804: 			  (_, Acc) ->
  805: 			      Acc
  806: 		      end,
  807: 		      [],
  808: 		      get_monitor_list(Pid)).
  809: 
  810: % find_erl_link(Obj, Ref) when is_reference(Ref) -> 
  811: %     ?line lists:foldl(fun (#erl_link{ref = R} = EL, Acc) when R == Ref ->
  812: % 			      ?line [EL|Acc];
  813: % 			  (_, Acc) ->
  814: % 			      ?line Acc
  815: % 		      end,
  816: % 		      [],
  817: % 		      get_link_list(Obj)).
  818: 
  819: find_erl_link(Obj, Type, [Item, Data]) when is_pid(Item);
  820: 					    is_port(Item);
  821: 					    is_atom(Item) -> 
  822:     lists:foldl(fun (#erl_link{type = T, pid = I, targets = D} = EL,
  823: 			   Acc) when T == Type, I == Item ->
  824: 			      case Data of
  825: 					D ->
  826: 					    [EL|Acc];
  827: 					[] ->
  828: 					    [EL|Acc];
  829: 					_ ->
  830: 					    Acc
  831: 				    end;
  832: 			  (_, Acc) ->
  833: 			      Acc
  834: 		      end,
  835: 		      [],
  836: 		      get_link_list(Obj));
  837: find_erl_link(Obj, Type, Item) when is_pid(Item); is_port(Item); is_atom(Item) ->
  838:     find_erl_link(Obj, Type, [Item, []]). 
  839: 
  840: 	
  841: 
  842: check_link(A, B) ->
  843:     ?line [#erl_link{type = ?LINK_PID,
  844: 		      pid = B,
  845: 		      targets = []}] = find_erl_link(A, ?LINK_PID, B),
  846:     ?line [#erl_link{type = ?LINK_PID,
  847: 		      pid = A,
  848: 		      targets = []}] = find_erl_link(B, ?LINK_PID, A),
  849:     ?line case node(A) == node(B) of
  850: 	      false ->
  851: 		  ?line [#erl_link{type = ?LINK_PID,
  852: 				   pid = A,
  853: 				   targets = [B]}] = find_erl_link({node(A),
  854: 							       node(B)},
  855: 							      ?LINK_PID,
  856: 							      [A, [B]]),
  857: 		  ?line [#erl_link{type = ?LINK_PID,
  858: 				   pid = B,
  859: 				   targets = [A]}] = find_erl_link({node(B),
  860: 								    node(A)},
  861: 								   ?LINK_PID,
  862: 								   [B, [A]]);
  863: 	      true ->
  864: 		  ?line [] = find_erl_link({node(A), node(B)},
  865: 					   ?LINK_PID,
  866: 					   [A, [B]]),
  867: 		  ?line [] = find_erl_link({node(B), node(A)},
  868: 					   ?LINK_PID,
  869: 					   [B, [A]])
  870: 	  end,
  871:     ?line ok.
  872: 
  873: check_unlink(A, B) ->
  874:     ?line [] = find_erl_link(A, ?LINK_PID, B),
  875:     ?line [] = find_erl_link(B, ?LINK_PID, A),
  876:     ?line [] = find_erl_link({node(A), node(B)}, ?LINK_PID, [A, [B]]),
  877:     ?line [] = find_erl_link({node(B), node(A)}, ?LINK_PID, [B, [A]]),
  878:     ?line ok.
  879: 
  880: check_process_monitor(From, {Name, Node}, Ref) when is_pid(From),
  881: 						    is_atom(Name),
  882: 						    Node == node(From),
  883: 						    is_reference(Ref) ->
  884:     ?line check_process_monitor(From, Name, Ref);
  885: check_process_monitor(From, {Name, Node}, Ref) when is_pid(From),
  886: 						    is_atom(Name),
  887: 						    is_atom(Node),
  888: 						    is_reference(Ref) ->
  889:     ?line MonitoredPid = rpc:call(Node, erlang, whereis, [Name]),
  890:     ?line [#erl_monitor{type = ?MON_ORIGIN,
  891: 			ref = Ref,
  892: 			pid = Node,
  893: 			name = Name}] = find_erl_monitor(From, Ref),
  894:     ?line [#erl_monitor{type = ?MON_TARGET,
  895: 			ref = Ref,
  896: 			pid = From,
  897: 			name = Name}] = 	find_erl_monitor({node(From), Node}, Ref),
  898:     ?line [#erl_monitor{type = ?MON_ORIGIN,
  899: 			ref = Ref,
  900: 			pid = MonitoredPid,
  901: 			name = Name}] = find_erl_monitor({Node, node(From)}, Ref),
  902:     ?line [#erl_monitor{type = ?MON_TARGET,
  903: 			ref = Ref,
  904: 			pid = From,
  905: 			name = Name}] = find_erl_monitor(MonitoredPid, Ref),
  906:     ?line ok;
  907: check_process_monitor(From, Name, Ref) when is_pid(From),
  908: 					    is_atom(Name),
  909: 					    undefined /= Name,
  910: 					    is_reference(Ref) ->
  911:     ?line MonitoredPid = rpc:call(node(From), erlang, whereis, [Name]),
  912:     
  913:     ?line [#erl_monitor{type = ?MON_ORIGIN,
  914: 			ref = Ref,
  915: 			pid = MonitoredPid,
  916: 			name = Name}] = find_erl_monitor(From, Ref),
  917: 
  918: 
  919:     ?line [#erl_monitor{type = ?MON_TARGET,
  920: 			ref = Ref,
  921: 			pid = From,
  922: 			name = Name}] = find_erl_monitor(MonitoredPid,Ref),
  923:     ok;
  924: check_process_monitor(From, To, Ref) when is_pid(From),
  925: 					  is_pid(To),
  926: 					  is_reference(Ref) ->
  927:     ?line OriMon = [#erl_monitor{type = ?MON_ORIGIN,
  928: 				 ref = Ref,
  929: 				 pid = To}],
  930: 
  931:     ?line OriMon = find_erl_monitor(From, Ref), 
  932: 
  933:     ?line TargMon = [#erl_monitor{type = ?MON_TARGET,
  934: 				 ref = Ref,
  935: 				 pid = From}],
  936:     ?line TargMon = find_erl_monitor(To, Ref),
  937: 			
  938: 
  939:     ?line case node(From) == node(To) of
  940: 	      false ->
  941: 		  ?line TargMon = find_erl_monitor({node(From), node(To)}, Ref),
  942: 		  ?line OriMon = find_erl_monitor({node(To), node(From)}, Ref);
  943: 	      true ->
  944: 		  ?line [] = find_erl_monitor({node(From), node(From)}, Ref)
  945: 	  end,
  946:     ?line ok.
  947: 
  948: 
  949: check_process_demonitor(From, {undefined, Node}, Ref) when is_pid(From),
  950: 							   is_reference(Ref) ->
  951:     ?line [] = find_erl_monitor(From, Ref),
  952:     ?line case node(From) == Node of
  953: 	      false ->
  954: 		  ?line [] = find_erl_monitor({node(From), Node}, Ref),
  955: 		  ?line [] = find_erl_monitor({Node, node(From)}, Ref);
  956: 	      true ->
  957: 		  ?line [] = find_erl_monitor({Node, Node}, Ref)
  958: 	  end,
  959:     ?line ok;
  960: check_process_demonitor(From, {Name, Node}, Ref) when is_pid(From),
  961: 						      is_atom(Name),
  962: 						      Node == node(From),
  963: 						      is_reference(Ref) ->
  964:     ?line MonitoredPid = rpc:call(Node, erlang, whereis, [Name]),
  965:     ?line case rpc:call(Node, erlang, whereis, [Name]) of
  966: 	      undefined ->
  967: 		  ?line check_process_demonitor(From, {undefined, Node}, Ref);
  968: 	      MonitoredPid ->
  969: 		  ?line check_process_demonitor(From, MonitoredPid, Ref)
  970: 	  end;
  971: check_process_demonitor(From, {Name, Node}, Ref) when is_pid(From),
  972: 						      is_atom(Name),
  973: 						      is_atom(Node),
  974: 						      is_reference(Ref) ->
  975:     ?line MonitoredPid = rpc:call(Node, erlang, whereis, [Name]),
  976:     ?line [] = find_erl_monitor(From, Ref),
  977:     ?line [] = find_erl_monitor({node(From), Node}, Ref),
  978:     ?line [] = find_erl_monitor({Node, node(From)}, Ref),
  979:     ?line [] = find_erl_monitor(MonitoredPid, Ref),
  980:     ?line ok;
  981: check_process_demonitor(From, undefined, Ref) when is_pid(From),
  982: 						   is_reference(Ref) ->
  983:     ?line [] = find_erl_monitor(From, Ref),
  984:     ?line case node(From) == node() of
  985: 	      false ->
  986: 		  ?line [] = find_erl_monitor({node(From), node()}, Ref),
  987: 		  ?line [] = find_erl_monitor({node(), node(From)}, Ref);
  988: 	      true ->
  989: 		  ?line [] = find_erl_monitor({node(), node()}, Ref)
  990: 	  end,
  991:     ?line ok;
  992: check_process_demonitor(From, Name, Ref) when is_pid(From),
  993: 					      is_atom(Name),
  994: 					      undefined /= Name,
  995: 					      is_reference(Ref) ->
  996:     ?line check_process_demonitor(From, {Name, node()}, Ref);
  997: check_process_demonitor(From, To, Ref) when is_pid(From),
  998: 					    is_pid(To),
  999: 					    is_reference(Ref) ->
 1000:     ?line [] = find_erl_monitor(From, Ref),
 1001:     ?line [] = find_erl_monitor(To, Ref),
 1002:     ?line case node(From) == node(To) of
 1003: 	      false ->
 1004: 		  ?line [] = find_erl_monitor({node(From), node(To)}, Ref),
 1005: 		  ?line [] = find_erl_monitor({node(To), node(From)}, Ref);
 1006: 	      true ->
 1007: 		  ?line [] = find_erl_monitor({node(From), node(From)}, Ref)
 1008: 	  end,
 1009:     ?line ok.
 1010: 
 1011: no_of_monitor_node(From, Node) when is_pid(From), is_atom(Node) ->
 1012:     ?line length(find_erl_link(From, ?LINK_NODE, Node)).
 1013: 
 1014: check_monitor_node(From, Node, No) when is_pid(From),
 1015: 					is_atom(Node),
 1016: 					is_integer(No),
 1017: 					No >= 0 ->
 1018:     ?line LL = lists:duplicate(No, #erl_link{type = ?LINK_NODE, pid = Node}),
 1019:     ?line DLL = lists:duplicate(No, #erl_link{type = ?LINK_NODE, pid = From}),
 1020:     ?line LL = find_erl_link(From, ?LINK_NODE, Node),
 1021:     ?line DLL = find_erl_link({node(From), Node}, ?LINK_NODE, From),
 1022:     ?line ok.
 1023: 
 1024: 
 1025: 
 1026: hostname() ->
 1027:     ?line from($@, atom_to_list(node())).
 1028: 
 1029: from(H, [H | T]) -> T;
 1030: from(H, [_ | T]) -> from(H, T);
 1031: from(_H, []) -> [].
 1032: 
 1033: get_names(N, T) when is_atom(T) ->
 1034:     get_names(N, T, []).
 1035: get_names(0, _, Acc) ->
 1036:     Acc;
 1037: get_names(N, T, Acc) ->
 1038:     {A, B, C} = now(),
 1039:     get_names(N-1, T, [list_to_atom(atom_to_list(?MODULE)
 1040: 				    ++ "-"
 1041: 				    ++ atom_to_list(T)
 1042: 				    ++ "-"
 1043: 				    ++ integer_to_list(A)
 1044: 				    ++ "-"
 1045: 				    ++ integer_to_list(B)
 1046: 				    ++ "-"
 1047: 				    ++ integer_to_list(C)) | Acc]).
 1048: 
 1049: start_node(Name) ->
 1050:     ?line start_node(Name, "").
 1051: 
 1052: start_node(Name, Args) ->
 1053:     ?line Pa = filename:dirname(code:which(?MODULE)),
 1054:     ?line Res = ?t:start_node(Name, slave, [{args,  Args ++ " -pa " ++ Pa}]),
 1055:     ?line {ok, Node} = Res,
 1056:     ?line rpc:call(Node, erts_debug, set_internal_state,
 1057: 		   [available_internal_state, true]),
 1058:     ?line Res.
 1059:     
 1060: 
 1061: stop_node(Node) ->
 1062:     ?line ?t:stop_node(Node).
 1063: 
 1064: -define(COOKIE, '').
 1065: -define(DOP_LINK,		1).
 1066: -define(DOP_SEND,		2).
 1067: -define(DOP_EXIT,		3).
 1068: -define(DOP_UNLINK,		4).
 1069: -define(DOP_REG_SEND,		6).
 1070: -define(DOP_GROUP_LEADER,	7).
 1071: -define(DOP_EXIT2,		8).
 1072: 
 1073: -define(DOP_SEND_TT,		12).
 1074: -define(DOP_EXIT_TT,		13).
 1075: -define(DOP_REG_SEND_TT,	16).
 1076: -define(DOP_EXIT2_TT,		18).
 1077: 
 1078: -define(DOP_MONITOR_P,		19).
 1079: -define(DOP_DEMONITOR_P,	20).
 1080: -define(DOP_MONITOR_P_EXIT,	21).
 1081: 
 1082: dport_send(To, Msg) ->
 1083:     Node = node(To),
 1084:     DPrt = case dport(Node) of
 1085: 	       undefined ->
 1086: 		   pong = net_adm:ping(Node),
 1087: 		   dport(Node);
 1088: 	       Prt ->
 1089: 		   Prt
 1090: 	   end,
 1091:     port_command(DPrt, [dmsg_hdr(),
 1092: 			dmsg_ext({?DOP_SEND,
 1093: 				  ?COOKIE,
 1094: 				  To}),
 1095: 			dmsg_ext(Msg)]).
 1096: 
 1097: dport_reg_send(Node, Name, Msg) ->
 1098:     DPrt = case dport(Node) of
 1099: 	       undefined ->
 1100: 		   pong = net_adm:ping(Node),
 1101: 		   dport(Node);
 1102: 	       Prt ->
 1103: 		   Prt
 1104: 	   end,
 1105:     port_command(DPrt, [dmsg_hdr(),
 1106: 			dmsg_ext({?DOP_REG_SEND,
 1107: 				  self(),
 1108: 				  ?COOKIE,
 1109: 				  Name}),
 1110: 			dmsg_ext(Msg)]).
 1111: 
 1112: dport(Node) when is_atom(Node) ->
 1113:     case catch erts_debug:get_internal_state(available_internal_state) of
 1114: 	true -> true;
 1115: 	_ -> erts_debug:set_internal_state(available_internal_state, true)
 1116:     end,
 1117:     erts_debug:get_internal_state({dist_port, Node}).
 1118: 
 1119: dmsg_hdr() ->
 1120:     [131, % Version Magic
 1121:      $D,  % Dist header
 1122:      0].  % No atom cache referenses
 1123: 
 1124: dmsg_ext(Term) ->	
 1125:     <<131, Res/binary>> = term_to_binary(Term),
 1126:     Res.
 1127: 
 1128: start_busy_dist_port_tracer() ->
 1129:     Tracer = spawn_link(fun () -> busy_dist_port_tracer() end),
 1130:     erlang:system_monitor(Tracer, [busy_dist_port]),
 1131:     Tracer.
 1132: 
 1133: stop_busy_dist_port_tracer(Tracer) when is_pid(Tracer) ->
 1134:     unlink(Tracer),
 1135:     exit(Tracer, bye);
 1136: stop_busy_dist_port_tracer(_) ->
 1137:     true.
 1138: 
 1139: busy_dist_port_tracer() ->
 1140:     receive
 1141: 	{monitor, _SuspendedProcess, busy_dist_port, _Port} = M ->
 1142: 	    erlang:display(M),
 1143: 	    busy_dist_port_tracer()
 1144:     end.
 1145: 	    
 1146:     
 1147: 
 1148: