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)].