1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 2002-2012. 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    : node_container_SUITE.erl
   22: %%% Author  : Rickard <rickard.green@uab.ericsson.se>
   23: %%% Purpose : 
   24: %%% Created : 24 Jul 2002 by Rickard <rickard.green@uab.ericsson.se>
   25: %%%----------------------------------------------------------------------
   26: 
   27: -module(node_container_SUITE).
   28: -author('rickard.green@uab.ericsson.se').
   29: 
   30: %-define(line_trace, 1).
   31: 
   32: -include_lib("test_server/include/test_server.hrl").
   33: 
   34: %-compile(export_all).
   35: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   36: 	 init_per_group/2,end_per_group/2, init_per_testcase/2, 
   37: 	 end_per_testcase/2,
   38: 	 node_container_refc_check/1]).
   39: 
   40: -export([term_to_binary_to_term_eq/1,
   41: 	 round_trip_eq/1,
   42: 	 cmp/1,
   43: 	 ref_eq/1,
   44: 	 node_table_gc/1,
   45: 	 dist_link_refc/1,
   46: 	 dist_monitor_refc/1,
   47: 	 node_controller_refc/1,
   48: 	 ets_refc/1,
   49: 	 match_spec_refc/1,
   50: 	 timer_refc/1,
   51: 	 otp_4715/1,
   52: 	 pid_wrap/1,
   53: 	 port_wrap/1,
   54: 	 bad_nc/1,
   55: 	 unique_pid/1,
   56: 	 iter_max_procs/1]).
   57: 
   58: -define(DEFAULT_TIMEOUT, ?t:minutes(10)).
   59: 
   60: suite() -> [{ct_hooks,[ts_install_cth]}].
   61: 
   62: all() -> 
   63:     [term_to_binary_to_term_eq, round_trip_eq, cmp, ref_eq,
   64:      node_table_gc, dist_link_refc, dist_monitor_refc,
   65:      node_controller_refc, ets_refc, match_spec_refc,
   66:      timer_refc, otp_4715, pid_wrap, port_wrap, bad_nc,
   67:      unique_pid, iter_max_procs].
   68: 
   69: groups() -> 
   70:     [].
   71: 
   72: init_per_suite(Config) ->
   73:     Config.
   74: 
   75: end_per_suite(_Config) ->
   76:     available_internal_state(false).
   77: 
   78: init_per_group(_GroupName, Config) ->
   79:     Config.
   80: 
   81: end_per_group(_GroupName, Config) ->
   82:     Config.
   83: 
   84: 
   85: available_internal_state(Bool) when Bool == true; Bool == false ->
   86:     case {Bool,
   87: 	  (catch erts_debug:get_internal_state(available_internal_state))} of
   88: 	{true, true} ->
   89: 	    true;
   90: 	{false, true} ->
   91: 	    erts_debug:set_internal_state(available_internal_state, false),
   92: 	    true;
   93: 	{true, _} ->
   94: 	    erts_debug:set_internal_state(available_internal_state, true),
   95: 	    false;
   96: 	{false, _} ->
   97: 	    false
   98:     end.
   99: 
  100: init_per_testcase(_Case, Config) when is_list(Config) ->
  101:     Dog = ?t:timetrap(?DEFAULT_TIMEOUT),
  102:     available_internal_state(true),
  103:     [{watchdog, Dog}|Config].
  104: 
  105: end_per_testcase(_Case, Config) when is_list(Config) ->
  106:     Dog = ?config(watchdog, Config),
  107:     ?t:timetrap_cancel(Dog),
  108:     ok.
  109: 
  110: %%%
  111: %%% The test cases -------------------------------------------------------------
  112: %%%
  113: 
  114: -define(MAX_PIDS_PORTS, ((1 bsl 28) - 1)).
  115: 
  116: %%
  117: %% Test case: term_to_binary_to_term_eq
  118: %%
  119: term_to_binary_to_term_eq(doc) ->
  120:     ["Tests that node container terms that are converted to external format "
  121:      "and back stay equal to themselves."];
  122: term_to_binary_to_term_eq(suite) -> [];
  123: term_to_binary_to_term_eq(Config) when is_list(Config) ->
  124:     ?line ThisNode = {node(), erlang:system_info(creation)},
  125:     % Get local node containers
  126:     ?line LPid = self(),
  127:     ?line LXPid = mk_pid(ThisNode, 32767, 8191),
  128:     ?line LPort = hd(erlang:ports()),
  129:     ?line LXPort = mk_port(ThisNode, 268435455),
  130:     ?line LLRef = make_ref(),
  131:     ?line LHLRef = mk_ref(ThisNode, [47, 11]),
  132:     ?line LSRef = mk_ref(ThisNode, [4711]),
  133:     % Test local nc:s
  134:     ?line LPid = binary_to_term(term_to_binary(LPid)),
  135:     ?line LXPid = binary_to_term(term_to_binary(LXPid)),
  136:     ?line LPort = binary_to_term(term_to_binary(LPort)),
  137:     ?line LXPort = binary_to_term(term_to_binary(LXPort)),
  138:     ?line LLRef = binary_to_term(term_to_binary(LLRef)),
  139:     ?line LHLRef = binary_to_term(term_to_binary(LHLRef)),
  140:     ?line LSRef = binary_to_term(term_to_binary(LSRef)),
  141:     % Get remote node containers
  142:     ?line RNode = {get_nodename(), 3},
  143:     ?line RPid = mk_pid(RNode, 4711, 1),
  144:     ?line RXPid = mk_pid(RNode, 32767, 8191),
  145:     ?line RPort = mk_port(RNode, 4711),
  146:     ?line RXPort = mk_port(RNode, 268435455),
  147:     ?line RLRef = mk_ref(RNode, [4711, 4711, 4711]),
  148:     ?line RHLRef = mk_ref(RNode, [4711, 4711]),
  149:     ?line RSRef = mk_ref(RNode, [4711]),
  150:     % Test remote nc:s
  151:     ?line RPid = binary_to_term(term_to_binary(RPid)),
  152:     ?line RXPid = binary_to_term(term_to_binary(RXPid)),
  153:     ?line RPort = binary_to_term(term_to_binary(RPort)),
  154:     ?line RXPort = binary_to_term(term_to_binary(RXPort)),
  155:     ?line RLRef = binary_to_term(term_to_binary(RLRef)),
  156:     ?line RHLRef = binary_to_term(term_to_binary(RHLRef)),
  157:     ?line RSRef = binary_to_term(term_to_binary(RSRef)),
  158:     ?line nc_refc_check(node()),
  159:     ?line ok.
  160: 
  161: 
  162: %%
  163: %% Test case: round_trip_eq
  164: %%
  165: round_trip_eq(doc) ->
  166:     ["Tests that node containers that are sent beteen nodes stay equal to "
  167:      "themselves."];
  168: round_trip_eq(suite) -> [];
  169: round_trip_eq(Config) when is_list(Config) ->
  170:     ?line ThisNode = {node(), erlang:system_info(creation)},
  171:     ?line NodeFirstName = get_nodefirstname(),
  172:     ?line ?line {ok, Node} = start_node(NodeFirstName),
  173:     ?line Self = self(),
  174:     ?line RPid = spawn_link(Node,
  175: 			    fun () ->
  176: 				    receive
  177: 					{Self, Data} ->
  178: 					    Self ! {self(), Data}
  179: 				    end
  180: 			    end),
  181:     ?line SentPid = self(),
  182:     ?line SentXPid = mk_pid(ThisNode, 17471, 8190),
  183:     ?line SentPort = hd(erlang:ports()),
  184:     ?line SentXPort = mk_port(ThisNode, 268435451),
  185:     ?line SentLRef = make_ref(),
  186:     ?line SentHLRef = mk_ref(ThisNode, [4711, 17]),
  187:     ?line SentSRef = mk_ref(ThisNode, [4711]),
  188:     ?line RPid ! {Self, {SentPid,
  189: 			 SentXPid,
  190: 			 SentPort,
  191: 			 SentXPort,
  192: 			 SentLRef,
  193: 			 SentHLRef,
  194: 			 SentSRef}},
  195:     receive
  196: 	{RPid, {RecPid,
  197: 		RecXPid,
  198: 		RecPort,
  199: 		RecXPort,
  200: 		RecLRef,
  201: 		RecHLRef,
  202: 		RecSRef}} ->
  203: 	    ?line stop_node(Node),
  204: 	    ?line SentPid = RecPid,
  205: 	    ?line SentXPid = RecXPid,
  206: 	    ?line SentPort = RecPort,
  207: 	    ?line SentXPort = RecXPort,
  208: 	    ?line SentLRef = RecLRef,
  209: 	    ?line SentHLRef = RecHLRef,
  210: 	    ?line SentSRef = RecSRef,
  211: 	    ?line nc_refc_check(node()),
  212: 	    ?line ok
  213:     end.
  214: 	    
  215: 
  216: 
  217: %%
  218: %% Test case: cmp
  219: %%
  220: cmp(doc) ->
  221:     ["Tests that Erlang term comparison works as it should on node "
  222:      "containers."];
  223: cmp(suite) -> [];
  224: cmp(Config) when is_list(Config) ->
  225: 
  226:     %% Inter type comparison ---------------------------------------------------
  227: 
  228:     %% The Erlang term order:
  229:     %% number < atom < ref < fun < port < pid < tuple < nil < cons < binary
  230:     RNode = {get_nodename(), 2},
  231: 
  232:     IRef = make_ref(),
  233:     ERef = mk_ref({get_nodename(), 2}, [1,2,3]),
  234:     
  235:     IPid = self(),
  236:     EPid = mk_pid(RNode, 1, 2),
  237: 
  238:     IPort = hd(erlang:ports()),
  239:     EPort = mk_port(RNode, 1),
  240:     
  241:     %% Test pids ----------------------------------------------------
  242:     ?line true = 1 < IPid,
  243:     ?line true = 1.3 < IPid,
  244:     ?line true = (1 bsl 64) < IPid,
  245:     ?line true = an_atom < IPid,
  246:     ?line true = IRef < IPid,
  247:     ?line true = ERef < IPid,
  248:     ?line true = fun () -> a_fun end < IPid,
  249:     ?line true = IPort < IPid,
  250:     ?line true = EPort < IPid,
  251:     ?line true = IPid < {a, tuple},
  252:     ?line true = IPid < [],
  253:     ?line true = IPid < [a|cons],
  254:     ?line true = IPid < <<"a binary">>,
  255: 
  256:     ?line true = 1 < EPid,
  257:     ?line true = 1.3 < EPid,
  258:     ?line true = (1 bsl 64) < EPid,
  259:     ?line true = an_atom < EPid,
  260:     ?line true = IRef < EPid,
  261:     ?line true = ERef < EPid,
  262:     ?line true = fun () -> a_fun end < EPid,
  263:     ?line true = IPort < EPid,
  264:     ?line true = EPort < EPid,
  265:     ?line true = EPid < {a, tuple},
  266:     ?line true = EPid < [],
  267:     ?line true = EPid < [a|cons],
  268:     ?line true = EPid < <<"a binary">>,
  269: 
  270:     %% Test ports --------------------------------------------------
  271:     ?line true = 1 < IPort,
  272:     ?line true = 1.3 < IPort,
  273:     ?line true = (1 bsl 64) < IPort,
  274:     ?line true = an_atom < IPort,
  275:     ?line true = IRef < IPort,
  276:     ?line true = ERef < IPort,
  277:     ?line true = fun () -> a_fun end < IPort,
  278:     ?line true = IPort < IPid,
  279:     ?line true = IPort < EPid,
  280:     ?line true = IPort < {a, tuple},
  281:     ?line true = IPort < [],
  282:     ?line true = IPort < [a|cons],
  283:     ?line true = IPort < <<"a binary">>,
  284: 
  285:     ?line true = 1 < EPort,
  286:     ?line true = 1.3 < EPort,
  287:     ?line true = (1 bsl 64) < EPort,
  288:     ?line true = an_atom < EPort,
  289:     ?line true = IRef < EPort,
  290:     ?line true = ERef < EPort,
  291:     ?line true = fun () -> a_fun end < EPort,
  292:     ?line true = EPort < IPid,
  293:     ?line true = EPort < EPid,
  294:     ?line true = EPort < {a, tuple},
  295:     ?line true = EPort < [],
  296:     ?line true = EPort < [a|cons],
  297:     ?line true = EPort < <<"a binary">>,
  298: 
  299:     %% Test refs ----------------------------------------------------
  300:     ?line true = 1 < IRef,
  301:     ?line true = 1.3 < IRef,
  302:     ?line true = (1 bsl 64) < IRef,
  303:     ?line true = an_atom < IRef,
  304:     ?line true = IRef < fun () -> a_fun end,
  305:     ?line true = IRef < IPort,
  306:     ?line true = IRef < EPort,
  307:     ?line true = IRef < IPid,
  308:     ?line true = IRef < EPid,
  309:     ?line true = IRef < {a, tuple},
  310:     ?line true = IRef < [],
  311:     ?line true = IRef < [a|cons],
  312:     ?line true = IRef < <<"a binary">>,
  313: 
  314:     ?line true = 1 < ERef,
  315:     ?line true = 1.3 < ERef,
  316:     ?line true = (1 bsl 64) < ERef,
  317:     ?line true = an_atom < ERef,
  318:     ?line true = ERef < fun () -> a_fun end,
  319:     ?line true = ERef < IPort,
  320:     ?line true = ERef < EPort,
  321:     ?line true = ERef < IPid,
  322:     ?line true = ERef < EPid,
  323:     ?line true = ERef < {a, tuple},
  324:     ?line true = ERef < [],
  325:     ?line true = ERef < [a|cons],
  326:     ?line true = ERef < <<"a binary">>,
  327: 
  328: 
  329:     %% Intra type comparison ---------------------------------------------------
  330: 	
  331: 
  332:     %% Test pids ----------------------------------------------------
  333:     %%
  334:     %% Significance (most -> least):
  335:     %%   serial, number, nodename, creation
  336:     %%
  337: 
  338:     ?line Pid = mk_pid({b@b, 2}, 4711, 1),
  339: 
  340:     ?line true = mk_pid({a@b, 1}, 4710, 2) > Pid,
  341:     ?line true = mk_pid({a@b, 1}, 4712, 1) > Pid,
  342:     ?line true = mk_pid({c@b, 1}, 4711, 1) > Pid,
  343:     ?line true = mk_pid({b@b, 3}, 4711, 1) > Pid,
  344:     ?line true = mk_pid({b@b, 2}, 4711, 1) =:= Pid,
  345: 
  346:     %% Test ports ---------------------------------------------------
  347:     %%
  348:     %% Significance (most -> least):
  349:     %%   nodename, creation, number 
  350:     %%
  351:     %% OBS: Comparison between ports has changed in R9. This
  352:     %%      since it wasn't stable in R8 (and eariler releases).
  353:     %%      Significance used to be: dist_slot, number,
  354:     %%      creation.
  355: 
  356:     ?line Port = mk_port({b@b, 2}, 4711),
  357: 
  358:     ?line true = mk_port({c@b, 1}, 4710) > Port,
  359:     ?line true = mk_port({b@b, 3}, 4710) > Port,
  360:     ?line true = mk_port({b@b, 2}, 4712) > Port,
  361:     ?line true = mk_port({b@b, 2}, 4711) =:= Port,
  362: 
  363:     %% Test refs ----------------------------------------------------
  364:     %% Significance (most -> least):
  365:     %% nodename, creation, (number high, number mid), number low, 
  366:     %%
  367:     %% OBS: Comparison between refs has changed in R9. This
  368:     %%      since it wasn't stable in R8 (and eariler releases).
  369:     %%      Significance used to be: dist_slot, number,
  370:     %%      creation.
  371:     %%
  372: 
  373:     ?line Ref = mk_ref({b@b, 2}, [4711, 4711, 4711]),
  374: 
  375:     ?line true = mk_ref({c@b, 1}, [4710, 4710, 4710]) > Ref,
  376:     ?line true = mk_ref({b@b, 3}, [4710, 4710, 4710]) > Ref,
  377:     ?line true = mk_ref({b@b, 2}, [4710, 4710, 4712]) > Ref,
  378:     ?line true = mk_ref({b@b, 2}, [4710, 4712, 4711]) > Ref,
  379:     ?line true = mk_ref({b@b, 2}, [4712, 4711, 4711]) > Ref,
  380:     ?line true = mk_ref({b@b, 2}, [4711, 4711, 4711]) =:= Ref,
  381: 
  382:     ok.
  383: 
  384: %%
  385: %% Test case: ref_eq
  386: %%
  387: ref_eq(doc) -> ["Test that one word refs \"works\"."];
  388: ref_eq(suite) -> [];
  389: ref_eq(Config) when is_list(Config) ->
  390:     ?line ThisNode = {node(), erlang:system_info(creation)},
  391:     ?line AnotherNode = {get_nodename(),2},
  392:     ?line LLongRef = mk_ref(ThisNode, [4711, 0, 0]),
  393:     ?line LHalfLongRef = mk_ref(ThisNode, [4711, 0]),
  394:     ?line LShortRef = mk_ref(ThisNode, [4711]),
  395:     ?line true = LLongRef =:= LShortRef,
  396:     ?line true = LLongRef =:= LHalfLongRef,
  397:     ?line true = LLongRef =:= LLongRef,
  398:     ?line true = LHalfLongRef =:= LShortRef,
  399:     ?line true = LHalfLongRef =:= LHalfLongRef,
  400:     ?line true = LShortRef =:= LShortRef,
  401:     ?line false = LShortRef == mk_ref(ThisNode, [4711, 0, 1]), % Not any more
  402:     ?line RLongRef = mk_ref(AnotherNode, [4711, 0, 0]),
  403:     ?line RHalfLongRef = mk_ref(AnotherNode, [4711, 0]),
  404:     ?line RShortRef = mk_ref(AnotherNode, [4711]),
  405:     ?line true = RLongRef =:= RShortRef,
  406:     ?line true = RLongRef =:= RHalfLongRef,
  407:     ?line true = RLongRef =:= RLongRef,
  408:     ?line true = RHalfLongRef =:= RShortRef,
  409:     ?line true = RHalfLongRef =:= RHalfLongRef,
  410:     ?line true = RShortRef =:= RShortRef,
  411:     ?line false = RShortRef == mk_ref(AnotherNode, [4711, 0, 1]), % Not any more
  412:     ?line nc_refc_check(node()),
  413:     ?line ok.
  414:     
  415: %%
  416: %% Test case: node_table_gc
  417: %%
  418: node_table_gc(doc) ->
  419:     ["Tests that node tables are garbage collected."];
  420: node_table_gc(suite) -> [];
  421: node_table_gc(Config) when is_list(Config) ->
  422:     ?line PreKnown = nodes(known),
  423:     ?line ?t:format("PreKnown = ~p~n", [PreKnown]),
  424:     ?line make_node_garbage(0, 200000, 1000, []),
  425:     ?line PostKnown = nodes(known),
  426:     ?line PostAreas = erlang:system_info(allocated_areas),
  427:     ?line ?t:format("PostKnown = ~p~n", [PostKnown]),
  428:     ?line ?t:format("PostAreas = ~p~n", [PostAreas]),
  429:     ?line true = length(PostKnown) =< length(PreKnown),
  430:     ?line nc_refc_check(node()),
  431:     ?line ok.
  432: 
  433: make_node_garbage(N, L, I, Ps) when N < L ->
  434:     ?line Self = self(),
  435:     ?line P = spawn_link(fun () ->
  436: 				 % Generate two node entries and one dist
  437: 				 % entry per node name
  438: 				 ?line PL1 = make_faked_pid_list(N,
  439: 								 I div 2,
  440: 								 1),
  441: 				 ?line put(a, PL1),
  442: 				 ?line PL2 = make_faked_pid_list(N,
  443: 								 I div 2,
  444: 								 2),
  445: 				 ?line put(b, PL2),
  446: 				 ?line Self ! {self(), length(nodes(known))}
  447: 			 end),
  448:     ?line receive
  449: 	      {P, KnownLength} ->
  450: 		  ?line true = KnownLength >= I div 2
  451: 	  end,
  452:     ?line make_node_garbage(N+(I div 2)*2, L, I, [P|Ps]);
  453: make_node_garbage(_, _, _, Ps) ->
  454:     %% Cleanup garbage...
  455:     ProcIsCleanedUp
  456: 	= fun (Proc) ->
  457: 		  undefined == erts_debug:get_internal_state({process_status,
  458: 							      Proc})
  459: 	  end,
  460:     lists:foreach(fun (P) -> wait_until(fun () -> ProcIsCleanedUp(P) end) end,
  461: 		  Ps),
  462:     ?line ok.
  463: 
  464: 
  465: make_faked_pid_list(Start, No, Creation) ->
  466:     make_faked_pid_list(Start, No, Creation, []).
  467: 
  468: make_faked_pid_list(_Start, 0, _Creation, Acc) ->
  469:     Acc;
  470: make_faked_pid_list(Start, No, Creation, Acc) ->
  471:     make_faked_pid_list(Start+1,
  472: 			No-1,
  473: 			Creation,
  474: 			[mk_pid({"faked_node-"
  475: 				 ++ integer_to_list(Start rem 50000)
  476: 				 ++ "@"
  477: 				 ++ atom_to_list(?MODULE),
  478: 				 Creation},
  479: 				4711,
  480: 				3) | Acc]).
  481: 
  482: %%
  483: %% Test case: dist_link_refc
  484: %%
  485: dist_link_refc(doc) ->
  486:     ["Tests that external reference counts are incremented and decremented "
  487:      "as they should for distributed links"];
  488: dist_link_refc(suite) -> [];
  489: dist_link_refc(Config) when is_list(Config) ->
  490:     ?line NodeFirstName = get_nodefirstname(),
  491:     ?line ?line {ok, Node} = start_node(NodeFirstName),
  492:     ?line RP = spawn_execer(Node),
  493:     ?line LP = spawn_link_execer(node()),
  494:     ?line true = sync_exec(RP, fun () -> link(LP) end),
  495:     ?line wait_until(fun () ->
  496: 			     ?line {links, Links} = process_info(LP, links),
  497: 			     ?line lists:member(RP, Links)
  498: 		     end),
  499:     ?line NodeCre = sync_exec(RP, fun() -> erlang:system_info(creation) end),
  500:     ?line 1 = reference_type_count(
  501: 		link,
  502: 		refering_entity_id({process, LP},
  503: 				   get_node_references({Node, NodeCre}))),
  504:     ?line exec(RP, fun() -> exit(normal) end),
  505:     ?line wait_until(fun () ->
  506: 			     ?line {links, Links} = process_info(LP, links),
  507: 			     ?line not lists:member(RP, Links)
  508: 		     end),
  509:     ?line 0 = reference_type_count(
  510: 		link,
  511: 		refering_entity_id({process, LP},
  512: 				   get_node_references({Node, NodeCre}))),
  513:     ?line exit(LP, normal),
  514:     ?line stop_node(Node),
  515:     ?line nc_refc_check(node()),
  516:     ?line ok.
  517: 
  518: 
  519: %%
  520: %% Test case: dist_monitor_refc
  521: %%
  522: dist_monitor_refc(doc) ->
  523:     ["Tests that external reference counts are incremented and decremented "
  524:      "as they should for distributed monitors"];
  525: dist_monitor_refc(suite) -> [];
  526: dist_monitor_refc(Config) when is_list(Config) ->
  527:     ?line NodeFirstName = get_nodefirstname(),
  528:     ?line {ok, Node} = start_node(NodeFirstName),
  529:     ?line RP = spawn_execer(Node),
  530:     ?line LP = spawn_link_execer(node()),
  531:     ?line RMon = sync_exec(RP, fun () -> erlang:monitor(process, LP) end),
  532:     ?line true = is_reference(RMon),
  533:     ?line LMon = sync_exec(LP, fun () -> erlang:monitor(process, RP) end),
  534:     ?line true = is_reference(LMon),
  535:     ?line NodeCre = sync_exec(RP, fun() -> erlang:system_info(creation) end),
  536:     ?line wait_until(fun () ->
  537: 			     ?line {monitored_by, MonBy}
  538: 				 = process_info(LP, monitored_by),
  539: 			     ?line {monitors, Mon}
  540: 				 = process_info(LP, monitors),
  541: 			     ?line (lists:member(RP, MonBy)
  542: 				    and lists:member({process,RP}, Mon))
  543: 		     end),
  544:     ?line 3 = reference_type_count(
  545: 		monitor,
  546: 		refering_entity_id({process, LP},
  547: 				   get_node_references({Node, NodeCre}))),
  548:     ?line exec(RP, fun () -> exit(normal) end),
  549:     ?line wait_until(fun () ->
  550: 			     ?line {monitored_by, MonBy}
  551: 				 = process_info(LP, monitored_by),
  552: 			     ?line {monitors, Mon}
  553: 				 = process_info(LP, monitors),
  554: 			     ?line ((not lists:member(RP, MonBy))
  555: 				    and (not lists:member({process,RP}, Mon)))
  556: 		     end),
  557:     ?line ok = sync_exec(LP,
  558: 			 fun () ->
  559: 				 receive
  560: 				     {'DOWN', LMon, process, _, _} ->
  561: 					 ok
  562: 				 end
  563: 			 end),
  564:     ?line 0 = reference_type_count(
  565: 		link,
  566: 		refering_entity_id({process, LP},
  567: 				   get_node_references({Node, NodeCre}))),
  568:     ?line exit(LP, normal),
  569:     ?line stop_node(Node),
  570:     ?line nc_refc_check(node()),
  571:     ?line ok.
  572: 
  573: 
  574: %%
  575: %% Test case: node_controller_refc
  576: %%
  577: node_controller_refc(doc) ->
  578:     ["Tests that external reference counts are incremented and decremented "
  579:      "as they should for entities controlling a connections."];
  580: node_controller_refc(suite) -> [];
  581: node_controller_refc(Config) when is_list(Config) ->
  582:     ?line NodeFirstName = get_nodefirstname(),
  583:     ?line ?line {ok, Node} = start_node(NodeFirstName),
  584:     ?line true = lists:member(Node, nodes()),
  585:     ?line 1 = reference_type_count(control, get_dist_references(Node)),
  586:     ?line P = spawn_link_execer(node()),
  587:     ?line Node
  588: 	= sync_exec(P,
  589: 		    fun () ->
  590: 			    put(remote_net_kernel,
  591: 				rpc:call(Node,erlang,whereis,[net_kernel])),
  592: 			    node(get(remote_net_kernel))
  593: 		    end),
  594:     ?line Creation = rpc:call(Node, erlang, system_info, [creation]),
  595:     ?line monitor_node(Node,true),
  596:     ?line stop_node(Node),
  597:     ?line receive {nodedown, Node} -> ok end,
  598:     ?line DistRefs = get_dist_references(Node),
  599:     ?line true = reference_type_count(node, DistRefs) > 0,
  600:     ?line 0 = reference_type_count(control, DistRefs),
  601:     % Get rid of all references to Node
  602:     ?line exec(P, fun () -> exit(normal) end),
  603:     ?line wait_until(fun () -> not is_process_alive(P) end),
  604:     lists:foreach(fun (Proc) -> garbage_collect(Proc) end, processes()),
  605:     ?line false = get_node_references({Node,Creation}),
  606:     ?line false = get_dist_references(Node),
  607:     ?line false = lists:member(Node, nodes(known)),
  608:     ?line nc_refc_check(node()),
  609:     ?line ok.
  610: 
  611: %%
  612: %% Test case: ets_refc
  613: %%
  614: ets_refc(doc) ->
  615:     ["Tests that external reference counts are incremented and decremented "
  616:      "as they should for data stored in ets tables."];
  617: ets_refc(suite) -> [];
  618: ets_refc(Config) when is_list(Config) ->
  619:     ?line RNode = {get_nodename(), 1},
  620:     ?line RPid = mk_pid(RNode, 4711, 2),
  621:     ?line RPort = mk_port(RNode, 4711),
  622:     ?line RRef = mk_ref(RNode, [4711, 47, 11]),
  623:     ?line Tab = ets:new(ets_refc, []),
  624:     ?line 0 = reference_type_count(ets, get_node_references(RNode)),
  625:     ?line true = ets:insert(Tab, [{a, self()},
  626: 				  {b, RPid},
  627: 				  {c, hd(erlang:ports())},
  628: 				  {d, RPort},
  629: 				  {e, make_ref()}]),
  630:     ?line 2 = reference_type_count(ets, get_node_references(RNode)),
  631:     ?line true = ets:insert(Tab, {f, RRef}),
  632:     ?line 3 = reference_type_count(ets, get_node_references(RNode)),
  633:     ?line true = ets:delete(Tab, d),
  634:     ?line 2 = reference_type_count(ets, get_node_references(RNode)),
  635:     ?line true = ets:delete_all_objects(Tab),
  636:     ?line 0 = reference_type_count(ets, get_node_references(RNode)),
  637:     ?line true = ets:insert(Tab, [{b, RPid}, {e, make_ref()}]),
  638:     ?line 1 = reference_type_count(ets, get_node_references(RNode)),
  639:     ?line true = ets:delete(Tab),
  640:     ?line 0 = reference_type_count(ets, get_node_references(RNode)),
  641:     ?line nc_refc_check(node()),
  642:     ?line ok.
  643: 
  644: %%
  645: %% Test case: match_spec_refc
  646: %%
  647: match_spec_refc(doc) ->
  648:     ["Tests that external reference counts are incremented and decremented "
  649:      "as they should for data stored in match specifications."];
  650: match_spec_refc(suite) -> [];
  651: match_spec_refc(Config) when is_list(Config) ->
  652:     ?line RNode = {get_nodename(), 1},
  653:     ?line RPid = mk_pid(RNode, 4711, 2),
  654:     ?line RPort = mk_port(RNode, 4711),
  655:     ?line RRef = mk_ref(RNode, [4711, 47, 11]),
  656:     ?line ok = do_match_spec_test(RNode, RPid, RPort, RRef),
  657:     ?line garbage_collect(),
  658:     ?line NodeRefs = get_node_references(RNode),
  659:     ?line 0 = reference_type_count(binary, NodeRefs),
  660:     ?line 0 = reference_type_count(ets, NodeRefs),
  661:     ?line nc_refc_check(node()),
  662:     ?line ok.
  663: 
  664: do_match_spec_test(RNode, RPid, RPort, RRef) ->
  665:     ?line Tab = ets:new(match_spec_refc, []),
  666:     ?line true = ets:insert(Tab, [{a, RPid, RPort, RRef},
  667: 				  {b, self(), RPort, RRef},
  668: 				  {c, RPid, RPort, make_ref()},
  669: 				  {d, RPid, RPort, RRef}]),
  670:     ?line {M1, C1} = ets:select(Tab, [{{'$1',RPid,RPort,RRef},[],['$1']}], 1),
  671:     ?line NodeRefs = get_node_references(RNode),
  672:     ?line 3 = reference_type_count(binary, NodeRefs),
  673:     ?line 10 = reference_type_count(ets, NodeRefs),
  674:     ?line {M2, C2} = ets:select(C1),
  675:     ?line '$end_of_table' = ets:select(C2),
  676:     ?line ets:delete(Tab),
  677:     ?line [a,d] = lists:sort(M1++M2),
  678:     ?line ok.
  679:     
  680: 
  681: %%
  682: %% Test case: ets_refc
  683: %%
  684: timer_refc(doc) ->
  685:     ["Tests that external reference counts are incremented and decremented "
  686:      "as they should for data stored in bif timers."];
  687: timer_refc(suite) -> [];
  688: timer_refc(Config) when is_list(Config) ->
  689:     ?line RNode = {get_nodename(), 1},
  690:     ?line RPid = mk_pid(RNode, 4711, 2),
  691:     ?line RPort = mk_port(RNode, 4711),
  692:     ?line RRef = mk_ref(RNode, [4711, 47, 11]),
  693:     ?line 0 = reference_type_count(timer, get_node_references(RNode)),
  694:     ?line Pid = spawn(fun () -> receive after infinity -> ok end end),
  695:     ?line erlang:start_timer(10000, Pid, {RPid, RPort, RRef}),
  696:     ?line 3 = reference_type_count(timer, get_node_references(RNode)),
  697:     ?line exit(Pid, kill),
  698:     ?line Mon = erlang:monitor(process, Pid),
  699:     ?line receive {'DOWN', Mon, process, Pid, _} -> ok end,
  700:     ?line 0 = reference_type_count(timer, get_node_references(RNode)),
  701:     ?line erlang:send_after(500, Pid, {timer, RPid, RPort, RRef}),
  702:     ?line 0 = reference_type_count(timer, get_node_references(RNode)),
  703:     ?line erlang:send_after(500, self(), {timer, RPid, RPort, RRef}),
  704:     ?line erlang:send_after(400, bananfluga, {timer, RPid, RPort, RRef}),
  705:     ?line 6 = reference_type_count(timer, get_node_references(RNode)),
  706:     ?line receive {timer, RPid, RPort, RRef} -> ok end,
  707:     ?line 0 = reference_type_count(timer, get_node_references(RNode)),
  708:     ?line nc_refc_check(node()),
  709:     ?line ok.
  710: 
  711: otp_4715(doc) -> [];
  712: otp_4715(suite) -> [];
  713: otp_4715(Config) when is_list(Config) ->
  714:     case ?t:is_release_available("r9b") of
  715: 	true -> otp_4715_1(Config);
  716: 	false -> {skip,"No R9B found"}
  717:     end.
  718: 
  719: otp_4715_1(Config) ->
  720:     case erlang:system_info(compat_rel) of
  721: 	9 ->
  722: 	    ?line run_otp_4715(Config);
  723: 	_ ->
  724: 	    ?line Pa = filename:dirname(code:which(?MODULE)),
  725: 	    ?line ?t:run_on_shielded_node(fun () ->
  726: 						  run_otp_4715(Config)
  727: 					  end,
  728: 					  "+R9 -pa " ++ Pa)
  729:     end.
  730: 
  731: run_otp_4715(Config) when is_list(Config) ->
  732:     ?line erts_debug:set_internal_state(available_internal_state, true),
  733:     ?line PidList = [mk_pid({a@b, 1}, 4710, 2),
  734: 		     mk_pid({a@b, 1}, 4712, 1),
  735: 		     mk_pid({c@b, 1}, 4711, 1),
  736: 		     mk_pid({b@b, 3}, 4711, 1),
  737: 		     mk_pid({b@b, 2}, 4711, 1)],
  738: 
  739:     ?line R9Sorted = old_mod:sort_on_old_node(PidList),
  740:     ?line R9Sorted = lists:sort(PidList).
  741: 
  742: pid_wrap(doc) -> [];
  743: pid_wrap(suite) -> [];
  744: pid_wrap(Config) when is_list(Config) -> ?line pp_wrap(pid).
  745: 
  746: port_wrap(doc) -> [];
  747: port_wrap(suite) -> [];
  748: port_wrap(Config) when is_list(Config) ->
  749:     ?line case ?t:os_type() of
  750: 	      {unix, _} ->
  751: 		  ?line pp_wrap(port);
  752: 	      _ ->
  753: 		  ?line {skip, "Only run on unix"}
  754: 	  end.
  755: 
  756: get_next_id(pid) ->
  757:     erts_debug:get_internal_state(next_pid);
  758: get_next_id(port) ->
  759:     erts_debug:get_internal_state(next_port).
  760: 
  761: set_next_id(pid, N) ->
  762:     erts_debug:set_internal_state(next_pid, N);
  763: set_next_id(port, N) ->
  764:     erts_debug:set_internal_state(next_port, N).
  765: 
  766: pp_wrap(What) ->
  767:     ?line N = set_high_pp_next(What),
  768:     ?line Cre = N + 100,
  769:     ?line ?t:format("no creations = ~p~n", [Cre]),
  770:     ?line PreCre = get_next_id(What),
  771:     ?line ?t:format("pre creations = ~p~n", [PreCre]),
  772:     ?line true = is_integer(PreCre),
  773:     ?line do_pp_creations(What, Cre),
  774:     ?line PostCre = get_next_id(What),
  775:     ?line ?t:format("post creations = ~p~n", [PostCre]),
  776:     ?line true = is_integer(PostCre),
  777:     ?line true = PreCre > PostCre,
  778:     ?line Now = set_next_id(What, ?MAX_PIDS_PORTS div 2),
  779:     ?line ?t:format("reset to = ~p~n", [Now]),
  780:     ?line true = is_integer(Now),
  781:     ?line ok.
  782: 
  783: set_high_pp_next(What) ->
  784:     ?line set_high_pp_next(What, ?MAX_PIDS_PORTS-1).
  785:     
  786: set_high_pp_next(What, N) ->
  787:     ?line M = set_next_id(What, N),
  788:     ?line true = is_integer(M),
  789:     ?line case {M >= N, M =< ?MAX_PIDS_PORTS} of
  790: 	      {true, true} ->
  791: 		  ?line ?MAX_PIDS_PORTS - M + 1;
  792: 	      _ ->
  793: 		  ?line set_high_pp_next(What, N - 100)
  794: 	  end.
  795: 
  796: do_pp_creations(_What, N) when is_integer(N), N =< 0 ->
  797:     ?line done;
  798: do_pp_creations(pid, N) when is_integer(N) ->
  799:     %% Create new pid and make sure it works...
  800:     ?line Me = self(),
  801:     ?line Ref = make_ref(),
  802:     ?line Pid = spawn_link(fun () ->
  803: 				   receive
  804: 				       Ref ->
  805: 					   Me ! Ref
  806: 				   end
  807: 			   end),
  808:     ?line Pid ! Ref,
  809:     ?line receive
  810: 	      Ref ->
  811: 		  ?line do_pp_creations(pid, N - 1)
  812: 	  end;
  813: do_pp_creations(port, N) when is_integer(N) ->
  814:     %% Create new port and make sure it works...
  815:     ?line "hej" = os:cmd("echo hej") -- "\n",
  816:     ?line do_pp_creations(port, N - 1).
  817: 
  818: bad_nc(doc) -> [];
  819: bad_nc(suite) -> [];
  820: bad_nc(Config) when is_list(Config) ->
  821:     % Make sure emulator don't crash on bad node containers...
  822:     ?line MaxPidNum = (1 bsl 15) - 1,
  823:     ?line MaxPidSer = ?MAX_PIDS_PORTS bsr 15,
  824:     ?line ThisNode = {node(), erlang:system_info(creation)},
  825:     ?line {'EXIT', {badarg, mk_pid, _}}
  826: 	= (catch mk_pid(ThisNode, MaxPidNum + 1, 17)),
  827:     ?line {'EXIT', {badarg, mk_pid, _}}
  828: 	= (catch mk_pid(ThisNode, 4711, MaxPidSer + 1)),
  829:     ?line {'EXIT', {badarg, mk_port, _}}
  830: 	= (catch mk_port(ThisNode, ?MAX_PIDS_PORTS + 1)),
  831:     ?line {'EXIT', {badarg, mk_ref, _}}
  832: 	= (catch mk_ref(ThisNode,[(1 bsl 18), 4711, 4711])),
  833:     ?line {'EXIT', {badarg, mk_ref, _}}
  834: 	= (catch mk_ref(ThisNode, [4711, 4711, 4711, 4711, 4711, 4711, 4711])),
  835:     ?line RemNode = {x@y, 2},
  836:     ?line {'EXIT', {badarg, mk_pid, _}}
  837: 	= (catch mk_pid(RemNode, MaxPidNum + 1, MaxPidSer)),
  838:     ?line {'EXIT', {badarg, mk_pid, _}}
  839: 	= (catch mk_pid(RemNode, MaxPidNum, MaxPidSer + 1)),
  840:     ?line {'EXIT', {badarg, mk_port, _}}
  841: 	= (catch mk_port(RemNode, ?MAX_PIDS_PORTS + 1)),
  842:     ?line {'EXIT', {badarg, mk_ref, _}}
  843: 	= (catch mk_ref(RemNode, [(1 bsl 18), 4711, 4711])),
  844:     ?line {'EXIT', {badarg, mk_ref, _}}
  845: 	= (catch mk_ref(RemNode, [4711, 4711, 4711, 4711, 4711, 4711, 4711])),
  846:     ?line BadNode = {x@y, 4},
  847:     ?line {'EXIT', {badarg, mk_pid, _}}
  848: 	= (catch mk_pid(BadNode, 4711, 17)),
  849:     ?line {'EXIT', {badarg, mk_port, _}}
  850: 	= (catch mk_port(BadNode, 4711)),
  851:     ?line {'EXIT', {badarg, mk_ref, _}}
  852: 	= (catch mk_ref(BadNode, [4711, 4711, 17])),
  853:     ?line ok.
  854: 
  855: 
  856: 
  857: -define(NO_PIDS, 1000000).
  858: 
  859: unique_pid(doc) -> [];
  860: unique_pid(suite) -> [];
  861: unique_pid(Config) when is_list(Config) ->
  862:     case catch erlang:system_info(modified_timing_level) of
  863: 	Level when is_integer(Level) ->
  864: 	    {skip,
  865: 	     "Modified timing (level " ++ integer_to_list(Level)
  866: 	     ++ ") is enabled. spawn() is too slow for this "
  867: 	     " test when modified timing is enabled."};
  868: 	_ ->
  869: 	    ?line ?NO_PIDS = length(lists:usort(mkpidlist(?NO_PIDS, []))),
  870: 	    ?line ok
  871:     end.
  872:     
  873: mkpidlist(0, Ps) -> Ps;
  874: mkpidlist(N, Ps) -> mkpidlist(N-1, [spawn(fun () -> ok end)|Ps]).
  875: 
  876: 
  877: iter_max_procs(doc) -> [];
  878: iter_max_procs(suite) -> [];
  879: iter_max_procs(Config) when is_list(Config) ->
  880:     ?line NoMoreTests = make_ref(),
  881:     ?line erlang:send_after(10000, self(), NoMoreTests),
  882:     ?line Res = chk_max_proc_line(),
  883:     ?line Res = chk_max_proc_line(),
  884:     ?line done = chk_max_proc_line_until(NoMoreTests, Res),
  885:     ?line {comment,
  886: 	   io_lib:format("max processes = ~p; "
  887: 			 "process line length = ~p",
  888: 			 [element(2, Res), element(1, Res)])}.
  889:     
  890:     
  891: max_proc_line(Root, Parent, N) ->
  892:     Me = self(),
  893:     case catch spawn_link(fun () -> max_proc_line(Root, Me, N+1) end) of
  894: 	{'EXIT', {system_limit, _}} when Root /= self() ->
  895: 	    Root ! {proc_line_length, N, self()},
  896: 	    receive remove_proc_line -> Parent ! {exiting, Me} end;
  897: 	P when is_pid(P), Root =/= self() ->
  898: 	    receive {exiting, P} -> Parent ! {exiting, Me} end;
  899: 	P when is_pid(P) ->
  900: 	    P;
  901: 	Unexpected ->
  902: 	    exit({unexpected_spawn_result, Unexpected})
  903:     end.
  904: 
  905: chk_max_proc_line() ->
  906:     ?line Child = max_proc_line(self(), self(), 0),
  907:     ?line receive
  908: 	      {proc_line_length, PLL, End} ->
  909: 		  ?line PC = erlang:system_info(process_count),
  910: 		  ?line LP = length(processes()),
  911: 		  ?line ?t:format("proc line length = ~p; "
  912: 				  "process count = ~p; "
  913: 				  "length processes = ~p~n",
  914: 				  [PLL, PC, LP]),
  915: 		  ?line End ! remove_proc_line,
  916: 		  ?line PC = LP,
  917: 		  ?line receive {exiting, Child} -> ok end,
  918: 		  ?line {PLL, PC}
  919: 	  end.
  920: 
  921: chk_max_proc_line_until(NoMoreTests, Res) ->
  922:     receive
  923: 	NoMoreTests ->
  924: 	    ?line done
  925:     after 0 ->
  926: 	    ?line Res = chk_max_proc_line(),
  927: 	    ?line chk_max_proc_line_until(NoMoreTests, Res)
  928:     end.
  929: 
  930: %%
  931: %% -- Internal utils ---------------------------------------------------------
  932: %%
  933: 
  934: -define(ND_REFS, erts_debug:get_internal_state(node_and_dist_references)).
  935: 
  936: node_container_refc_check(Node) when is_atom(Node) ->
  937:     AIS = available_internal_state(true),
  938:     nc_refc_check(Node),
  939:     available_internal_state(AIS).
  940: 
  941: nc_refc_check(Node) when is_atom(Node) ->
  942:     Ref = make_ref(),
  943:     Self = self(),
  944:     ?t:format("Starting reference count check of node ~w~n", [Node]),
  945:     spawn_link(Node,
  946: 	       fun () ->
  947: 		       {{node_references, NodeRefs},
  948: 			{dist_references, DistRefs}} = ?ND_REFS,
  949: 		       check_nd_refc({node(), erlang:system_info(creation)},
  950: 				     NodeRefs,
  951: 				     DistRefs,
  952: 				     fun (ErrMsg) ->
  953: 					     Self ! {Ref, ErrMsg, failed},
  954: 					     exit(normal)
  955: 				     end),
  956: 		       Self ! {Ref, succeded}
  957: 	       end),
  958:     receive
  959: 	{Ref, ErrorMsg, failed} ->
  960: 	    ?t:format("~s~n", [ErrorMsg]),
  961: 	    ?t:fail(reference_count_check_failed);
  962: 	{Ref, succeded} ->
  963: 	    ?t:format("Reference count check of node ~w succeded!~n", [Node]),
  964: 	    ok
  965:     end.
  966: 
  967: check_nd_refc({ThisNodeName, ThisCreation}, NodeRefs, DistRefs, Fail) ->
  968:     case catch begin
  969: 		   check_refc(ThisNodeName,ThisCreation,"node table",NodeRefs),
  970: 		   check_refc(ThisNodeName,ThisCreation,"dist table",DistRefs),
  971: 		   ok
  972: 	       end of
  973: 	ok ->
  974: 	    ok;
  975: 	{'EXIT', Reason} ->
  976: 	    {Y,Mo,D} = date(),
  977: 	    {H,Mi,S} = time(),
  978: 	    ErrMsg = io_lib:format("~n"
  979: 				   "*** Reference count check of node ~w "
  980: 				   "failed (~p) at ~w~w~w ~w:~w:~w~n"
  981: 				   "*** Node table references:~n ~p~n"
  982: 				   "*** Dist table references:~n ~p~n",
  983: 				   [node(), Reason, Y, Mo, D, H, Mi, S,
  984: 				    NodeRefs, DistRefs]),
  985: 	    Fail(lists:flatten(ErrMsg))
  986:     end.
  987: 
  988: 
  989: check_refc(ThisNodeName,ThisCreation,Table,EntryList) when is_list(EntryList) ->
  990:     lists:foreach(
  991:       fun ({Entry, Refc, ReferrerList}) ->
  992: 	      FoundRefs =
  993: 		  lists:foldl(
  994: 		    fun ({_Referrer, ReferencesList}, A1) ->
  995: 			    A1 + lists:foldl(fun ({_T,Rs},A2) ->
  996: 						     A2+Rs
  997: 					     end,
  998: 					     0,
  999: 					     ReferencesList)
 1000: 		    end,
 1001: 		    0,
 1002: 		    ReferrerList),
 1003: 	      
 1004: 	      %% Reference count equals found references ?
 1005: 	      case Refc =:= FoundRefs of
 1006: 		  true ->
 1007: 		      ok;
 1008: 		  false ->
 1009: 		      exit({invalid_reference_count, Table, Entry})
 1010: 	      end,
 1011: 
 1012: 	      %% All entries in table referred to?
 1013: 	      case {Entry, Refc} of
 1014: 		  {ThisNodeName, 0} -> ok;
 1015: 		  {{ThisNodeName, ThisCreation}, 0} -> ok;
 1016: 		  {_, 0} -> exit({not_referred_entry_in_table, Table, Entry});
 1017: 		  {_, _} -> ok 
 1018: 	      end
 1019: 
 1020:       end,
 1021:       EntryList),
 1022:     ok.
 1023: 
 1024: get_node_references({NodeName, Creation} = Node) when is_atom(NodeName),
 1025: 						      is_integer(Creation) ->
 1026:     {{node_references, NodeRefs},
 1027: 	   {dist_references, DistRefs}} = ?ND_REFS,
 1028:     check_nd_refc({node(), erlang:system_info(creation)},
 1029: 			NodeRefs,
 1030: 			DistRefs,
 1031: 			fun (ErrMsg) ->
 1032: 				?t:format("~s", [ErrMsg]),
 1033: 				?t:fail(reference_count_check_failed)
 1034: 			end),
 1035:     find_references(Node, NodeRefs).
 1036: 
 1037: get_dist_references(NodeName) when is_atom(NodeName) ->
 1038:     ?line {{node_references, NodeRefs},
 1039: 	   {dist_references, DistRefs}} = ?ND_REFS,
 1040:     ?line check_nd_refc({node(), erlang:system_info(creation)},
 1041: 			NodeRefs,
 1042: 			DistRefs,
 1043: 			fun (ErrMsg) ->
 1044: 				?line ?t:format("~s", [ErrMsg]),
 1045: 				?line ?t:fail(reference_count_check_failed)
 1046: 			end),
 1047:     ?line find_references(NodeName, DistRefs).
 1048: 
 1049: find_references(N, NRefList) ->
 1050:     case lists:keysearch(N, 1, NRefList) of
 1051: 	      {value, {N, _, ReferrersList}} -> ReferrersList;
 1052: 	      _ -> false
 1053: 	  end.
 1054: 
 1055: %% Currently unused
 1056: % refering_entity_type(RefererType, ReferingEntities) ->
 1057: %     lists:filter(fun ({{RT, _}, _}) when RT == RefererType ->
 1058: % 			 true;
 1059: % 		     (_) ->
 1060: % 			 false
 1061: % 		 end,
 1062: % 		 ReferingEntities).
 1063: 
 1064: refering_entity_id(ReferingEntityId, [{ReferingEntityId,_} = ReferingEntity
 1065: 				      | _ReferingEntities]) ->
 1066:     ReferingEntity;
 1067: refering_entity_id(ReferingEntityId, [_ | ReferingEntities]) ->
 1068:     refering_entity_id(ReferingEntityId, ReferingEntities);
 1069: refering_entity_id(_, []) ->
 1070:     false.
 1071: 
 1072: reference_type_count(_, false) ->
 1073:     0;
 1074: reference_type_count(Type, {_, _ReferenceCountList} = ReferingEntity) ->
 1075:     reference_type_count(Type, [ReferingEntity]);
 1076: reference_type_count(Type, ReferingEntities) when is_list(ReferingEntities) ->
 1077:     lists:foldl(fun ({_, ReferenceCountList}, Acc1) ->
 1078: 			lists:foldl(fun ({T, N}, Acc2) when T == Type ->
 1079: 					    N + Acc2;
 1080: 					(_, Acc2) ->
 1081: 					    Acc2
 1082: 				    end,
 1083: 				    Acc1,
 1084: 				    ReferenceCountList)
 1085: 		end,
 1086: 		0,
 1087: 		ReferingEntities).
 1088: 
 1089: 
 1090: start_node(Name, Args) ->
 1091:     ?line Pa = filename:dirname(code:which(?MODULE)),
 1092:     ?line Res = test_server:start_node(Name,
 1093: 				       slave,
 1094: 				       [{args, "-pa "++Pa++" "++Args}]),
 1095:     ?line {ok, Node} = Res,
 1096:     ?line rpc:call(Node, erts_debug, set_internal_state,
 1097: 		   [available_internal_state, true]),
 1098:     ?line Res.
 1099:     
 1100: start_node(Name) ->
 1101:     ?line start_node(Name, "").
 1102: 
 1103: stop_node(Node) ->
 1104:     ?line nc_refc_check(Node),
 1105:     ?line true = test_server:stop_node(Node).
 1106: 
 1107: hostname() ->
 1108:     from($@, atom_to_list(node())).
 1109: 
 1110: from(H, [H | T]) -> T;
 1111: from(H, [_ | T]) -> from(H, T);
 1112: from(_H, []) -> [].
 1113: 
 1114: wait_until(Pred) ->
 1115:     case Pred() of
 1116: 	true -> ok;
 1117: 	false -> receive after 100 -> wait_until(Pred) end
 1118:     end.
 1119: 
 1120: 
 1121: get_nodefirstname() ->
 1122:     {A, B, C} = now(),
 1123:     list_to_atom(atom_to_list(?MODULE)
 1124: 		 ++ "-"
 1125: 		 ++ integer_to_list(A)
 1126: 		 ++ "-"
 1127: 		 ++ integer_to_list(B)
 1128: 		 ++ "-"
 1129: 		 ++ integer_to_list(C)).
 1130: 
 1131: get_nodename() ->
 1132:     {A, B, C} = now(),
 1133:     list_to_atom(atom_to_list(?MODULE)
 1134: 		 ++ "-"
 1135: 		 ++ integer_to_list(A)
 1136: 		 ++ "-"
 1137: 		 ++ integer_to_list(B)
 1138: 		 ++ "-"
 1139: 		 ++ integer_to_list(C)
 1140: 		 ++ "@"
 1141: 		 ++ hostname()).
 1142:     
 1143: 
 1144: 
 1145: -define(VERSION_MAGIC,       131).
 1146: 
 1147: -define(ATOM_EXT,            100).
 1148: -define(REFERENCE_EXT,       101).
 1149: -define(PORT_EXT,            102).
 1150: -define(PID_EXT,             103).
 1151: -define(NEW_REFERENCE_EXT,   114).
 1152: 
 1153: uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 ->
 1154:     [(Uint bsr 24) band 16#ff,
 1155:      (Uint bsr 16) band 16#ff,
 1156:      (Uint bsr 8) band 16#ff,
 1157:      Uint band 16#ff];
 1158: uint32_be(Uint) ->
 1159:     exit({badarg, uint32_be, [Uint]}).
 1160: 
 1161: 
 1162: uint16_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 16 ->
 1163:     [(Uint bsr 8) band 16#ff,
 1164:      Uint band 16#ff];
 1165: uint16_be(Uint) ->
 1166:     exit({badarg, uint16_be, [Uint]}).
 1167: 
 1168: uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 ->
 1169:     Uint band 16#ff;
 1170: uint8(Uint) ->
 1171:     exit({badarg, uint8, [Uint]}).
 1172: 
 1173: 
 1174: 
 1175: mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) ->
 1176:     mk_pid({atom_to_list(NodeName), Creation}, Number, Serial);
 1177: mk_pid({NodeName, Creation}, Number, Serial) ->
 1178:     case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
 1179: 					?PID_EXT,
 1180: 					?ATOM_EXT,
 1181: 					uint16_be(length(NodeName)),
 1182: 					NodeName,
 1183: 					uint32_be(Number),
 1184: 					uint32_be(Serial),
 1185: 					uint8(Creation)])) of
 1186: 	Pid when is_pid(Pid) ->
 1187: 	    Pid;
 1188: 	{'EXIT', {badarg, _}} ->
 1189: 	    exit({badarg, mk_pid, [{NodeName, Creation}, Number, Serial]});
 1190: 	Other ->
 1191: 	    exit({unexpected_binary_to_term_result, Other})
 1192:     end.
 1193: 
 1194: mk_port({NodeName, Creation}, Number) when is_atom(NodeName) ->
 1195:     mk_port({atom_to_list(NodeName), Creation}, Number);
 1196: mk_port({NodeName, Creation}, Number) ->
 1197:     case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
 1198: 					      ?PORT_EXT,
 1199: 					      ?ATOM_EXT,
 1200: 					      uint16_be(length(NodeName)),
 1201: 					      NodeName,
 1202: 					      uint32_be(Number),
 1203: 					      uint8(Creation)])) of
 1204: 	Port when is_port(Port) ->
 1205: 	    Port;
 1206: 	{'EXIT', {badarg, _}} ->
 1207: 	    exit({badarg, mk_port, [{NodeName, Creation}, Number]});
 1208: 	Other ->
 1209: 	    exit({unexpected_binary_to_term_result, Other})
 1210:     end.
 1211: 
 1212: mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName),
 1213: 					   is_integer(Creation),
 1214: 					   is_list(Numbers) ->
 1215:     mk_ref({atom_to_list(NodeName), Creation}, Numbers);
 1216: mk_ref({NodeName, Creation}, [Number]) when is_list(NodeName),
 1217: 					    is_integer(Creation),
 1218: 					    is_integer(Number) ->
 1219:     case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
 1220: 					      ?REFERENCE_EXT,
 1221: 					      ?ATOM_EXT,
 1222: 					      uint16_be(length(NodeName)),
 1223: 					      NodeName,
 1224: 					      uint32_be(Number),
 1225: 					      uint8(Creation)])) of
 1226: 	Ref when is_reference(Ref) ->
 1227: 	    Ref;
 1228: 	{'EXIT', {badarg, _}} ->
 1229: 	    exit({badarg, mk_ref, [{NodeName, Creation}, [Number]]});
 1230: 	Other ->
 1231: 	    exit({unexpected_binary_to_term_result, Other})
 1232:     end;
 1233: mk_ref({NodeName, Creation}, Numbers) when is_list(NodeName),
 1234: 					   is_integer(Creation),
 1235: 					   is_list(Numbers) ->
 1236:     case catch binary_to_term(list_to_binary([?VERSION_MAGIC,
 1237: 					      ?NEW_REFERENCE_EXT,
 1238: 					      uint16_be(length(Numbers)),
 1239: 					      ?ATOM_EXT,
 1240: 					      uint16_be(length(NodeName)),
 1241: 					      NodeName,
 1242: 					      uint8(Creation),
 1243: 					      lists:map(fun (N) ->
 1244: 								uint32_be(N)
 1245: 							end,
 1246: 							Numbers)])) of
 1247: 	Ref when is_reference(Ref) ->
 1248: 	    Ref;
 1249: 	{'EXIT', {badarg, _}} ->
 1250: 	    exit({badarg, mk_ref, [{NodeName, Creation}, Numbers]});
 1251: 	Other ->
 1252: 	    exit({unexpected_binary_to_term_result, Other})
 1253:     end.
 1254: 
 1255: exec_loop() ->
 1256:     receive
 1257: 	{exec_fun, Fun} when is_function(Fun) ->
 1258: 	    Fun();
 1259: 	{sync_exec_fun, From, Fun} when is_pid(From), is_function(Fun)  ->
 1260: 	    From ! {sync_exec_fun_res, self(), Fun()}
 1261:     end,
 1262:     exec_loop().
 1263: 
 1264: spawn_execer(Node) ->
 1265:     spawn(Node, fun () -> exec_loop() end).
 1266: 
 1267: spawn_link_execer(Node) ->
 1268:     spawn_link(Node, fun () -> exec_loop() end).
 1269: 
 1270: exec(Pid, Fun) when is_pid(Pid), is_function(Fun) ->
 1271:     Pid ! {exec_fun, Fun}.
 1272: 
 1273: sync_exec(Pid, Fun) when is_pid(Pid), is_function(Fun) ->
 1274:     Pid ! {sync_exec_fun, self(), Fun},
 1275:     receive
 1276: 	{sync_exec_fun_res, Pid, Res} ->
 1277: 	    Res
 1278:     end.