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