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.