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: