1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 1999-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: -module(monitor_SUITE). 21: 22: -include_lib("test_server/include/test_server.hrl"). 23: 24: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 25: init_per_group/2,end_per_group/2, 26: case_1/1, case_1a/1, case_2/1, case_2a/1, mon_e_1/1, demon_e_1/1, demon_1/1, 27: demon_2/1, demon_3/1, demonitor_flush/1, 28: local_remove_monitor/1, remote_remove_monitor/1, mon_1/1, mon_2/1, 29: large_exit/1, list_cleanup/1, mixer/1, named_down/1, otp_5827/1]). 30: 31: -export([init_per_testcase/2, end_per_testcase/2]). 32: 33: -export([y2/1, g/1, g0/0, g1/0, large_exit_sub/1]). 34: 35: suite() -> [{ct_hooks,[ts_install_cth]}]. 36: 37: all() -> 38: [case_1, case_1a, case_2, case_2a, mon_e_1, demon_e_1, 39: demon_1, mon_1, mon_2, demon_2, demon_3, 40: demonitor_flush, {group, remove_monitor}, large_exit, 41: list_cleanup, mixer, named_down, otp_5827]. 42: 43: groups() -> 44: [{remove_monitor, [], 45: [local_remove_monitor, remote_remove_monitor]}]. 46: 47: init_per_suite(Config) -> 48: Config. 49: 50: end_per_suite(_Config) -> 51: ok. 52: 53: init_per_group(_GroupName, Config) -> 54: Config. 55: 56: end_per_group(_GroupName, Config) -> 57: Config. 58: 59: 60: init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> 61: Dog=?t:timetrap(?t:minutes(15)), 62: [{watchdog, Dog}|Config]. 63: 64: end_per_testcase(_Func, Config) -> 65: Dog=?config(watchdog, Config), 66: ?t:timetrap_cancel(Dog). 67: 68: case_1(doc) -> 69: "A monitors B, B kills A and then exits (yielded core dump)"; 70: case_1(suite) -> []; 71: case_1(Config) when is_list(Config) -> 72: ?line process_flag(trap_exit, true), 73: ?line spawn_link(?MODULE, g0, []), 74: ?line receive _ -> ok end, 75: ok. 76: 77: case_1a(doc) -> 78: "A monitors B, B kills A and then exits (yielded core dump)"; 79: case_1a(Config) when is_list(Config) -> 80: ?line process_flag(trap_exit, true), 81: ?line spawn_link(?MODULE, g1, []), 82: ?line receive _ -> ok end, 83: ok. 84: 85: g0() -> 86: ?line B = spawn(?MODULE, g, [self()]), 87: ?line erlang:monitor(process, B), 88: ?line B ! ok, 89: ?line receive ok -> ok end, 90: ok. 91: 92: g1() -> 93: ?line {B,_} = spawn_monitor(?MODULE, g, [self()]), 94: ?line B ! ok, 95: ?line receive ok -> ok end, 96: ok. 97: 98: g(Parent) -> 99: ?line receive ok -> ok end, 100: ?line exit(Parent, foo), 101: ?line ok. 102: 103: 104: case_2(doc) -> 105: "A monitors B, B demonitors A (yielded core dump)"; 106: case_2(Config) when is_list(Config) -> 107: ?line B = spawn(?MODULE, y2, [self()]), 108: ?line R = erlang:monitor(process, B), 109: ?line B ! R, 110: ?line receive 111: {'EXIT', _} -> ok; 112: Other -> 113: test_server:fail({rec, Other}) 114: end, 115: ?line expect_down(R, B, normal), 116: ok. 117: 118: case_2a(doc) -> 119: "A monitors B, B demonitors A (yielded core dump)"; 120: case_2a(Config) when is_list(Config) -> 121: ?line {B,R} = spawn_monitor(?MODULE, y2, [self()]), 122: ?line B ! R, 123: ?line receive 124: {'EXIT', _} -> ok; 125: Other -> 126: test_server:fail({rec, Other}) 127: end, 128: ?line expect_down(R, B, normal), 129: ok. 130: 131: y2(Parent) -> 132: ?line R = receive T -> T end, 133: ?line Parent ! (catch erlang:demonitor(R)), 134: ok. 135: 136: expect_down(Ref, P) -> 137: receive 138: {'DOWN', Ref, process, P, Reason} -> 139: Reason; 140: Other -> 141: test_server:fail({rec, Other}) 142: end. 143: 144: expect_down(Ref, P, Reason) -> 145: receive 146: {'DOWN', Ref, process, P, Reason} -> 147: ok; 148: Other -> 149: test_server:fail({rec, Other}) 150: end. 151: 152: expect_no_msg() -> 153: receive 154: Msg -> 155: test_server:fail({msg, Msg}) 156: after 0 -> 157: ok 158: end. 159: 160: %%% Error cases for monitor/2 161: 162: mon_e_1(doc) -> 163: "Error cases for monitor/2"; 164: mon_e_1(suite) -> []; 165: mon_e_1(Config) when is_list(Config) -> 166: ?line {ok, N} = test_server:start_node(hej, slave, []), 167: ?line mon_error(plutt, self()), 168: ?line mon_error(process, [bingo]), 169: ?line mon_error(process, {rex, N, junk}), 170: ?line mon_error(process, 1), 171: 172: ?line true = test_server:stop_node(N), 173: ok. 174: 175: %%% We would also like to have a test case that tries to monitor something 176: %%% on an R5 node, but this isn't possible to do systematically. 177: %%% 178: %%% Likewise against an R6 node, which is not capable of monitoring 179: %%% by name, which gives a badarg on the R7 node at the call to 180: %%% erlang:monitor(process, {Name, Node}). This has been tested 181: %%% manually at least once. 182: 183: mon_error(Type, Item) -> 184: case catch erlang:monitor(Type, Item) of 185: {'EXIT', _} -> 186: ok; 187: Other -> 188: test_server:fail({err, Other}) 189: end. 190: 191: %%% Error cases for demonitor/1 192: 193: demon_e_1(doc) -> 194: "Error cases for demonitor/1"; 195: demon_e_1(suite) -> []; 196: demon_e_1(Config) when is_list(Config) -> 197: ?line {ok, N} = test_server:start_node(hej, slave, []), 198: ?line demon_error(plutt, badarg), 199: ?line demon_error(1, badarg), 200: 201: %% Demonitor with ref created at other node 202: ?line R1 = rpc:call(N, erlang, make_ref, []), 203: ?line demon_error(R1, badarg), 204: 205: %% Demonitor with ref created at wrong monitor link end 206: ?line P0 = self(), 207: ?line P2 = spawn( 208: fun() -> 209: P0 ! {self(), ref, erlang:monitor(process,P0)}, 210: receive {P0, stop} -> ok end 211: end ), 212: ?line receive 213: {P2, ref, R2} -> 214: ?line demon_error(R2, badarg), 215: ?line P2 ! {self(), stop}; 216: Other2 -> 217: test_server:fail({rec, Other2}) 218: end, 219: 220: ?line true = test_server:stop_node(N), 221: ok. 222: 223: demon_error(Ref, Reason) -> 224: case catch erlang:demonitor(Ref) of 225: {'EXIT', {Reason, _}} -> 226: ok; 227: Other -> 228: test_server:fail({err, Other}) 229: end. 230: 231: %%% No-op cases for demonitor/1 232: 233: demon_1(doc) -> 234: "demonitor/1"; 235: demon_1(suite) -> []; 236: demon_1(Config) when is_list(Config) -> 237: ?line true = erlang:demonitor(make_ref()), 238: ok. 239: 240: 241: %%% Cases for demonitor/1 242: 243: demon_2(doc) -> 244: "Cases for demonitor/1"; 245: demon_2(suite) -> []; 246: demon_2(Config) when is_list(Config) -> 247: ?line R1 = erlang:monitor(process, self()), 248: ?line true = erlang:demonitor(R1), 249: %% Extra demonitor 250: ?line true = erlang:demonitor(R1), 251: ?line expect_no_msg(), 252: 253: %% Normal 'DOWN' 254: ?line P2 = spawn(timer, sleep, [1]), 255: ?line R2 = erlang:monitor(process, P2), 256: ?line case expect_down(R2, P2) of 257: normal -> ?line ok; 258: noproc -> ?line ok; 259: BadReason -> ?line ?t:fail({bad_reason, BadReason}) 260: end, 261: 262: %% OTP-5772 263: % %% 'DOWN' before demonitor 264: % ?line P3 = spawn(timer, sleep, [100000]), 265: % ?line R3 = erlang:monitor(process, P3), 266: % ?line exit(P3, frop), 267: % ?line erlang:demonitor(R3), 268: % ?line expect_down(R3, P3, frop), 269: 270: %% Demonitor before 'DOWN' 271: ?line P4 = spawn(timer, sleep, [100000]), 272: ?line R4 = erlang:monitor(process, P4), 273: ?line erlang:demonitor(R4), 274: ?line exit(P4, frop), 275: ?line expect_no_msg(), 276: 277: ok. 278: 279: demon_3(doc) -> 280: "Distributed case for demonitor/1 (OTP-3499)"; 281: demon_3(suite) -> []; 282: demon_3(Config) when is_list(Config) -> 283: ?line {ok, N} = test_server:start_node(hej, slave, []), 284: 285: %% 'DOWN' before demonitor 286: ?line P2 = spawn(N, timer, sleep, [100000]), 287: ?line R2 = erlang:monitor(process, P2), 288: ?line true = test_server:stop_node(N), 289: ?line true = erlang:demonitor(R2), 290: ?line expect_down(R2, P2, noconnection), 291: 292: ?line {ok, N2} = test_server:start_node(hej, slave, []), 293: 294: %% Demonitor before 'DOWN' 295: ?line P3 = spawn(N2, timer, sleep, [100000]), 296: ?line R3 = erlang:monitor(process, P3), 297: ?line true = erlang:demonitor(R3), 298: ?line true = test_server:stop_node(N2), 299: ?line expect_no_msg(), 300: 301: ok. 302: 303: demonitor_flush(suite) -> []; 304: demonitor_flush(doc) -> []; 305: demonitor_flush(Config) when is_list(Config) -> 306: ?line {'EXIT', {badarg, _}} = (catch erlang:demonitor(make_ref(), flush)), 307: ?line {'EXIT', {badarg, _}} = (catch erlang:demonitor(make_ref(), [flus])), 308: ?line {'EXIT', {badarg, _}} = (catch erlang:demonitor(x, [flush])), 309: ?line {ok, N} = test_server:start_node(demonitor_flush, slave, []), 310: ?line ok = demonitor_flush_test(N), 311: ?line true = test_server:stop_node(N), 312: ?line ok = demonitor_flush_test(node()). 313: 314: demonitor_flush_test(Node) -> 315: ?line P = spawn(Node, timer, sleep, [100000]), 316: ?line M1 = erlang:monitor(process, P), 317: ?line M2 = erlang:monitor(process, P), 318: ?line M3 = erlang:monitor(process, P), 319: ?line M4 = erlang:monitor(process, P), 320: ?line true = erlang:demonitor(M1, [flush, flush]), 321: ?line exit(P, bang), 322: ?line receive {'DOWN', M2, process, P, bang} -> ok end, 323: ?line receive after 100 -> ok end, 324: ?line true = erlang:demonitor(M3, [flush]), 325: ?line true = erlang:demonitor(M4, []), 326: ?line receive {'DOWN', M4, process, P, bang} -> ok end, 327: ?line receive 328: {'DOWN', M, _, _, _} =DM when M == M1, 329: M == M3 -> 330: ?line ?t:fail({unexpected_down_message, DM}) 331: after 100 -> 332: ?line ok 333: end. 334: 335: -define(RM_MON_GROUPS, 100). 336: -define(RM_MON_GPROCS, 100). 337: 338: 339: local_remove_monitor(Config) when is_list(Config) -> 340: Gs = generate(fun () -> start_remove_monitor_group(node()) end, 341: ?RM_MON_GROUPS), 342: {True, False} = lists:foldl(fun (G, {T, F}) -> 343: receive 344: {rm_mon_res, G, {GT, GF}} -> 345: {T+GT, F+GF} 346: end 347: end, 348: {0, 0}, 349: Gs), 350: erlang:display({local_remove_monitor, True, False}), 351: {comment, 352: "True = "++integer_to_list(True)++"; False = "++integer_to_list(False)}. 353: 354: remote_remove_monitor(Config) when is_list(Config) -> 355: ?line {ok, N} = test_server:start_node(demonitor_flush, slave, []), 356: Gs = generate(fun () -> start_remove_monitor_group(node()) end, 357: ?RM_MON_GROUPS), 358: {True, False} = lists:foldl(fun (G, {T, F}) -> 359: receive 360: {rm_mon_res, G, {GT, GF}} -> 361: {T+GT, F+GF} 362: end 363: end, 364: {0, 0}, 365: Gs), 366: erlang:display({remote_remove_monitor, True, False}), 367: ?line true = test_server:stop_node(N), 368: {comment, 369: "True = "++integer_to_list(True)++"; False = "++integer_to_list(False)}. 370: 371: start_remove_monitor_group(Node) -> 372: Master = self(), 373: spawn_link( 374: fun () -> 375: Ms = generate(fun () -> 376: P = spawn(Node, fun () -> ok end), 377: erlang:monitor(process, P) 378: end, ?RM_MON_GPROCS), 379: Res = lists:foldl(fun (M, {T, F}) -> 380: case erlang:demonitor(M, [info]) of 381: true -> 382: receive 383: {'DOWN', M, _, _, _} -> 384: exit(down_msg_found) 385: after 0 -> 386: ok 387: end, 388: {T+1, F}; 389: false -> 390: receive 391: {'DOWN', M, _, _, _} -> 392: ok 393: after 0 -> 394: exit(no_down_msg_found) 395: end, 396: {T, F+1} 397: end 398: end, 399: {0,0}, 400: Ms), 401: Master ! {rm_mon_res, self(), Res} 402: end). 403: 404: 405: %%% Cases for monitor/2 406: 407: mon_1(doc) -> 408: "Cases for monitor/2"; 409: mon_1(suite) -> []; 410: mon_1(Config) when is_list(Config) -> 411: %% Normal case 412: ?line P2 = spawn(timer, sleep, [1]), 413: ?line R2 = erlang:monitor(process, P2), 414: ?line case expect_down(R2, P2) of 415: normal -> ?line ok; 416: noproc -> ?line ok; 417: BadReason -> ?line ?t:fail({bad_reason, BadReason}) 418: end, 419: ?line {P2A,R2A} = spawn_monitor(timer, sleep, [1]), 420: ?line expect_down(R2A, P2A, normal), 421: 422: %% 'DOWN' with other reason 423: ?line P3 = spawn(timer, sleep, [100000]), 424: ?line R3 = erlang:monitor(process, P3), 425: ?line exit(P3, frop), 426: ?line expect_down(R3, P3, frop), 427: ?line {P3A,R3A} = spawn_monitor(timer, sleep, [100000]), 428: ?line exit(P3A, frop), 429: ?line expect_down(R3A, P3A, frop), 430: 431: %% Monitor fails because process is dead 432: ?line R4 = erlang:monitor(process, P3), 433: ?line expect_down(R4, P3, noproc), 434: 435: %% Normal case (named process) 436: ?line P5 = start_jeeves(jeeves), 437: ?line R5 = erlang:monitor(process, jeeves), 438: ?line tell_jeeves(P5, stop), 439: ?line expect_down(R5, {jeeves, node()}, normal), 440: 441: %% 'DOWN' with other reason and node explicit activation 442: ?line P6 = start_jeeves(jeeves), 443: ?line R6 = erlang:monitor(process, {jeeves, node()}), 444: ?line tell_jeeves(P6, {exit, frop}), 445: ?line expect_down(R6, {jeeves, node()}, frop), 446: 447: %% Monitor (named process) fails because process is dead 448: ?line R7 = erlang:monitor(process, {jeeves, node()}), 449: ?line expect_down(R7, {jeeves, node()}, noproc), 450: 451: ok. 452: 453: mon_2(doc) -> 454: "Distributed cases for monitor/2"; 455: mon_2(suite) -> []; 456: mon_2(Config) when is_list(Config) -> 457: ?line {ok, N1} = test_server:start_node(hej1, slave, []), 458: 459: %% Normal case 460: ?line P2 = spawn(N1, timer, sleep, [4000]), 461: ?line R2 = erlang:monitor(process, P2), 462: ?line expect_down(R2, P2, normal), 463: 464: %% 'DOWN' with other reason 465: ?line P3 = spawn(N1, timer, sleep, [100000]), 466: ?line R3 = erlang:monitor(process, P3), 467: ?line exit(P3, frop), 468: ?line expect_down(R3, P3, frop), 469: 470: %% Monitor fails because process is dead 471: ?line R4 = erlang:monitor(process, P3), 472: ?line expect_down(R4, P3, noproc), 473: 474: %% Other node goes down 475: ?line P5 = spawn(N1, timer, sleep, [100000]), 476: ?line R5 = erlang:monitor(process, P5), 477: 478: ?line true = test_server:stop_node(N1), 479: 480: ?line expect_down(R5, P5, noconnection), 481: 482: %% Monitor fails because other node is dead 483: ?line P6 = spawn(N1, timer, sleep, [100000]), 484: ?line R6 = erlang:monitor(process, P6), 485: ?line R6_Reason = expect_down(R6, P6), 486: ?line true = (R6_Reason == noconnection) orelse (R6_Reason == noproc), 487: 488: %% Start a new node that can load code in this module 489: ?line PA = filename:dirname(code:which(?MODULE)), 490: ?line {ok, N2} = test_server:start_node 491: (hej2, slave, [{args, "-pa " ++ PA}]), 492: 493: %% Normal case (named process) 494: ?line P7 = start_jeeves({jeeves, N2}), 495: ?line R7 = erlang:monitor(process, {jeeves, N2}), 496: ?line tell_jeeves(P7, stop), 497: ?line expect_down(R7, {jeeves, N2}, normal), 498: 499: %% 'DOWN' with other reason (named process) 500: ?line P8 = start_jeeves({jeeves, N2}), 501: ?line R8 = erlang:monitor(process, {jeeves, N2}), 502: ?line tell_jeeves(P8, {exit, frop}), 503: ?line expect_down(R8, {jeeves, N2}, frop), 504: 505: %% Monitor (named process) fails because process is dead 506: ?line R9 = erlang:monitor(process, {jeeves, N2}), 507: ?line expect_down(R9, {jeeves, N2}, noproc), 508: 509: %% Other node goes down (named process) 510: ?line _P10 = start_jeeves({jeeves, N2}), 511: ?line R10 = erlang:monitor(process, {jeeves, N2}), 512: 513: ?line true = test_server:stop_node(N2), 514: 515: ?line expect_down(R10, {jeeves, N2}, noconnection), 516: 517: %% Monitor (named process) fails because other node is dead 518: ?line R11 = erlang:monitor(process, {jeeves, N2}), 519: ?line expect_down(R11, {jeeves, N2}, noconnection), 520: 521: ok. 522: 523: %%% Large exit reason. Crashed first attempt to release R5B. 524: 525: large_exit(doc) -> 526: "Large exit reason"; 527: large_exit(suite) -> []; 528: large_exit(Config) when is_list(Config) -> 529: ?line f(100), 530: ok. 531: 532: f(0) -> 533: ok; 534: f(N) -> 535: f(), 536: f(N-1). 537: 538: f() -> 539: ?line S0 = {big, tuple, with, [list, 4563784278]}, 540: ?line S = {S0, term_to_binary(S0)}, 541: ?line P = spawn(?MODULE, large_exit_sub, [S]), 542: ?line R = erlang:monitor(process, P), 543: ?line P ! hej, 544: receive 545: {'DOWN', R, process, P, X} -> 546: ?line io:format(" -> ~p~n", [X]), 547: if 548: X == S -> 549: ok; 550: true -> 551: test_server:fail({X, S}) 552: end; 553: Other -> 554: ?line io:format(" -> ~p~n", [Other]), 555: exit({answer, Other}) 556: end. 557: 558: large_exit_sub(S) -> 559: receive _X -> ok end, 560: exit(S). 561: 562: %%% Testing of monitor link list cleanup 563: %%% by using erlang:process_info(self(), monitors) 564: %%% and erlang:process_info(self(), monitored_by) 565: 566: list_cleanup(doc) -> 567: "Testing of monitor link list cleanup by using " ++ 568: "erlang:process_info/2"; 569: list_cleanup(suite) -> []; 570: list_cleanup(Config) when is_list(Config) -> 571: ?line P0 = self(), 572: ?line M = node(), 573: ?line PA = filename:dirname(code:which(?MODULE)), 574: ?line true = register(master_bertie, self()), 575: 576: %% Normal local case, monitor and demonitor 577: ?line P1 = start_jeeves(jeeves), 578: ?line {[], []} = monitors(), 579: ?line expect_jeeves(P1, monitors, {monitors, {[], []}}), 580: ?line R1a = erlang:monitor(process, P1), 581: ?line {[{process, P1}], []} = monitors(), 582: ?line expect_jeeves(P1, monitors, {monitors, {[], [P0]}}), 583: ?line true = erlang:demonitor(R1a), 584: ?line expect_no_msg(), 585: ?line {[], []} = monitors(), 586: ?line expect_jeeves(P1, monitors, {monitors, {[], []}}), 587: %% Remonitor named and try again, now exiting the monitored process 588: ?line R1b = erlang:monitor(process, jeeves), 589: ?line {[{process, {jeeves, M}}], []} = monitors(), 590: ?line expect_jeeves(P1, monitors, {monitors, {[], [P0]}}), 591: ?line tell_jeeves(P1, stop), 592: ?line expect_down(R1b, {jeeves, node()}, normal), 593: ?line {[], []} = monitors(), 594: 595: %% Slightly weird local case - the monitoring process crashes 596: ?line P2 = start_jeeves(jeeves), 597: ?line {[], []} = monitors(), 598: ?line expect_jeeves(P2, monitors, {monitors, {[], []}}), 599: ?line {monitor_process, _R2} = 600: ask_jeeves(P2, {monitor_process, master_bertie}), 601: ?line {[], [P2]} = monitors(), 602: ?line expect_jeeves(P2, monitors, 603: {monitors, {[{process, {master_bertie, node()}}], []}}), 604: ?line tell_jeeves(P2, {exit, frop}), 605: timer:sleep(2000), 606: ?line {[], []} = monitors(), 607: 608: %% Start a new node that can load code in this module 609: ?line {ok, J} = test_server:start_node 610: (jeeves, slave, [{args, "-pa " ++ PA}]), 611: 612: %% Normal remote case, monitor and demonitor 613: ?line P3 = start_jeeves({jeeves, J}), 614: ?line {[], []} = monitors(), 615: ?line expect_jeeves(P3, monitors, {monitors, {[], []}}), 616: ?line R3a = erlang:monitor(process, P3), 617: ?line {[{process, P3}], []} = monitors(), 618: ?line expect_jeeves(P3, monitors, {monitors, {[], [P0]}}), 619: ?line true = erlang:demonitor(R3a), 620: ?line expect_no_msg(), 621: ?line {[], []} = monitors(), 622: ?line expect_jeeves(P3, monitors, {monitors, {[], []}}), 623: %% Remonitor named and try again, now exiting the monitored process 624: ?line R3b = erlang:monitor(process, {jeeves, J}), 625: ?line {[{process, {jeeves, J}}], []} = monitors(), 626: ?line expect_jeeves(P3, monitors, {monitors, {[], [P0]}}), 627: ?line tell_jeeves(P3, stop), 628: ?line expect_down(R3b, {jeeves, J}, normal), 629: ?line {[], []} = monitors(), 630: 631: %% Slightly weird remote case - the monitoring process crashes 632: ?line P4 = start_jeeves({jeeves, J}), 633: ?line {[], []} = monitors(), 634: ?line expect_jeeves(P4, monitors, {monitors, {[], []}}), 635: ?line {monitor_process, _R4} = 636: ask_jeeves(P4, {monitor_process, {master_bertie, M}}), 637: ?line {[], [P4]} = monitors(), 638: ?line expect_jeeves(P4, monitors, 639: {monitors, {[{process, {master_bertie, M}}], []}} ), 640: ?line tell_jeeves(P4, {exit, frop}), 641: timer:sleep(2000), 642: ?line {[], []} = monitors(), 643: 644: %% Now, the monitoring remote node crashes 645: ?line P5 = start_jeeves({jeeves, J}), 646: ?line {[], []} = monitors(), 647: ?line expect_jeeves(P5, monitors, {monitors, {[], []}}), 648: ?line {monitor_process, _R5} = 649: ask_jeeves(P5, {monitor_process, P0}), 650: ?line {[], [P5]} = monitors(), 651: ?line expect_jeeves(P5, monitors, 652: {monitors, {[{process, P0}], []}} ), 653: ?line test_server:stop_node(J), 654: timer:sleep(4000), 655: ?line {[], []} = monitors(), 656: 657: ?line true = unregister(master_bertie), 658: ok. 659: 660: 661: %%% Mixed internal and external monitors 662: 663: mixer(doc) -> 664: "Test mixing of internal and external monitors."; 665: mixer(Config) when is_list(Config) -> 666: ?line PA = filename:dirname(code:which(?MODULE)), 667: ?line NN = [j0,j1,j2,j3], 668: % ?line NN = [j0,j1], 669: ?line NL0 = [begin 670: {ok, J} = test_server:start_node 671: (X, slave, [{args, "-pa " ++ PA}]), 672: J 673: end || X <- NN], 674: ?line NL1 = lists:duplicate(2,node()) ++ NL0, 675: ?line Perm = perm(NL1), 676: ?line lists:foreach( 677: fun(NL) -> 678: ?line Js = [ start_jeeves({[],M}) || M <- (NL ++ NL) ], 679: ?line [ask_jeeves(P,{monitor_process,self()}) || P <- Js], 680: ?line {monitored_by,MB} = 681: process_info(self(),monitored_by), 682: ?line MBL = lists:sort(MB), 683: ?line JsL = lists:sort(Js), 684: ?line MBL = JsL, 685: ?line {monitors,[]} = process_info(self(),monitors), 686: ?line [tell_jeeves(P,{exit,flaff}) || P <- Js], 687: ?line wait_for_m([],[],200) 688: end, 689: Perm), 690: ?line lists:foreach( 691: fun(NL) -> 692: ?line Js = [ start_jeeves({[],M}) || M <- (NL ++ NL) ], 693: ?line Rs = [begin 694: {monitor_process,Ref} = 695: ask_jeeves(P,{monitor_process,self()}), 696: {P,Ref} 697: end 698: || P <- Js], 699: ?line {monitored_by,MB} = 700: process_info(self(),monitored_by), 701: ?line MBL = lists:sort(MB), 702: ?line JsL = lists:sort(Js), 703: ?line MBL = JsL, 704: ?line {monitors,[]} = process_info(self(),monitors), 705: ?line [ask_jeeves(P,{demonitor,Ref}) || {P,Ref} <- Rs], 706: ?line wait_for_m([],[],200), 707: ?line [tell_jeeves(P,{exit,flaff}) || P <- Js] 708: end, 709: Perm), 710: ?line lists:foreach( 711: fun(NL) -> 712: ?line Js = [ start_jeeves({[],M}) || M <- (NL ++ NL) ], 713: ?line [ask_jeeves(P,{monitor_process,self()}) || P <- Js], 714: ?line [erlang:monitor(process,P) || P <- Js], 715: ?line {monitored_by,MB} = 716: process_info(self(),monitored_by), 717: ?line MBL = lists:sort(MB), 718: ?line JsL = lists:sort(Js), 719: ?line MBL = JsL, 720: ?line {monitors,M} = 721: process_info(self(),monitors), 722: ?line ML = lists:sort([P||{process,P} <- M]), 723: ?line ML = JsL, 724: ?line [begin 725: tell_jeeves(P,{exit,flaff}), 726: receive {'DOWN',_,process,P,_} -> ok end 727: end || P <- Js], 728: ?line wait_for_m([],[],200) 729: end, 730: Perm), 731: ?line lists:foreach( 732: fun(NL) -> 733: ?line Js = [ start_jeeves({[],M}) || M <- (NL ++ NL) ], 734: ?line Rs = [begin 735: {monitor_process,Ref} = 736: ask_jeeves(P,{monitor_process,self()}), 737: {P,Ref} 738: end 739: || P <- Js], 740: ?line R2s = [{P,erlang:monitor(process,P)} || P <- Js], 741: ?line {monitored_by,MB} = 742: process_info(self(),monitored_by), 743: ?line MBL = lists:sort(MB), 744: ?line JsL = lists:sort(Js), 745: ?line MBL = JsL, 746: ?line {monitors,M} = 747: process_info(self(),monitors), 748: ?line ML = lists:sort([P||{process,P} <- M]), 749: ?line ML = JsL, 750: ?line [ask_jeeves(P,{demonitor,Ref}) || {P,Ref} <- Rs], 751: ?line wait_for_m(lists:sort(M),[],200), 752: ?line [erlang:demonitor(Ref) || {_P,Ref} <- R2s], 753: ?line wait_for_m([],[],200), 754: ?line [tell_jeeves(P,{exit,flaff}) || P <- Js] 755: end, 756: Perm), 757: [test_server:stop_node(K) || K <- NL0 ], 758: ok. 759: 760: named_down(doc) -> ["Test that DOWN message for a named monitor isn't" 761: " delivered until name has been unregistered"]; 762: named_down(suite) -> []; 763: named_down(Config) when is_list(Config) -> 764: ?line {A,B,C} = now(), 765: ?line Name = list_to_atom(atom_to_list(?MODULE) 766: ++ "-named_down-" 767: ++ integer_to_list(A) 768: ++ "-" ++ integer_to_list(B) 769: ++ "-" ++ integer_to_list(C)), 770: ?line Prio = process_flag(priority,high), 771: %% Spawn a bunch of high prio cpu bound processes to prevent 772: %% normal prio processes from terminating during the next 773: %% 500 ms... 774: ?line Self = self(), 775: ?line spawn_opt(fun () -> 776: WFun = fun 777: (F, hej) -> F(F, hopp); 778: (F, hopp) -> F(F, hej) 779: end, 780: NoSchedulers = erlang:system_info(schedulers_online), 781: lists:foreach(fun (_) -> 782: spawn_opt(fun () -> 783: WFun(WFun, 784: hej) 785: end, 786: [{priority,high}, 787: link]) 788: end, 789: lists:seq(1, NoSchedulers)), 790: receive after 500 -> ok end, 791: unlink(Self), 792: exit(bang) 793: end, 794: [{priority,high}, link]), 795: ?line NamedProc = spawn_link(fun () -> 796: receive after infinity -> ok end 797: end), 798: ?line true = register(Name, NamedProc), 799: ?line unlink(NamedProc), 800: ?line exit(NamedProc, bang), 801: ?line Mon = erlang:monitor(process, Name), 802: ?line receive {'DOWN',Mon, _, _, _} -> ok end, 803: ?line true = register(Name, self()), 804: ?line true = unregister(Name), 805: ?line process_flag(priority,Prio), 806: ok. 807: 808: otp_5827(doc) -> []; 809: otp_5827(suite) -> []; 810: otp_5827(Config) when is_list(Config) -> 811: %% Make a pid with the same nodename but with another creation 812: ?line [CreEnd | RPTail] 813: = lists:reverse(binary_to_list(term_to_binary(self()))), 814: ?line NewCreEnd = case CreEnd of 815: 0 -> 1; 816: 1 -> 2; 817: _ -> CreEnd - 1 818: end, 819: ?line OtherCreationPid 820: = binary_to_term(list_to_binary(lists:reverse([NewCreEnd | RPTail]))), 821: %% If the bug is present erlang:monitor(process, OtherCreationPid) 822: %% will hang... 823: ?line Parent = self(), 824: ?line Ok = make_ref(), 825: ?line spawn(fun () -> 826: Mon = erlang:monitor(process, OtherCreationPid), 827: % Should get the DOWN message right away 828: receive 829: {'DOWN', Mon, process, OtherCreationPid, noproc} -> 830: Parent ! Ok 831: end 832: end), 833: ?line receive 834: Ok -> 835: ?line ok 836: after 1000 -> 837: ?line ?t:fail("erlang:monitor/2 hangs") 838: end. 839: 840: 841: wait_for_m(_,_,0) -> 842: exit(monitor_wait_timeout); 843: wait_for_m(Monitors, MonitoredBy, N) -> 844: {monitors,M0} = process_info(self(),monitors), 845: {monitored_by,MB0} = process_info(self(),monitored_by), 846: case lists:sort(M0) of 847: Monitors -> 848: case lists:sort(MB0) of 849: MonitoredBy -> 850: ok; 851: _ -> 852: receive after 100 -> ok end, 853: wait_for_m(Monitors,MonitoredBy,N-1) 854: end; 855: _ -> 856: receive after 100 -> ok end, 857: wait_for_m(Monitors,MonitoredBy,N-1) 858: end. 859: 860: % All permutations of a list... 861: perm([]) -> 862: []; 863: perm([X]) -> 864: [[X]]; 865: perm(List) -> 866: perm([],List,[]). 867: 868: perm(_,[],Acc) -> 869: Acc; 870: perm(Pre,[El|Post],Acc) -> 871: Res = [[El|X] || X <- perm(Pre ++ Post)], 872: perm(Pre ++ [El], Post, Res ++ Acc). 873: 874: 875: %%% Our butler for named process monitor tests 876: 877: jeeves(Parent, Name, Ref) 878: when is_pid(Parent), (is_atom(Name) or (Name =:= [])), is_reference(Ref) -> 879: %%io:format("monitor_SUITE:jeeves(~p, ~p)~n", [Parent, Name]), 880: case Name of 881: Atom when is_atom(Atom) -> 882: register(Name, self()); 883: [] -> 884: ok 885: end, 886: Parent ! {self(), Ref}, 887: jeeves_loop(Parent). 888: 889: jeeves_loop(Parent) -> 890: receive 891: {Parent, monitors} -> 892: Parent ! {self(), {monitors, monitors()}}, 893: jeeves_loop(Parent); 894: {Parent, {monitor_process, P}} -> 895: Parent ! {self(), {monitor_process, 896: catch erlang:monitor(process, P) }}, 897: jeeves_loop(Parent); 898: {Parent, {demonitor, Ref}} -> 899: Parent ! {self(), {demonitor, catch erlang:demonitor(Ref)}}, 900: jeeves_loop(Parent); 901: {Parent, stop} -> 902: ok; 903: {Parent, {exit, Reason}} -> 904: exit(Reason); 905: Other -> 906: io:format("~p:jeeves_loop received ~p~n", [?MODULE, Other]) 907: end. 908: 909: 910: start_jeeves({Name, Node}) 911: when (is_atom(Name) or (Name =:= [])), is_atom(Node) -> 912: Parent = self(), 913: Ref = make_ref(), 914: Pid = spawn(Node, fun() -> jeeves(Parent, Name, Ref) end), 915: receive 916: {Pid, Ref} -> 917: ok; 918: Other -> 919: test_server:fail({rec, Other}) 920: end, 921: Pid; 922: start_jeeves(Name) when is_atom(Name) -> 923: start_jeeves({Name, node()}). 924: 925: 926: tell_jeeves(Pid, What) when is_pid(Pid) -> 927: Pid ! {self(), What}. 928: 929: 930: ask_jeeves(Pid, Request) when is_pid(Pid) -> 931: Pid ! {self(), Request}, 932: receive 933: {Pid, Response} -> 934: Response; 935: Other -> 936: test_server:fail({rec, Other}) 937: end. 938: 939: 940: expect_jeeves(Pid, Request, Response) when is_pid(Pid) -> 941: Pid ! {self(), Request}, 942: receive 943: {Pid, Response} -> 944: ok; 945: Other -> 946: test_server:fail({rec, Other}) 947: end. 948: 949: 950: monitors() -> 951: monitors(self()). 952: 953: monitors(Pid) when is_pid(Pid) -> 954: {monitors, Monitors} = process_info(self(), monitors), 955: {monitored_by, MonitoredBy} = process_info(self(), monitored_by), 956: {Monitors, MonitoredBy}. 957: 958: generate(_Fun, 0) -> 959: []; 960: generate(Fun, N) -> 961: [Fun() | generate(Fun, N-1)].