1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1997-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(trace_SUITE).
22
23%%%
24%%% Tests the trace BIF.
25%%%
26
27-export([all/0, suite/0, init_per_testcase/2, end_per_testcase/2,
28         link_receive_call_correlation/0,
29         receive_trace/1, link_receive_call_correlation/1, self_send/1,
30	 timeout_trace/1, send_trace/1,
31	 procs_trace/1, dist_procs_trace/1, procs_new_trace/1,
32	 suspend/1, suspend_exit/1, suspender_exit/1,
33	 suspend_system_limit/1, suspend_opts/1, suspend_waiting/1,
34	 new_clear/1, existing_clear/1, tracer_die/1,
35	 set_on_spawn/1, set_on_first_spawn/1, cpu_timestamp/1,
36	 set_on_link/1, set_on_first_link/1,
37	 system_monitor_args/1, more_system_monitor_args/1,
38	 system_monitor_long_gc_1/1, system_monitor_long_gc_2/1,
39	 system_monitor_large_heap_1/1, system_monitor_large_heap_2/1,
40	 system_monitor_long_schedule/1,
41	 bad_flag/1, trace_delivered/1, trap_exit_self_receive/1,
42         trace_info_badarg/1, erl_704/1, ms_excessive_nesting/1]).
43
44-include_lib("common_test/include/ct.hrl").
45
46%%% Internal exports
47-export([process/1]).
48
49suite() ->
50    [{ct_hooks,[ts_install_cth]},
51     {timetrap, {minutes, 1}}].
52
53all() ->
54    [cpu_timestamp, receive_trace, link_receive_call_correlation,
55     self_send, timeout_trace,
56     send_trace, procs_trace, dist_procs_trace, suspend,
57     suspend_exit, suspender_exit,
58     suspend_system_limit, suspend_opts, suspend_waiting,
59     new_clear, existing_clear, tracer_die, set_on_spawn,
60     set_on_first_spawn, set_on_link, set_on_first_link,
61     system_monitor_args,
62     more_system_monitor_args, system_monitor_long_gc_1,
63     system_monitor_long_gc_2, system_monitor_large_heap_1,
64     system_monitor_long_schedule,
65     system_monitor_large_heap_2, bad_flag, trace_delivered,
66     trap_exit_self_receive, trace_info_badarg, erl_704,
67     ms_excessive_nesting].
68
69init_per_testcase(_Case, Config) ->
70    [{receiver,spawn(fun receiver/0)}|Config].
71
72end_per_testcase(_Case, Config) ->
73    Receiver = proplists:get_value(receiver, Config),
74    unlink(Receiver),
75    exit(Receiver, die),
76    ok.
77
78%% No longer testing anything, just reporting whether cpu_timestamp
79%% is enabled or not.
80cpu_timestamp(Config) when is_list(Config) ->
81    %% Test whether cpu_timestamp is implemented on this platform.
82    Works = try erlang:trace(all, true, [cpu_timestamp]) of
83                _ ->
84                    erlang:trace(all, false, [cpu_timestamp]),
85                    true
86            catch
87                error:badarg -> false
88            end,
89    {comment,case Works of
90                 false -> "cpu_timestamp is NOT implemented/does not work";
91                 true -> "cpu_timestamp works"
92             end}.
93
94
95%% Tests that trace(Pid, How, ['receive']) works.
96
97receive_trace(Config) when is_list(Config) ->
98    Receiver = proplists:get_value(receiver, Config),
99
100    %% Trace the process; make sure that we receive the trace messages.
101    1 = erlang:trace(Receiver, true, ['receive']),
102    Hello = {hello, world},
103    Receiver ! Hello,
104    {trace, Receiver, 'receive', Hello} = receive_first_trace(),
105    Hello2 = {hello, again, world},
106    Receiver ! Hello2,
107    {trace, Receiver, 'receive', Hello2} = receive_first_trace(),
108    receive_nothing(),
109
110    %% Test 'receive' with matchspec
111    F1 = fun ({Pat, IsMatching}) ->
112		 set_trace_pattern('receive', Pat, []),
113		 Receiver ! Hello,
114		 case IsMatching of
115		     true ->
116			 {trace, Receiver, 'receive', Hello} = receive_first_trace();
117		     false ->
118			 ok
119		 end,
120		 receive_nothing()
121	 end,
122    From = self(),
123    Node = node(),
124    lists:foreach(F1, [{no, true},
125		       {[{[Node, undefined,"Unexpected"],[],[]}], false},
126		       {[{[Node, From,'_'],[],[]}], true},
127		       {[{[Node, '$1','_'],[{'=/=','$1',From}],[]}], false},
128		       {[{['$1', '_','_'],[{'=:=','$1',Node}],[]}], true},
129		       {false, false},
130		       {true, true}]),
131
132    %% Remote messages
133    OtherName = atom_to_list(?MODULE)++"_receive_trace",
134    {ok, OtherNode} = start_node(OtherName),
135    RemoteProc = spawn_link(OtherNode, ?MODULE, process, [self()]),
136    io:format("RemoteProc = ~p ~n", [RemoteProc]),
137
138    RemoteProc ! {send_please, Receiver, Hello},
139    {trace, Receiver, 'receive', Hello} = receive_first_trace(),
140    RemoteProc ! {send_please, Receiver, 99},
141    {trace, Receiver, 'receive', 99} = receive_first_trace(),
142
143    %% Remote with matchspec
144    F2 = fun (To, {Pat, IsMatching}) ->
145		 set_trace_pattern('receive', Pat, []),
146		 RemoteProc ! {send_please, To, Hello},
147		 case IsMatching of
148		     true ->
149			 {trace, Receiver, 'receive', Hello} = receive_first_trace();
150		     false ->
151			 ok
152		 end,
153		 receive_nothing()
154	 end,
155    F2(Receiver, {no, true}),
156    F2(Receiver, {[{[OtherNode, undefined,"Unexpected"],[],[]}], false}),
157    F2(Receiver, {[{[OtherNode, RemoteProc,'_'],[],[]},
158		   {[OtherNode, undefined,'_'],[],[]}], true}),
159    F2(Receiver, {[{[OtherNode, '$1','_'],
160		    [{'orelse',{'=:=','$1',undefined},{'=/=',{node,'$1'},{node}}}],
161		    []}], true}),
162    F2(Receiver, {[{['$1', '_','_'], [{'=:=','$1',OtherNode}], []}], true}),
163    F2(Receiver, {false, false}),
164    F2(Receiver, {true, true}),
165
166    %% Remote to named with matchspec
167    Name = trace_SUITE_receiver,
168    register(Name, Receiver),
169    NN = {Name, node()},
170    F2(NN, {no, true}),
171    F2(NN, {[{[OtherNode, undefined,"Unexpected"],[],[]}], false}),
172    F2(NN, {[{[OtherNode, RemoteProc,'_'],[],[]},
173	     {[OtherNode, undefined,'_'],[],[]}], true}),
174    F2(NN, {[{[OtherNode, '$1','_'],
175	      [{'orelse',{'=:=','$1',undefined},{'=/=',{node,'$1'},{node}}}],
176	      []}], true}),
177    F2(NN, {[{['$1', '_','_'], [{'==','$1',OtherNode}], []}], true}),
178    F2(NN, {false, false}),
179    F2(NN, {true, true}),
180
181    unlink(RemoteProc),
182    true = stop_node(OtherNode),
183
184    %% Timeout
185    Receiver ! {set_timeout, 10},
186    {trace, Receiver, 'receive', {set_timeout, 10}} = receive_first_trace(),
187    {trace, Receiver, 'receive', timeout} = receive_first_trace(),
188    erlang:trace_pattern('receive', [{[clock_service,undefined,timeout], [], []}], []),
189    Receiver ! {set_timeout, 7},
190    {trace, Receiver, 'receive', timeout} = receive_first_trace(),
191    erlang:trace_pattern('receive', true, []),
192
193    %% Another process should not be able to trace Receiver.
194    process_flag(trap_exit, true),
195    Intruder = fun_spawn(fun() -> erlang:trace(Receiver, true, ['receive']) end),
196    {'EXIT', Intruder, {badarg, _}} = receive_first(),
197
198    %% Untrace the process; we should not receive anything.
199    1 = erlang:trace(Receiver, false, ['receive']),
200    Receiver ! {hello, there},
201    Receiver ! any_garbage,
202    receive_nothing(),
203
204    %% Verify restrictions in matchspec for 'receive'
205    F3 = fun (Pat) -> {'EXIT', {badarg,_}} = (catch erlang:trace_pattern('receive', Pat, [])) end,
206    WC = ['_','_','_'],
207    F3([{WC,[],[{message, {process_dump}}]}]),
208    F3([{WC,[{is_seq_trace}],[]}]),
209    F3([{WC,[],[{set_seq_token,label,4711}]}]),
210    F3([{WC,[],[{get_seq_token}]}]),
211    F3([{WC,[],[{enable_trace,call}]}]),
212    F3([{WC,[],[{enable_trace,self(),call}]}]),
213    F3([{WC,[],[{disable_trace,call}]}]),
214    F3([{WC,[],[{disable_trace,self(),call}]}]),
215    F3([{WC,[],[{trace,[call],[]}]}]),
216    F3([{WC,[],[{trace,self(),[],[call]}]}]),
217    F3([{WC,[],[{caller}]}]),
218    F3([{WC,[],[{silent,true}]}]),
219
220    ok.
221
222%% Tests that receive of a message always happens before a call with
223%% that message and that links/unlinks are ordered together with the
224%% 'receive'.
225link_receive_call_correlation() ->
226    [{timetrap, {minutes, 5}}].
227link_receive_call_correlation(Config) when is_list(Config) ->
228    Receiver = fun_spawn(fun F() ->
229                                 receive
230                                     stop -> ok;
231                                     M -> receive_msg(M), F()
232                                 end
233                         end),
234    process_flag(trap_exit, true),
235
236    %% Trace the process; make sure that we receive the trace messages.
237    1 = erlang:trace(Receiver, true, ['receive', procs, call, timestamp, scheduler_id]),
238    1 = erlang:trace_pattern({?MODULE, receive_msg, '_'}, [], [local]),
239
240    Num = 100,
241
242    (fun F(0) -> [];
243         F(N) ->
244             if N rem 2 == 0 ->
245                     link(Receiver);
246                true ->
247                     unlink(Receiver)
248             end,
249             [Receiver ! N | F(N-1)]
250     end)(Num),
251
252    Receiver ! stop,
253    MonRef = erlang:monitor(process, Receiver),
254    receive {'DOWN', MonRef, _, _, _} -> ok end,
255    Ref = erlang:trace_delivered(Receiver),
256    receive {trace_delivered, _, Ref} -> ok end,
257
258    Msgs = (fun F() -> receive M -> [M | F()] after 1 -> [] end end)(),
259
260    case check_consistent(Receiver, Num, Num, Num, Msgs, false, undefined) of
261        ok ->
262            ok;
263        {error, Reason} ->
264            ct:log("~p", [Msgs]),
265            ct:fail({error, Reason})
266    end.
267
268-define(schedid, , _).
269
270check_consistent(_Pid, Recv, Call, _LU, [Msg | _], _Received, _LinkedN) when Recv > Call ->
271    {error, Msg};
272check_consistent(Pid, Recv, Call, LU, [Msg | Msgs], false, undefined) ->
273
274    case Msg of
275        {trace, Pid, 'receive', Recv ?schedid} ->
276            check_consistent(Pid,Recv - 1, Call, LU, Msgs, true, undefined);
277        {trace_ts, Pid, 'receive', Recv ?schedid, _} ->
278            check_consistent(Pid,Recv - 1, Call, LU, Msgs, true, undefined);
279
280        {trace, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid} ->
281            check_consistent(Pid,Recv, Call - 1, LU, Msgs, false, undefined);
282        {trace_ts, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid, _} ->
283            check_consistent(Pid,Recv, Call - 1, LU, Msgs, false, undefined);
284
285        {trace, Pid, _, _Self ?schedid} ->
286            check_consistent(Pid, Recv, Call, LU, Msgs, false, undefined);
287        {trace_ts, Pid, _, _Self ?schedid, _} ->
288            check_consistent(Pid, Recv, Call, LU, Msgs, false, undefined);
289
290        Msg ->
291            {error, Msg}
292    end;
293check_consistent(Pid, Recv, Call, LU, [Msg | Msgs], true, undefined) ->
294
295    case Msg of
296        {trace, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid} ->
297            check_consistent(Pid,Recv, Call - 1, LU, Msgs, true, undefined);
298        {trace_ts, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid, _} ->
299            check_consistent(Pid,Recv, Call - 1, LU, Msgs, true, undefined);
300
301        {trace, Pid, getting_linked, _Self ?schedid} ->
302            check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, Recv rem 2);
303        {trace_ts, Pid, getting_linked, _Self ?schedid, _} ->
304            check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, Recv rem 2);
305
306        {trace, Pid, getting_unlinked, _Self ?schedid} ->
307            check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, (Recv+1) rem 2);
308        {trace_ts, Pid, getting_unlinked, _Self ?schedid, _} ->
309            check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, (Recv+1) rem 2);
310
311        Msg ->
312            {error, Msg}
313    end;
314check_consistent(Pid, Recv, Call, LU, [Msg | Msgs], true, LinkedN) ->
315    UnlinkedN = (LinkedN + 1) rem 2,
316
317    case Msg of
318        {trace, Pid, 'receive', Recv ?schedid} when Recv == LU ->
319            check_consistent(Pid,Recv - 1, Call, LU, Msgs, true, LinkedN);
320        {trace_ts, Pid, 'receive', Recv ?schedid, _} when Recv == LU ->
321            check_consistent(Pid,Recv - 1, Call, LU, Msgs, true, LinkedN);
322
323        {trace, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid} ->
324            check_consistent(Pid,Recv, Call - 1, LU, Msgs, true, LinkedN);
325        {trace_ts, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid, _} ->
326            check_consistent(Pid,Recv, Call - 1, LU, Msgs, true, LinkedN);
327
328        %% We check that for each receive we have gotten a
329        %% getting_linked or getting_unlinked message. Also
330        %% if we receive a getting_linked, then the next
331        %% message we expect to receive is an even number
332        %% and odd number for getting_unlinked.
333        {trace, Pid, getting_linked, _Self ?schedid}
334          when Recv rem 2 == LinkedN ->
335            check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, LinkedN);
336        {trace_ts, Pid, getting_linked, _Self ?schedid, _}
337          when Recv rem 2 == LinkedN ->
338            check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, LinkedN);
339
340        {trace, Pid, getting_unlinked, _Self ?schedid}
341          when Recv rem 2 == UnlinkedN ->
342            check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, LinkedN);
343        {trace_ts, Pid, getting_unlinked, _Self ?schedid, _}
344          when Recv rem 2 == UnlinkedN ->
345            check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, LinkedN);
346
347        {trace,Pid,'receive',Ignore ?schedid}
348          when Ignore == stop; Ignore == timeout ->
349            check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN);
350        {trace_ts,Pid,'receive',Ignore ?schedid,_}
351          when Ignore == stop; Ignore == timeout ->
352            check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN);
353
354        {trace, Pid, exit, normal ?schedid} ->
355            check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN);
356        {trace_ts, Pid, exit, normal  ?schedid, _} ->
357            check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN);
358        {'EXIT', Pid, normal} ->
359            check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN);
360        Msg ->
361            {error, Msg}
362    end;
363check_consistent(_, 0, 0, 1, [], true, _) ->
364    ok;
365check_consistent(_, Recv, Call, LU, [], _, _) ->
366    {error,{Recv, Call, LU}}.
367
368receive_msg(M) ->
369    M.
370
371%% Test that traces are generated for messages sent
372%% and received to/from self().
373self_send(Config) when is_list(Config) ->
374    Fun =
375    fun(Self, Parent) -> receive
376                             go_ahead ->
377                                 self() ! from_myself,
378                                 Self(Self, Parent);
379                             from_myself ->
380                                 Parent ! done
381                         end
382    end,
383    Self = self(),
384    SelfSender = fun_spawn(Fun, [Fun, Self]),
385    erlang:trace(SelfSender, true, ['receive', 'send']),
386    SelfSender ! go_ahead,
387    receive {trace, SelfSender, 'receive', go_ahead} -> ok end,
388    receive {trace, SelfSender, 'receive', from_myself} -> ok end,
389    receive
390        {trace,SelfSender,send,from_myself,SelfSender} -> ok
391    end,
392    receive {trace,SelfSender,send,done,Self} -> ok end,
393    receive done -> ok end,
394    ok.
395
396%% Test that we can receive timeout traces.
397timeout_trace(Config) when is_list(Config) ->
398    Process = fun_spawn(fun process/0),
399    1 = erlang:trace(Process, true, ['receive']),
400    Process ! timeout_please,
401    {trace, Process, 'receive', timeout_please} = receive_first_trace(),
402    {trace, Process, 'receive', timeout} = receive_first_trace(),
403    receive_nothing(),
404    ok.
405
406%% Tests that trace(Pid, How, [send]) works.
407
408send_trace(Config) when is_list(Config) ->
409    process_flag(trap_exit, true),
410    Sender = fun_spawn(fun sender/0),
411    Receiver = proplists:get_value(receiver, Config),
412
413    %% Check that a message sent to another process is traced.
414    1 = erlang:trace(Sender, true, [send]),
415    F1 = fun (Pat) ->
416		 set_trace_pattern(send, Pat, []),
417		 Sender ! {send_please, Receiver, to_receiver},
418		 {trace, Sender, send, to_receiver, Receiver} = receive_first_trace(),
419		 receive_nothing()
420	 end,
421    lists:foreach(F1, [no,
422		       [{[Receiver,to_receiver],[],[]}],
423		       [{['_','_'],[],[]}],
424		       [{['$1','_'],[{is_pid,'$1'}],[]}],
425		       [{['_','$1'],[{is_atom,'$1'}],[]}],
426		       true]),
427
428    %% Test {message, Msg}
429    F1m = fun ({Pat, Msg}) ->
430		 set_trace_pattern(send, Pat, []),
431		 Sender ! {send_please, Receiver, to_receiver},
432		 {trace, Sender, send, to_receiver, Receiver, Msg} = receive_first_trace(),
433		 receive_nothing()
434	 end,
435    lists:foreach(F1m, [{[{['_','_'],[],[{message, 4711}]}], 4711},
436			{[{['_','_'],[],[{message, "4711"}]}], "4711"}
437		       ]),
438
439    %% Test {message, {process_dump}}
440    set_trace_pattern(send, [{['_','_'],[],[{message, {process_dump}}]}], []),
441    Sender ! {send_please, Receiver, to_receiver},
442    {trace, Sender, send, to_receiver, Receiver, ProcDump} = receive_first_trace(),
443    true = is_binary(ProcDump),
444    receive_nothing(),
445
446    %% Same test with false match spec
447    F2 = fun (Pat) ->
448		 set_trace_pattern(send, Pat, []),
449		 Sender ! {send_please, Receiver, to_receiver},
450		 receive_nothing()
451	 end,
452    lists:foreach(F2, [[{[Sender,to_receiver],[],[]}],
453		       [{[Receiver,nomatch],[],[]}],
454		       [{['$1','_'],[{is_atom,'$1'}],[]}],
455		       [{['_','$1'],[{is_pid,'$1'}],[]}],
456		       false,
457		       [{['_','_'],[],[{message,false}]}],
458		       [{['_','_'],[],[{silent,true}]}]]),
459    erlang:trace_pattern(send, true, []),
460    erlang:trace(Sender, false, [silent]),
461
462    %% Check that a message sent to another registered process is traced.
463    register(?MODULE,Receiver),
464    F3 = fun (Pat) ->
465		 set_trace_pattern(send, Pat, []),
466		 Sender ! {send_please, ?MODULE, to_receiver},
467		 {trace, Sender, send, to_receiver, ?MODULE} = receive_first_trace(),
468		 receive_nothing()
469	 end,
470    lists:foreach(F3, [no,
471		       [{[?MODULE,to_receiver],[],[]}],
472		       [{['_','_'],[],[]}],
473		       [{['$1','_'],[{is_atom,'$1'}],[]}],
474		       [{['_','$1'],[{is_atom,'$1'}],[]}],
475		       true]),
476    %% Again with false match spec
477    F4 = fun (Pat) ->
478		 set_trace_pattern(send, Pat, []),
479		 Sender ! {send_please, ?MODULE, to_receiver},
480		 receive_nothing()
481	 end,
482    lists:foreach(F4, [[{[nomatch,to_receiver],[],[]}],
483		       [{[?MODULE,nomatch],[],[]}],
484		       [{['$1','_'],[{is_pid,'$1'}],[]}],
485		       [{['_','$1'],[{is_pid,'$1'}],[]}],
486		       [{['_','_'],[],[{message,false}]}],
487		       [{['_','_'],[],[{silent,true}]}]
488		      ]),
489    unregister(?MODULE),
490    erlang:trace_pattern(send, true, []),
491    erlang:trace(Sender, false, [silent]),
492
493    %% Check that a message sent to this process is traced.
494    F5 = fun (Pat) ->
495		 set_trace_pattern(send, Pat, []),
496		 Sender ! {send_please, self(), to_myself},
497		 receive to_myself -> ok end,
498		 Self = self(),
499		 {trace, Sender, send, to_myself, Self} = receive_first_trace(),
500		 receive_nothing()
501	 end,
502    lists:foreach(F5, [no,
503		       [{[self(),to_myself],[],[]}],
504		       [{['_','_'],[],[]}],
505		       true]),
506
507    %% Check that a message sent to dead process is traced.
508    {Pid,Ref} = spawn_monitor(fun() -> ok end),
509    receive {'DOWN',Ref,_,_,_} -> ok end,
510    F6 = fun (Pat) ->
511		 set_trace_pattern(send, Pat, []),
512		 Sender ! {send_please, Pid, to_dead},
513		 {trace, Sender, send_to_non_existing_process, to_dead, Pid} = receive_first_trace(),
514		 receive_nothing()
515	 end,
516    lists:foreach(F6, [no,
517		       [{[Pid,to_dead],[],[]}],
518		       [{['_','_'],[],[]}],
519		       true]),
520
521    %% Check that a message sent to unknown registrated process is traced.
522    BadargSender = fun_spawn(fun sender/0),
523    1 = erlang:trace(BadargSender, true, [send]),
524    unlink(BadargSender),
525    BadargSender ! {send_please, not_registered, to_unknown},
526    {trace, BadargSender, send, to_unknown, not_registered} = receive_first_trace(),
527    receive_nothing(),
528
529    %% Another process should not be able to trace Sender.
530    Intruder = fun_spawn(fun() -> erlang:trace(Sender, true, [send]) end),
531    {'EXIT', Intruder, {badarg, _}} = receive_first(),
532
533    %% Untrace the sender process and make sure that we receive no more
534    %% trace messages.
535    1 = erlang:trace(Sender, false, [send]),
536    Sender ! {send_please, Receiver, to_receiver},
537    Sender ! {send_please, self(), to_myself_again},
538    receive to_myself_again -> ok end,
539    receive_nothing(),
540
541    {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [global])),
542    {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [local])),
543    {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [meta])),
544    {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [{meta,self()}])),
545    {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [call_count])),
546    {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [call_time])),
547    {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, restart, [])),
548    {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, pause, [])),
549    {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, [{['_','_'],[],[{caller}]}], [])),
550
551    %% Done.
552    ok.
553
554set_trace_pattern(_, no, _) -> 0;
555set_trace_pattern(MFA, Pat, Flg) ->
556    R = erlang:trace_pattern(MFA, Pat, Flg),
557    {match_spec, Pat} = erlang:trace_info(MFA, match_spec),
558    R.
559
560%% Test trace(Pid, How, [procs]).
561procs_trace(Config) when is_list(Config) ->
562    Name = list_to_atom(atom_to_list(?MODULE)++"_procs_trace"),
563    Self = self(),
564    process_flag(trap_exit, true),
565    %%
566    Proc1 = spawn_link(?MODULE, process, [Self]),
567    io:format("Proc1 = ~p ~n", [Proc1]),
568    Proc2 = spawn(?MODULE, process, [Self]),
569    io:format("Proc2 = ~p ~n", [Proc2]),
570    %%
571    1 = erlang:trace(Proc1, true, [procs, set_on_first_spawn]),
572    MFA = {?MODULE, process, [Self]},
573    %%
574    %% spawn, link
575    Proc1 ! {spawn_link_please, Self, MFA},
576    Proc3 = receive {spawned, Proc1, P3} -> P3 end,
577    receive {trace, Proc3, spawned, Proc1, MFA} -> ok end,
578    receive {trace, Proc3, getting_linked, Proc1} -> ok end,
579    {trace, Proc1, spawn, Proc3, MFA} = receive_first_trace(),
580    io:format("Proc3 = ~p ~n", [Proc3]),
581    {trace, Proc1, link, Proc3} = receive_first_trace(),
582    receive_nothing(),
583    %%
584    %% getting_unlinked by exit()
585    Proc1 ! {trap_exit_please, true},
586    Reason3 = make_ref(),
587    Proc1 ! {send_please, Proc3, {exit_please, Reason3}},
588    receive {Proc1, {'EXIT', Proc3, Reason3}} -> ok end,
589    receive {trace, Proc3, exit, Reason3} -> ok end,
590    {trace, Proc1, getting_unlinked, Proc3} = receive_first_trace(),
591    Proc1 ! {trap_exit_please, false},
592    receive_nothing(),
593    %%
594    %% link
595    Proc1 ! {link_please, Proc2},
596    {trace, Proc1, link, Proc2} = receive_first_trace(),
597    receive_nothing(),
598    %%
599    %% unlink
600    Proc1 ! {unlink_please, Proc2},
601    {trace, Proc1, unlink, Proc2} = receive_first_trace(),
602    receive_nothing(),
603    %%
604    %% getting_linked
605    Proc2 ! {link_please, Proc1},
606    {trace, Proc1, getting_linked, Proc2} = receive_first_trace(),
607    receive_nothing(),
608    %%
609    %% getting_unlinked
610    Proc2 ! {unlink_please, Proc1},
611    {trace, Proc1, getting_unlinked, Proc2} = receive_first_trace(),
612    receive_nothing(),
613    %%
614    %% register
615    true = register(Name, Proc1),
616    {trace, Proc1, register, Name} = receive_first_trace(),
617    receive_nothing(),
618    %%
619    %% unregister
620    true = unregister(Name),
621    {trace, Proc1, unregister, Name} = receive_first_trace(),
622    receive_nothing(),
623    %%
624    %% exit (with registered name, due to link)
625    Reason4 = make_ref(),
626    Proc1 ! {spawn_link_please, Self, MFA},
627    Proc4 = receive {spawned, Proc1, P4} -> P4 end,
628    {trace, Proc1, spawn, Proc4, MFA} = receive_first_trace(),
629    io:format("Proc4 = ~p ~n", [Proc4]),
630    {trace, Proc1, link, Proc4} = receive_first_trace(),
631    Proc1 ! {register_please, Name, Proc1},
632    {trace, Proc1, register, Name} = receive_first_trace(),
633    Proc4 ! {exit_please, Reason4},
634    receive {'EXIT', Proc1, Reason4} -> ok end,
635    {trace, Proc1, exit, Reason4} = receive_first_trace(),
636    {trace, Proc1, unregister, Name} = receive_first_trace(),
637    receive_nothing(),
638    %%
639    %% exit (not linked to tracing process)
640    1 = erlang:trace(Proc2, true, [procs]),
641    Reason2 = make_ref(),
642    Proc2 ! {exit_please, Reason2},
643    {trace, Proc2, exit, Reason2} = receive_first_trace(),
644    receive_nothing(),
645    ok.
646
647
648dist_procs_trace(Config) when is_list(Config) ->
649    ct:timetrap({seconds, 15}),
650    OtherName = atom_to_list(?MODULE)++"_dist_procs_trace",
651    {ok, OtherNode} = start_node(OtherName),
652    Self = self(),
653    process_flag(trap_exit, true),
654    %%
655    Proc1 = spawn_link(?MODULE, process, [Self]),
656    io:format("Proc1 = ~p ~n", [Proc1]),
657    Proc2 = spawn(OtherNode, ?MODULE, process, [Self]),
658    io:format("Proc2 = ~p ~n", [Proc2]),
659    %%
660    1 = erlang:trace(Proc1, true, [procs]),
661    MFA = {?MODULE, process, [Self]},
662    %%
663    %% getting_unlinked by exit()
664    Proc1 ! {spawn_link_please, Self, OtherNode, MFA},
665    Proc1 ! {trap_exit_please, true},
666    Proc3 = receive {spawned, Proc1, P3} -> P3 end,
667    io:format("Proc3 = ~p ~n", [Proc3]),
668    {trace, Proc1, link, Proc3} = receive_first_trace(),
669    Reason3 = make_ref(),
670    Proc1 ! {send_please, Proc3, {exit_please, Reason3}},
671    receive {Proc1, {'EXIT', Proc3, Reason3}} -> ok end,
672    {trace, Proc1, getting_unlinked, Proc3} = receive_first_trace(),
673    Proc1 ! {trap_exit_please, false},
674    receive_nothing(),
675    %%
676    %% link
677    Proc1 ! {link_please, Proc2},
678    {trace, Proc1, link, Proc2} = receive_first_trace(),
679    receive_nothing(),
680    %%
681    %% unlink
682    Proc1 ! {unlink_please, Proc2},
683    {trace, Proc1, unlink, Proc2} = receive_first_trace(),
684    receive_nothing(),
685    %%
686    %% getting_linked
687    Proc2 ! {link_please, Proc1},
688    {trace, Proc1, getting_linked, Proc2} = receive_first_trace(),
689    receive_nothing(),
690    %%
691    %% getting_unlinked
692    Proc2 ! {unlink_please, Proc1},
693    {trace, Proc1, getting_unlinked, Proc2} = receive_first_trace(),
694    receive_nothing(),
695
696    %%
697    %% exit (with registered name, due to link)
698    Name = list_to_atom(OtherName),
699    Reason2 = make_ref(),
700    Proc1 ! {link_please, Proc2},
701    {trace, Proc1, link, Proc2} = receive_first_trace(),
702    Proc1 ! {register_please, Name, Proc1},
703    {trace, Proc1, register, Name} = receive_first_trace(),
704    Proc2 ! {exit_please, Reason2},
705    receive {'EXIT', Proc1, Reason2} -> ok end,
706    {trace, Proc1, exit, Reason2} = receive_first_trace(),
707    {trace, Proc1, unregister, Name} = receive_first_trace(),
708    receive_nothing(),
709    %%
710    %% Done.
711    true = stop_node(OtherNode),
712    ok.
713
714%% Test trace(new, How, [procs]).
715procs_new_trace(Config) when is_list(Config) ->
716    Self = self(),
717    process_flag(trap_exit, true),
718    %%
719    Proc1 = spawn_link(?MODULE, process, [Self]),
720    io:format("Proc1 = ~p ~n", [Proc1]),
721    %%
722    0 = erlang:trace(new, true, [procs]),
723
724    MFA = {?MODULE, process, [Self]},
725    %%
726    %% spawn, link
727    Proc1 ! {spawn_link_please, Self, MFA},
728    Proc3 = receive {spawned, Proc1, P3} -> P3 end,
729    receive {trace, Proc3, spawned, Proc1, MFA} -> ok end,
730    receive {trace, Proc3, getting_linked, Proc1} -> ok end,
731    io:format("Proc3 = ~p ~n", [Proc3]),
732    receive_nothing(),
733    %%
734    %%
735    %% exit (not linked to tracing process)
736    Reason1 = make_ref(),
737    Proc1 ! {exit_please, Reason1},
738    receive {'EXIT', Proc1, Reason1} -> ok end,
739    {trace, Proc3, exit, Reason1} = receive_first_trace(),
740    receive_nothing(),
741    ok.
742
743
744
745%% Tests trace(Pid, How, [set_on_spawn]).
746
747set_on_spawn(Config) when is_list(Config) ->
748    Listener = fun_spawn(fun process/0),
749
750    %% Create and trace a process with the set_on_spawn flag.
751    %% Make sure it is traced.
752    Father_SOS = fun_spawn(fun process/0),
753    1 = erlang:trace(Father_SOS, true, [send, set_on_spawn]),
754    true = is_send_traced(Father_SOS, Listener, sos_father),
755
756    %% Have the process spawn of two children and test that they
757    %% are traced.
758    [Child1, Child2] = spawn_children(Father_SOS, 2),
759    true = is_send_traced(Child1, Listener, child1),
760    true = is_send_traced(Child2, Listener, child2),
761
762    %% Second generation.
763    [Child11, Child12] = spawn_children(Child1, 2),
764    true = is_send_traced(Child11, Listener, child11),
765    true = is_send_traced(Child12, Listener, child12),
766    ok.
767
768%% Tests trace(Pid, How, [set_on_first_spawn]).
769
770set_on_first_spawn(Config) when is_list(Config) ->
771    ct:timetrap({seconds, 10}),
772    Listener = fun_spawn(fun process/0),
773
774    %% Create and trace a process with the set_on_first_spawn flag.
775    %% Make sure it is traced.
776    Parent = fun_spawn(fun process/0),
777    1 = erlang:trace(Parent, true, [send, set_on_first_spawn]),
778    is_send_traced(Parent, Listener, sos_father),
779
780    %% Have the process spawn off three children and test that the
781    %% first is traced.
782    [Child1, Child2, Child3] = spawn_children(Parent, 3),
783    true = is_send_traced(Child1, Listener, child1),
784    false = is_send_traced(Child2, Listener, child2),
785    false = is_send_traced(Child3, Listener, child3),
786    receive_nothing(),
787    ok.
788
789%% Tests trace(Pid, How, [set_on_link]).
790
791set_on_link(_Config) ->
792    Listener = fun_spawn(fun process/0),
793
794    %% Create and trace a process with the set_on_link flag.
795    %% Make sure it is traced.
796    Father_SOL = fun_spawn(fun process/0),
797    1 = erlang:trace(Father_SOL, true, [send, set_on_link]),
798    true = is_send_traced(Father_SOL, Listener, sol_father),
799
800    %% Have the process spawn of two children and test that they
801    %% are traced.
802    [Child1, Child2] = spawn_children(Father_SOL, 2),
803    true = is_send_traced(Child1, Listener, child1),
804    true = is_send_traced(Child2, Listener, child2),
805
806    %% Second generation.
807    [Child11, Child12] = spawn_children(Child1, 2),
808    true = is_send_traced(Child11, Listener, child11),
809    true = is_send_traced(Child12, Listener, child12),
810    ok.
811
812%% Tests trace(Pid, How, [set_on_first_spawn]).
813
814set_on_first_link(_Config) ->
815    ct:timetrap({seconds, 10}),
816    Listener = fun_spawn(fun process/0),
817
818    %% Create and trace a process with the set_on_first_spawn flag.
819    %% Make sure it is traced.
820    Parent = fun_spawn(fun process/0),
821    1 = erlang:trace(Parent, true, [send, set_on_first_link]),
822    is_send_traced(Parent, Listener, sol_father),
823
824    %% Have the process spawn off three children and test that the
825    %% first is traced.
826    [Child1, Child2, Child3] = spawn_children(Parent, 3),
827    true = is_send_traced(Child1, Listener, child1),
828    false = is_send_traced(Child2, Listener, child2),
829    false = is_send_traced(Child3, Listener, child3),
830    receive_nothing(),
831    ok.
832
833
834
835%% Tests arguments to erlang:system_monitor/0,1,2
836system_monitor_args(Config) when is_list(Config) ->
837    Self = self(),
838    %%
839    OldMonitor = erlang:system_monitor(undefined),
840    undefined = erlang:system_monitor(Self, [{long_gc,0}]),
841    MinT = case erlang:system_monitor() of
842               {Self,[{long_gc,T}]} when is_integer(T), T > 0 -> T;
843               Other1 -> test_server:fault(Other1)
844           end,
845    {Self,[{long_gc,MinT}]} = erlang:system_monitor(),
846    {Self,[{long_gc,MinT}]} =
847    erlang:system_monitor({Self,[{large_heap,0}]}),
848    MinN = case erlang:system_monitor() of
849               {Self,[{large_heap,N}]} when is_integer(N), N > 0 -> N;
850               Other2 -> test_server:fault(Other2)
851           end,
852    {Self,[{large_heap,MinN}]} = erlang:system_monitor(),
853    {Self,[{large_heap,MinN}]} =
854    erlang:system_monitor(Self, [busy_port]),
855    {Self,[busy_port]} = erlang:system_monitor(),
856    {Self,[busy_port]} =
857    erlang:system_monitor({Self,[busy_dist_port]}),
858    {Self,[busy_dist_port]} = erlang:system_monitor(),
859    All = lists:sort([busy_port,busy_dist_port,
860                      {long_gc,1},{large_heap,65535}]),
861    {Self,[busy_dist_port]} = erlang:system_monitor(Self, All),
862    {Self,A1} = erlang:system_monitor(),
863    All = lists:sort(A1),
864    {Self,A1} = erlang:system_monitor(Self, []),
865    Pid = spawn(fun () -> receive {Self,die} -> exit(die) end end),
866    Mref = erlang:monitor(process, Pid),
867    undefined = erlang:system_monitor(Pid, All),
868    {Pid,A2} = erlang:system_monitor(),
869    All = lists:sort(A2),
870    Pid ! {Self,die},
871    receive {'DOWN',Mref,_,_,_} -> ok end,
872    undefined = erlang:system_monitor(OldMonitor),
873    erlang:yield(),
874    OldMonitor = erlang:system_monitor(),
875    %%
876    {'EXIT',{badarg,_}} = (catch erlang:system_monitor(atom)),
877    {'EXIT',{badarg,_}} = (catch erlang:system_monitor({})),
878    {'EXIT',{badarg,_}} = (catch erlang:system_monitor({1})),
879    {'EXIT',{badarg,_}} = (catch erlang:system_monitor({1,2,3})),
880    {'EXIT',{badarg,_}} =
881    (catch erlang:system_monitor({Self,atom})),
882    {'EXIT',{badarg,_}} =
883    (catch erlang:system_monitor(atom, atom)),
884    {'EXIT',{badarg,_}} =
885    (catch erlang:system_monitor({Self,[busy_port|busy_dist_port]})),
886    {'EXIT',{badarg,_}} =
887    (catch erlang:system_monitor(Self, [{long_gc,-1}])),
888    {'EXIT',{badarg,_}} =
889    (catch erlang:system_monitor({Self,[{long_gc,atom}]})),
890    {'EXIT',{badarg,_}} =
891    (catch erlang:system_monitor(Self,[{large_heap,-1}])),
892    {'EXIT',{badarg,_}} =
893    (catch erlang:system_monitor({Self,[{large_heap,atom}]})),
894    ok.
895
896
897%% Tests arguments to erlang:system_monitor/0,1,2
898more_system_monitor_args(Config) when is_list(Config) ->
899    try_l(64000),
900    try_l(16#7ffffff),
901    try_l(16#3fffffff),
902    try_l(16#7fffffff),
903    try_l(16#ffffffff),
904    ok.
905
906try_l(Val) ->
907    Self = self(),
908    Arbitrary1 = 77777,
909    Arbitrary2 = 88888,
910
911    erlang:system_monitor(undefined),
912
913    undefined = erlang:system_monitor(Self, [{long_gc,Val},{large_heap,Arbitrary1}]),
914
915    {Self,Comb0} = erlang:system_monitor(Self, [{long_gc,Arbitrary2},{large_heap,Val}]),
916    [{large_heap,Arbitrary1},{long_gc,Val}] = lists:sort(Comb0),
917
918    {Self,Comb1} = erlang:system_monitor(undefined),
919    [{large_heap,Val},{long_gc,Arbitrary2}] = lists:sort(Comb1).
920
921monitor_sys(Parent) ->
922    receive
923        {monitor,Pid,long_schedule,Data} when is_pid(Pid) ->
924            io:format("Long schedule of ~w: ~w~n",[Pid,Data]),
925            Parent ! {Pid,Data},
926            monitor_sys(Parent);
927        {monitor,Port,long_schedule,Data} when is_port(Port) ->
928            {name,Name} = erlang:port_info(Port,name),
929            io:format("Long schedule of ~w (~p): ~w~n",[Port,Name,Data]),
930            Parent ! {Port,Data},
931            monitor_sys(Parent);
932        Other ->
933            erlang:display(Other)
934    end.
935
936start_monitor() ->
937    Parent = self(),
938    Mpid = spawn_link(fun() -> monitor_sys(Parent) end),
939    erlang:system_monitor(Mpid,[{long_schedule,100}]),
940    erlang:yield(), % Need to be rescheduled for the trace to take
941    ok.
942
943%% Tests erlang:system_monitor(Pid, [{long_schedule,Time}])
944system_monitor_long_schedule(Config) when is_list(Config) ->
945    Path = proplists:get_value(data_dir, Config),
946    erl_ddll:start(),
947    case (catch load_driver(Path, slow_drv)) of
948        ok ->
949            do_system_monitor_long_schedule();
950        _Error ->
951            {skip, "Unable to load slow_drv (windows or no usleep()?)"}
952    end.
953do_system_monitor_long_schedule() ->
954    start_monitor(),
955    Port = open_port({spawn_driver,slow_drv}, []),
956    "ok" = erlang:port_control(Port,0,[]),
957    Self = self(),
958    receive
959        {Self,L} when is_list(L) ->
960            ok
961    after 1000 ->
962            ct:fail(no_trace_of_pid)
963    end,
964    "ok" = erlang:port_control(Port,1,[]),
965    receive
966        {Port,LL} when is_list(LL) ->
967            ok
968    after 1000 ->
969            ct:fail(no_trace_of_port)
970    end,
971    port_close(Port),
972    erlang:system_monitor(undefined),
973    ok.
974
975
976-define(LONG_GC_SLEEP, 670).
977
978%% Tests erlang:system_monitor(Pid, [{long_gc,Time}])
979system_monitor_long_gc_1(Config) when is_list(Config) ->
980    erts_debug:set_internal_state(available_internal_state, true),
981    try
982        case erts_debug:get_internal_state(force_heap_frags) of
983            true ->
984                {skip,"emulator with FORCE_HEAP_FRAGS defined"};
985            false ->
986                %% Add ?LONG_GC_SLEEP ms to all gc
987                erts_debug:set_internal_state(test_long_gc_sleep,
988                                              ?LONG_GC_SLEEP),
989                LoadFun = fun () ->
990                                  garbage_collect(),
991                                  self()
992                          end,
993                long_gc(LoadFun, false)
994        end
995    after
996        erts_debug:set_internal_state(test_long_gc_sleep, 0),
997        erts_debug:set_internal_state(available_internal_state, false)
998    end.
999
1000%% Tests erlang:system_monitor(Pid, [{long_gc,Time}])
1001system_monitor_long_gc_2(Config) when is_list(Config) ->
1002    erts_debug:set_internal_state(available_internal_state, true),
1003    try
1004        case erts_debug:get_internal_state(force_heap_frags) of
1005            true ->
1006                {skip,"emulator with FORCE_HEAP_FRAGS defined"};
1007            false ->
1008                %% Add ?LONG_GC_SLEEP ms to all gc
1009                erts_debug:set_internal_state(test_long_gc_sleep,
1010                                              ?LONG_GC_SLEEP),
1011                Parent = self(),
1012                LoadFun =
1013                fun () ->
1014                        Ref = make_ref(),
1015                        Pid =
1016                        spawn_link(
1017                          fun () ->
1018                                  garbage_collect(),
1019                                  Parent ! {Ref, self()}
1020                          end),
1021                        receive {Ref, Pid} -> Pid end
1022                end,
1023                long_gc(LoadFun, true),
1024                long_gc(LoadFun, true),
1025                long_gc(LoadFun, true)
1026        end
1027    after
1028        erts_debug:set_internal_state(test_long_gc_sleep, 0),
1029        erts_debug:set_internal_state(available_internal_state, false)
1030    end.
1031
1032long_gc(LoadFun, ExpectMonMsg) ->
1033    Self = self(),
1034    Time = 1,
1035    OldMonitor = erlang:system_monitor(Self, [{long_gc,Time}]),
1036    Pid = LoadFun(),
1037    Ref = erlang:trace_delivered(Pid),
1038    receive {trace_delivered, Pid, Ref} -> ok end,
1039    {Self,[{long_gc,Time}]} = erlang:system_monitor(OldMonitor),
1040    case {long_gc_check(Pid, Time, undefined), ExpectMonMsg} of
1041        {ok, true} when Pid =/= Self ->
1042            ok;
1043        {ok, false} ->
1044            ct:fail(unexpected_system_monitor_message_received);
1045        {undefined, false} ->
1046            ok;
1047        {undefined, true} ->
1048            ct:fail(no_system_monitor_message_received)
1049    end.
1050
1051long_gc_check(Pid, Time, Result) ->
1052    receive
1053        {monitor,Pid,long_gc,L} = Monitor ->
1054            case lists:foldl(
1055                   fun (_, error) ->
1056                           error;
1057                       ({timeout,T}, N) when is_integer(T),
1058                                             Time =< T, T =< 10*?LONG_GC_SLEEP ->
1059                           %% OTP-7622. The time T must be within reasonable limits
1060                           %% for the test to pass.
1061                           N-1;
1062                       ({heap_size,_}, N) ->
1063                           N-1;
1064                       ({old_heap_size,_}, N) ->
1065                           N-1;
1066                       ({stack_size,_}, N) ->
1067                           N-1;
1068                       ({mbuf_size,_}, N) ->
1069                           N-1;
1070                       ({heap_block_size,_}, N) ->
1071                           N-1;
1072                       ({old_heap_block_size,_}, N) ->
1073                           N-1;
1074                       (_, _) ->
1075                           error
1076                   end, 7, L) of
1077                0 ->
1078                    long_gc_check(Pid, Time, ok);
1079                error ->
1080                    {error,Monitor}
1081            end;
1082        {monitor,_,long_gc,_} ->
1083            long_gc_check(Pid, Time, Result);
1084        Other ->
1085            {error,Other}
1086    after 0 ->
1087              Result
1088    end.
1089
1090%% Tests erlang:system_monitor(Pid, [{large_heap,Size}])
1091system_monitor_large_heap_1(Config) when is_list(Config) ->
1092    LoadFun =
1093    fun (Size) ->
1094            List = seq(1,2*Size),
1095            garbage_collect(),
1096            true = lists:prefix([1], List),
1097            self()
1098    end,
1099    large_heap(LoadFun, false).
1100
1101%% Tests erlang:system_monitor(Pid, [{large_heap,Size}])
1102system_monitor_large_heap_2(Config) when is_list(Config) ->
1103    Parent = self(),
1104    LoadFun =
1105    fun (Size) ->
1106            Ref = make_ref(),
1107            Pid =
1108            spawn_opt(fun () ->
1109                              garbage_collect(),
1110                              Parent ! {Ref, self()}
1111                      end,
1112                      [link, {min_heap_size, 2*Size}]),
1113            receive {Ref, Pid} -> Pid end
1114    end,
1115    large_heap(LoadFun, true).
1116
1117large_heap(LoadFun, ExpectMonMsg) ->
1118    ct:timetrap({seconds, 20}),
1119    %%
1120    Size = 65535,
1121    Self = self(),
1122    NewMonitor = {Self,[{large_heap,Size}]},
1123    OldMonitor = erlang:system_monitor(NewMonitor),
1124    Pid = LoadFun(Size),
1125    Ref = erlang:trace_delivered(Pid),
1126    receive {trace_delivered, Pid, Ref} -> ok end,
1127    {Self,[{large_heap,Size}]} = erlang:system_monitor(OldMonitor),
1128    case {large_heap_check(Pid, Size, undefined), ExpectMonMsg} of
1129        {ok, true} when Pid =/= Self ->
1130            ok;
1131        {ok, false} ->
1132            ct:fail(unexpected_system_monitor_message_received);
1133        {undefined, false} ->
1134            ok;
1135        {undefined, true} ->
1136            ct:fail(no_system_monitor_message_received)
1137    end,
1138    ok.
1139
1140large_heap_check(Pid, Size, Result) ->
1141    receive
1142        {monitor,Pid,large_heap,L} = Monitor ->
1143            case lists:foldl(
1144                   fun (_, error) ->
1145                           error;
1146                       ({heap_size,_}, N) ->
1147                           N-1;
1148                       ({old_heap_size,_}, N) ->
1149                           N-1;
1150                       ({stack_size,_}, N) ->
1151                           N-1;
1152                       ({mbuf_size,_}, N) ->
1153                           N-1;
1154                       ({heap_block_size,_}, N) ->
1155                           N-1;
1156                       ({old_heap_block_size,_}, N) ->
1157                           N-1;
1158                       (_, _) ->
1159                           error
1160                   end, 6, L) of
1161                0 ->
1162                    large_heap_check(Pid, Size, ok);
1163                error ->
1164                    {error,Monitor}
1165            end;
1166        {monitor,_,large_heap,_} ->
1167            large_heap_check(Pid, Size, Result);
1168        Other ->
1169            {error,Other}
1170    after 0 ->
1171              Result
1172    end.
1173
1174seq(N, M) ->
1175    seq(N, M, []).
1176
1177seq(M, M, R) ->
1178    lists:reverse(R);
1179seq(N, M, R) ->
1180    seq(N+1, M, [N|R]).
1181
1182
1183is_send_traced(Pid, Listener, Msg) ->
1184    Pid ! {send_please, Listener, Msg},
1185    receive
1186        Any ->
1187            {trace, Pid, send, Msg, Listener} = Any,
1188            true
1189    after 1000 ->
1190              false
1191    end.
1192
1193%% This procedure assumes that the Parent process is send traced.
1194
1195spawn_children(Parent, Number) ->
1196    spawn_children(Parent, Number, []).
1197
1198spawn_children(_Parent, 0, Result) ->
1199    lists:reverse(Result);
1200spawn_children(Parent, Number, Result) ->
1201    Self = self(),
1202    Parent ! {spawn_please, Self, fun process/0},
1203    Child =
1204    receive
1205        {trace, Parent, send, {spawned, Pid}, Self} -> Pid
1206    end,
1207    receive
1208        {spawned, Child} ->
1209            spawn_children(Parent, Number-1, [Child|Result])
1210    end.
1211
1212%% Test erlang:suspend/1 and erlang:resume/1.
1213suspend(Config) when is_list(Config) ->
1214    ct:timetrap({minutes,2}),
1215    Worker = fun_spawn(fun worker/0),
1216    %% Suspend a process and test that it is suspended.
1217    ok = do_suspend(Worker, 10000),
1218    ok.
1219
1220do_suspend(_Pid, 0) ->
1221    ok;
1222do_suspend(Pid, N) ->
1223    %% Suspend a process and test that it is suspended.
1224    true = erlang:suspend_process(Pid),
1225    {status, suspended} = process_info(Pid, status),
1226
1227    %% Unsuspend the process and make sure it starts working.
1228    true = erlang:resume_process(Pid),
1229    case process_info(Pid, status) of
1230        {status, runnable} -> ok;
1231        {status, running} -> ok;
1232        {status, garbage_collecting} -> ok;
1233        ST -> ct:fail(ST)
1234    end,
1235    erlang:yield(),
1236    do_suspend(Pid, N-1).
1237
1238suspend_exit(Config) when is_list(Config) ->
1239    ct:timetrap({minutes, 2}),
1240    rand:seed(exsplus, {4711,17,4711}),
1241    do_suspend_exit(5000),
1242    ok.
1243
1244do_suspend_exit(0) ->
1245    ok;
1246do_suspend_exit(N) ->
1247    Work = rand:uniform(50),
1248    Parent = self(),
1249    {Suspendee, Mon2}
1250    = spawn_monitor(fun () ->
1251                            suspend_exit_work(Work),
1252                            exit(normal)
1253                    end),
1254    {Suspender, Mon1}
1255    = spawn_monitor(
1256        fun () ->
1257                suspend_exit_work(Work div 2),
1258                Parent ! {doing_suspend, self()},
1259                case catch erlang:suspend_process(Suspendee) of
1260                    {'EXIT', _} ->
1261                        ok;
1262                    true ->
1263                        erlang:resume_process(Suspendee)
1264                end
1265        end),
1266    receive
1267        {doing_suspend, Suspender} ->
1268            case N rem 2 of
1269                0 -> exit(Suspender, bang);
1270                1 -> ok
1271            end
1272    end,
1273    receive {'DOWN', Mon1, process, Suspender, _} -> ok end,
1274    receive {'DOWN', Mon2, process, Suspendee, _} -> ok end,
1275    do_suspend_exit(N-1).
1276
1277
1278
1279
1280suspend_exit_work(0) ->
1281    ok;
1282suspend_exit_work(N) ->
1283    process_info(self()),
1284    suspend_exit_work(N-1).
1285
1286-define(CHK_SUSPENDED(P,B), chk_suspended(P, B, ?LINE)).
1287
1288chk_suspended(P, Bool, Line) ->
1289    {Bool, Line} = {({status, suspended} == process_info(P, status)), Line}.
1290
1291suspender_exit(Config) when is_list(Config) ->
1292    ct:timetrap({minutes, 3}),
1293    P1 = spawn_link(fun () -> receive after infinity -> ok end end),
1294    {'EXIT', _} = (catch erlang:resume_process(P1)),
1295    {P2, M2} = spawn_monitor(
1296                 fun () ->
1297                         ?CHK_SUSPENDED(P1, false),
1298                         erlang:suspend_process(P1),
1299                         ?CHK_SUSPENDED(P1, true),
1300                         erlang:suspend_process(P1),
1301                         erlang:suspend_process(P1),
1302                         erlang:suspend_process(P1),
1303                         ?CHK_SUSPENDED(P1, true),
1304                         erlang:resume_process(P1),
1305                         erlang:resume_process(P1),
1306                         erlang:resume_process(P1),
1307                         ?CHK_SUSPENDED(P1, true),
1308                         erlang:resume_process(P1),
1309                         ?CHK_SUSPENDED(P1, false),
1310                         erlang:suspend_process(P1),
1311                         erlang:suspend_process(P1),
1312                         erlang:suspend_process(P1),
1313                         ?CHK_SUSPENDED(P1, true),
1314                         exit(bang)
1315                 end),
1316    receive
1317        {'DOWN', M2,process,P2,R2} ->
1318            bang = R2,
1319            ?CHK_SUSPENDED(P1, false)
1320    end,
1321    Parent = self(),
1322    {P3, M3} = spawn_monitor(
1323                 fun () ->
1324                         erlang:suspend_process(P1),
1325                         ?CHK_SUSPENDED(P1, true),
1326                         Parent ! self(),
1327                         receive after infinity -> ok end
1328                 end),
1329    {P4, M4} = spawn_monitor(
1330                 fun () ->
1331                         erlang:suspend_process(P1),
1332                         ?CHK_SUSPENDED(P1, true),
1333                         Parent ! self(),
1334                         receive after infinity -> ok end
1335                 end),
1336    {P5, M5} = spawn_monitor(
1337                 fun () ->
1338                         erlang:suspend_process(P1),
1339                         ?CHK_SUSPENDED(P1, true),
1340                         Parent ! self(),
1341                         receive after infinity -> ok end
1342                 end),
1343    {P6, M6} = spawn_monitor(
1344                 fun () ->
1345                         erlang:suspend_process(P1),
1346                         ?CHK_SUSPENDED(P1, true),
1347                         Parent ! self(),
1348                         receive after infinity -> ok end
1349                 end),
1350    {P7, M7} = spawn_monitor(
1351                 fun () ->
1352                         erlang:suspend_process(P1),
1353                         ?CHK_SUSPENDED(P1, true),
1354                         Parent ! self(),
1355                         receive after infinity -> ok end
1356                 end),
1357    receive P3 -> ok end,
1358    receive P4 -> ok end,
1359    receive P5 -> ok end,
1360    receive P6 -> ok end,
1361    receive P7 -> ok end,
1362    ?CHK_SUSPENDED(P1, true),
1363    exit(P3, bang),
1364    receive
1365        {'DOWN',M3,process,P3,R3} ->
1366            bang = R3,
1367            ?CHK_SUSPENDED(P1, true)
1368    end,
1369    exit(P4, bang),
1370    receive
1371        {'DOWN',M4,process,P4,R4} ->
1372            bang = R4,
1373            ?CHK_SUSPENDED(P1, true)
1374    end,
1375    exit(P5, bang),
1376    receive
1377        {'DOWN',M5,process,P5,R5} ->
1378            bang = R5,
1379            ?CHK_SUSPENDED(P1, true)
1380    end,
1381    exit(P6, bang),
1382    receive
1383        {'DOWN',M6,process,P6,R6} ->
1384            bang = R6,
1385            ?CHK_SUSPENDED(P1, true)
1386    end,
1387    exit(P7, bang),
1388    receive
1389        {'DOWN',M7,process,P7,R7} ->
1390            bang = R7,
1391            ?CHK_SUSPENDED(P1, false)
1392    end,
1393    unlink(P1),
1394    exit(P1, bong),
1395    ok.
1396
1397suspend_system_limit(Config) when is_list(Config) ->
1398    case os:getenv("ERL_EXTREME_TESTING") of
1399        "true" ->
1400            ct:timetrap({minutes, 3*60}),
1401            P = spawn_link(fun () -> receive after infinity -> ok end end),
1402            suspend_until_system_limit(P),
1403            unlink(P),
1404            exit(P, bye),
1405            ok;
1406        _ ->
1407            {skip, "Takes too long time for normal testing"}
1408    end.
1409
1410suspend_until_system_limit(P) ->
1411    suspend_until_system_limit(P, 0, 0).
1412
1413suspend_until_system_limit(P, N, M) ->
1414    NewM = case M of
1415               1 ->
1416                   ?CHK_SUSPENDED(P, true), 2;
1417               1000000 ->
1418                   erlang:display(N), 1;
1419               _ ->
1420                   M+1
1421           end,
1422    case catch erlang:suspend_process(P) of
1423        true ->
1424            suspend_until_system_limit(P, N+1, NewM);
1425        {'EXIT', R} when R == system_limit;
1426                         element(1, R) == system_limit ->
1427            io:format("system limit at ~p~n", [N]),
1428            resume_from_system_limit(P, N, 0);
1429        Error ->
1430            ct:fail(Error)
1431    end.
1432
1433resume_from_system_limit(P, 0, _) ->
1434    ?CHK_SUSPENDED(P, false),
1435    {'EXIT', _} = (catch erlang:resume_process(P)),
1436    ok;
1437resume_from_system_limit(P, N, M) ->
1438    NewM = case M of
1439               1 ->
1440                   ?CHK_SUSPENDED(P, true), 2;
1441               1000000 ->
1442                   erlang:display(N), 1;
1443               _ ->
1444                   M+1
1445           end,
1446    erlang:resume_process(P),
1447    resume_from_system_limit(P, N-1, NewM).
1448
1449-record(susp_info, {async = 0,
1450                    dbl_async = 0,
1451                    synced = 0,
1452                    async_once = 0}).
1453
1454suspend_opts(Config) when is_list(Config) ->
1455    ct:timetrap({minutes, 3}),
1456    Self = self(),
1457    wait_for_empty_runq(10),
1458    Tok = spawn_link(fun () ->
1459                             Self ! self(),
1460                             tok_trace_loop(Self, 0, 1000000000)
1461                     end),
1462    TC = 1000,
1463    receive Tok -> ok end,
1464    SF = fun (N, #susp_info {async = A,
1465                             dbl_async = AA,
1466                             synced = S,
1467                             async_once = AO} = Acc) ->
1468                 Tag = {make_ref(), self()},
1469                 erlang:suspend_process(Tok, [{asynchronous, Tag}]),
1470                 Res = case {suspend_count(Tok), N rem 4} of
1471                           {0, 2} ->
1472                               erlang:suspend_process(Tok,
1473                                                      [asynchronous]),
1474                               case suspend_count(Tok) of
1475                                   2 ->
1476                                       erlang:resume_process(Tok),
1477                                       Acc#susp_info{async = A+1};
1478                                   0 ->
1479                                       erlang:resume_process(Tok),
1480                                       Acc#susp_info{async = A+1,
1481                                                     dbl_async = AA+1}
1482                               end;
1483                           {0, 1} ->
1484                               erlang:suspend_process(Tok,
1485                                                      [asynchronous,
1486                                                       unless_suspending]),
1487                               case suspend_count(Tok) of
1488                                   1 ->
1489                                       Acc#susp_info{async = A+1};
1490                                   0 ->
1491                                       Acc#susp_info{async = A+1,
1492                                                     async_once = AO+1}
1493                               end;
1494                           {0, 0} ->
1495                               erlang:suspend_process(Tok,
1496                                                      [unless_suspending]),
1497                               1 = suspend_count(Tok),
1498                               Acc#susp_info{async = A+1,
1499                                             synced = S+1};
1500                           {0, _} ->
1501                               Acc#susp_info{async = A+1};
1502                           _ ->
1503                               Acc
1504                       end,
1505                 receive
1506                     {Tag, Result} ->
1507                         suspended = Result,
1508                         erlang:resume_process(Tok)
1509                 end,
1510                 erlang:yield(),
1511                 Res
1512         end,
1513    SI = repeat_acc(SF, TC, #susp_info{}),
1514    erlang:suspend_process(Tok, [asynchronous]),
1515    %% Verify that it eventually suspends
1516    WaitTime0 = 10,
1517    WaitTime1 = case {erlang:system_info(debug_compiled),
1518                      erlang:system_info(lock_checking)} of
1519                    {false, false} ->
1520                        WaitTime0;
1521                    {false, true} ->
1522                        WaitTime0*5;
1523                    _ ->
1524                        WaitTime0*10
1525                end,
1526    WaitTime = case {erlang:system_info(schedulers_online),
1527                     erlang:system_info(logical_processors)} of
1528                   {Schdlrs, CPUs} when is_integer(CPUs),
1529                                        Schdlrs =< CPUs ->
1530                       WaitTime1;
1531                   _ ->
1532                       WaitTime1*10
1533               end,
1534    receive after WaitTime -> ok end,
1535    1 = suspend_count(Tok),
1536    erlang:suspend_process(Tok, [asynchronous]),
1537    2 = suspend_count(Tok),
1538    erlang:suspend_process(Tok, [asynchronous]),
1539    3 = suspend_count(Tok),
1540    erlang:suspend_process(Tok),
1541    4 = suspend_count(Tok),
1542    erlang:suspend_process(Tok),
1543    5 = suspend_count(Tok),
1544    erlang:suspend_process(Tok, [unless_suspending]),
1545    5 = suspend_count(Tok),
1546    erlang:suspend_process(Tok, [unless_suspending,
1547                                 asynchronous]),
1548    5 = suspend_count(Tok),
1549    erlang:resume_process(Tok),
1550    erlang:resume_process(Tok),
1551    erlang:resume_process(Tok),
1552    erlang:resume_process(Tok),
1553    1 = suspend_count(Tok),
1554    io:format("Main suspends: ~p~n"
1555              "Main async: ~p~n"
1556              "Double async: ~p~n"
1557              "Async once: ~p~n"
1558              "Synced: ~p~n",
1559              [TC,
1560               SI#susp_info.async,
1561               SI#susp_info.dbl_async,
1562               SI#susp_info.async_once,
1563               SI#susp_info.synced]),
1564    case erlang:system_info(schedulers_online) of
1565        1 ->
1566            ok;
1567        _ ->
1568            true = SI#susp_info.async =/= 0
1569    end,
1570    unlink(Tok),
1571    exit(Tok, bang),
1572    ok.
1573
1574suspend_count(Suspendee) ->
1575    suspend_count(self(), Suspendee).
1576
1577suspend_count(Suspender, Suspendee) ->
1578    {suspending, SList} = process_info(Suspender, suspending),
1579
1580    case lists:keysearch(Suspendee, 1, SList) of
1581        {value, {_Suspendee, 0, 0}} ->
1582            ct:fail({bad_suspendee_list, SList});
1583        {value, {Suspendee, Count, 0}} when is_integer(Count), Count > 0 ->
1584            {status, suspended} = process_info(Suspendee, status),
1585            Count;
1586        {value, {Suspendee, 0, Outstanding}} when is_integer(Outstanding),
1587                                                  Outstanding > 0 ->
1588            0;
1589        false ->
1590            0;
1591        Error ->
1592            ct:fail({bad_suspendee_list, Error, SList})
1593    end.
1594
1595repeat_acc(Fun, N, Acc) ->
1596    repeat_acc(Fun, 0, N, Acc).
1597
1598repeat_acc(_Fun, N, N, Acc) ->
1599    Acc;
1600repeat_acc(Fun, N, M, Acc) ->
1601    repeat_acc(Fun, N+1, M, Fun(N, Acc)).
1602
1603%% Tests that waiting process can be suspended
1604%% (bug in R2D and earlier; see OTP-1488).
1605
1606%% Test that a waiting process can be suspended.
1607suspend_waiting(Config) when is_list(Config) ->
1608    Process = fun_spawn(fun process/0),
1609    receive after 1 -> ok end,
1610    true = erlang:suspend_process(Process),
1611    {status, suspended} = process_info(Process, status),
1612    ok.
1613
1614
1615%% Test that erlang:trace(new, true, ...) is cleared when tracer dies.
1616new_clear(Config) when is_list(Config) ->
1617    Tracer = proplists:get_value(receiver, Config),
1618
1619    0 = erlang:trace(new, true, [send, {tracer, Tracer}]),
1620    {flags, [send]} = erlang:trace_info(new, flags),
1621    {tracer, Tracer} = erlang:trace_info(new, tracer),
1622    Mref = erlang:monitor(process, Tracer),
1623    true = exit(Tracer, done),
1624    receive
1625        {'DOWN',Mref,_,_,_} -> ok
1626    end,
1627    {flags, []} = erlang:trace_info(new, flags),
1628    {tracer, []} = erlang:trace_info(new, tracer),
1629    ok.
1630
1631
1632
1633%% Test that erlang:trace(all, false, ...) works without tracer.
1634existing_clear(Config) when is_list(Config) ->
1635    Self = self(),
1636
1637    Tracer = proplists:get_value(receiver, Config),
1638    N = erlang:trace(existing, true, [send, {tracer, Tracer}]),
1639    {flags, [send]} = erlang:trace_info(Self, flags),
1640    {tracer, Tracer} = erlang:trace_info(Self, tracer),
1641    M = erlang:trace(all, false, [all]),
1642    io:format("Started trace on ~p processes and stopped on ~p~n",
1643              [N, M]),
1644    {flags, []} = erlang:trace_info(Self, flags),
1645    {tracer, []} = erlang:trace_info(Self, tracer),
1646    M = N, % Used to be N + 1, but from 19.0 the tracer is also traced
1647
1648    ok.
1649
1650%% Test that erlang:trace/3 can be called on processes where the
1651%% tracer has died. OTP-13928
1652tracer_die(Config) when is_list(Config) ->
1653    Proc = spawn_link(fun receiver/0),
1654
1655    Tracer = spawn_link(fun receiver/0),
1656    timer:sleep(1),
1657    N = erlang:trace(existing, true, [send, {tracer, Tracer}]),
1658    {flags, [send]} = erlang:trace_info(Proc, flags),
1659    {tracer, Tracer} = erlang:trace_info(Proc, tracer),
1660    unlink(Tracer),
1661    exit(Tracer, die),
1662
1663    Tracer2 = spawn_link(fun receiver/0),
1664    timer:sleep(1),
1665    N = erlang:trace(existing, true, [send, {tracer, Tracer2}]),
1666    {flags, [send]} = erlang:trace_info(Proc, flags),
1667    {tracer, Tracer2} = erlang:trace_info(Proc, tracer),
1668    unlink(Tracer2),
1669    exit(Tracer2, die),
1670
1671    Tracer3 = spawn_link(fun receiver/0),
1672    timer:sleep(1),
1673    1 = erlang:trace(Proc, true, [send, {tracer, Tracer3}]),
1674    {flags, [send]} = erlang:trace_info(Proc, flags),
1675    {tracer, Tracer3} = erlang:trace_info(Proc, tracer),
1676    unlink(Tracer3),
1677    exit(Tracer3, die),
1678
1679    ok.
1680
1681%% Test that an invalid flag cause badarg
1682bad_flag(Config) when is_list(Config) ->
1683    %% A bad flag could deadlock the SMP emulator in erts-5.5
1684    {'EXIT', {badarg, _}} = (catch erlang:trace(new,
1685                                                true,
1686                                                [not_a_valid_flag])),
1687
1688    %% Leaks of {tracer,_} in OTP 23.2
1689    Pid = spawn(fun() -> receive die -> ok end end),
1690    1 = erlang:trace(Pid, true, [{tracer, self()},
1691                                 {tracer, self()}]),
1692    Pid ! die,
1693    {'EXIT', {badarg, _}} =
1694        (catch erlang:trace(new, true, [{tracer, self()}
1695                                        | improper])),
1696    {'EXIT', {badarg, _}} =
1697        (catch erlang:trace(new, true, [{tracer, self()},
1698                                        not_a_valid_flag])),
1699    ok.
1700
1701%% Test erlang:trace_delivered/1
1702trace_delivered(Config) when is_list(Config) ->
1703    ct:timetrap({minutes, 1}),
1704    TokLoops = 10000,
1705    Go = make_ref(),
1706    Parent = self(),
1707    Tok = spawn(fun () ->
1708                        receive Go -> gone end,
1709                        tok_trace_loop(Parent, 0, TokLoops)
1710                end),
1711    1 = erlang:trace(Tok, true, [procs]),
1712    Mon = erlang:monitor(process, Tok),
1713    NoOfTraceMessages = 4*TokLoops + 1,
1714    io:format("Expect a total of ~p trace messages~n",
1715              [NoOfTraceMessages]),
1716    Tok ! Go,
1717    NoOfTraceMessages = drop_trace_until_down(Tok, Mon),
1718    receive
1719        Msg ->
1720            ct:fail({unexpected_message, Msg})
1721    after 1000 ->
1722              ok
1723    end.
1724
1725%% This testcase checks that receive trace works on exit signal messages
1726%% when the sender of the exit signal is the process itself.
1727trap_exit_self_receive(Config) ->
1728    Parent = self(),
1729    Proc = spawn_link(fun() -> process(Parent) end),
1730
1731    1 = erlang:trace(Proc, true, ['receive']),
1732    Proc ! {trap_exit_please, true},
1733    {trace, Proc, 'receive', {trap_exit_please, true}} = receive_first_trace(),
1734
1735    %% Make the process call exit(self(), signal)
1736    Reason1 = make_ref(),
1737    Proc ! {exit_signal_please, Reason1},
1738    {trace, Proc, 'receive', {exit_signal_please, Reason1}} = receive_first_trace(),
1739    {trace, Proc, 'receive', {'EXIT', Proc, Reason1}} = receive_first_trace(),
1740    receive {Proc, {'EXIT', Proc, Reason1}} -> ok end,
1741    receive_nothing(),
1742
1743    unlink(Proc),
1744    Reason2 = make_ref(),
1745    Proc ! {exit_please, Reason2},
1746    {trace, Proc, 'receive', {exit_please, Reason2}} = receive_first_trace(),
1747    receive_nothing(),
1748    ok.
1749
1750trace_info_badarg(Config) when is_list(Config) ->
1751    catch erlang:trace_info({a,b,c},d),
1752    ok.
1753
1754%% An incoming suspend monitor down wasn't handled
1755%% correct when the local monitor half had been
1756%% removed with an emulator crash as result.
1757erl_704(Config) ->
1758    erl_704_test(100).
1759
1760erl_704_test(0) ->
1761    ok;
1762erl_704_test(N) ->
1763    P = spawn(fun () -> receive infinity -> ok end end),
1764    erlang:suspend_process(P),
1765    exit(P, kill),
1766    (catch erlang:resume_process(P)),
1767    erl_704_test(N-1).
1768
1769ms_excessive_nesting(Config) when is_list(Config) ->
1770    MkMSCond = fun (_Fun, N) when N < 0 -> true;
1771                   (Fun, N) -> {'or', {'=:=', N, '$1'}, Fun(Fun, N-1)}
1772               end,
1773    %% Ensure it compiles with substantial but reasonable
1774    %% (hmm...) nesting
1775    MS = [{['$1'], [MkMSCond(MkMSCond, 100)], []}],
1776    io:format("~p~n", [erlang:match_spec_test([1], MS, trace)]),
1777    _ = erlang:trace_pattern({?MODULE, '_', '_'}, MS, []),
1778    %% Now test a match spec using excessive nesting. This
1779    %% used to seg-fault the emulator due to recursion
1780    %% beyond the end of the C-stack.
1781    %%
1782    %% We expect to get a system_limit error, but don't
1783    %% fail if it compiles (someone must have rewritten
1784    %% compilation of match specs to use an explicit
1785    %% stack instead of using recursion).
1786    ENMS = [{['$1'], [MkMSCond(MkMSCond, 1000000)], []}],
1787    io:format("~p~n", [erlang:match_spec_test([1], ENMS, trace)]),
1788    try
1789        _ = erlang:trace_pattern({?MODULE, '_', '_'}, ENMS, []),
1790        {comment, "compiled"}
1791    catch
1792        error:system_limit ->
1793            {comment, "got system_limit"}
1794    end.
1795
1796drop_trace_until_down(Proc, Mon) ->
1797    drop_trace_until_down(Proc, Mon, false, 0, 0).
1798
1799drop_trace_until_down(Proc, Mon, TDRef, N, D) ->
1800    case receive Msg -> Msg end of
1801        {trace_delivered, Proc, TDRef} ->
1802            io:format("~p trace messages on 'DOWN'~n", [D]),
1803            io:format("Got a total of ~p trace messages~n", [N]),
1804            N;
1805        {'DOWN', Mon, process, Proc, _} ->
1806            Ref = erlang:trace_delivered(Proc),
1807            drop_trace_until_down(Proc, Mon, Ref, N, N);
1808        Trace when is_tuple(Trace),
1809                   element(1, Trace) == trace,
1810                   element(2, Trace) == Proc ->
1811            drop_trace_until_down(Proc, Mon, TDRef, N+1, D)
1812    end.
1813
1814tok_trace_loop(_, N, N) ->
1815    ok;
1816tok_trace_loop(Parent, N, M) ->
1817    Name = 'A really stupid name which I will unregister at once',
1818    link(Parent),
1819    register(Name, self()),
1820    unregister(Name),
1821    unlink(Parent),
1822    tok_trace_loop(Parent, N+1, M).
1823
1824%% Waits for and returns the first message in the message queue.
1825
1826receive_first() ->
1827    receive
1828        Any -> Any
1829    end.
1830
1831%% Waits for and returns the first message in the message queue.
1832
1833receive_first_trace() ->
1834    receive
1835	Any when element(1,Any) =:= trace; element(1,Any) =:= trace_ts -> Any
1836    end.
1837
1838%% Ensures that there is no message in the message queue.
1839
1840receive_nothing() ->
1841    receive
1842        Any ->
1843            ct:fail({unexpected_message, Any})
1844    after 100 ->
1845	    ok
1846    end.
1847
1848
1849%%% Models for various kinds of processes.
1850
1851process(Dest) ->
1852    receive
1853        {send_please, To, What} ->
1854            To ! What,
1855            process(Dest);
1856        {spawn_link_please, ReplyTo, {M, F, A}} ->
1857            Pid = spawn_link(M, F, A),
1858            ReplyTo ! {spawned, self(), Pid},
1859            process(Dest);
1860        {spawn_link_please, ReplyTo, Node, {M, F, A}} ->
1861            Pid = spawn_link(Node, M, F, A),
1862            ReplyTo ! {spawned, self(), Pid},
1863            process(Dest);
1864        {link_please, Pid} ->
1865            link(Pid),
1866            process(Dest);
1867        {unlink_please, Pid} ->
1868            unlink(Pid),
1869            process(Dest);
1870        {register_please, Name, Pid} ->
1871            register(Name, Pid),
1872            process(Dest);
1873        {unregister_please, Name} ->
1874            unregister(Name),
1875            process(Dest);
1876        {exit_please, Reason} ->
1877            exit(Reason);
1878        {exit_signal_please, Reason} ->
1879            exit(self(), Reason),
1880            process(Dest);
1881        {trap_exit_please, State} ->
1882            process_flag(trap_exit, State),
1883            process(Dest);
1884        Other ->
1885            Dest ! {self(), Other},
1886            process(Dest)
1887    after 3000 ->
1888              exit(timeout)
1889    end.
1890
1891
1892%% A smart process template.
1893
1894process() ->
1895    receive
1896        {spawn_please, ReplyTo, Fun} ->
1897            Pid = fun_spawn(Fun),
1898            ReplyTo ! {spawned, Pid},
1899            process();
1900        {send_please, To, What} ->
1901            To ! What,
1902            process();
1903        timeout_please ->
1904            receive after 1 -> process() end;
1905        _Other ->
1906            process()
1907    end.
1908
1909
1910%% Sends messages when ordered to.
1911
1912sender() ->
1913    receive
1914        {send_please, To, What} ->
1915            To ! What,
1916            sender()
1917    end.
1918
1919
1920%% Just consumes messages from its message queue.
1921
1922receiver() ->
1923    receiver(infinity).
1924
1925receiver(Timeout) ->
1926    receiver(receive
1927		 {set_timeout, NewTimeout} -> NewTimeout;
1928		 _Any -> Timeout
1929	     after Timeout -> infinity  %% reset
1930	     end).
1931
1932%% Works as long as it receives CPU time.  Will always be RUNNABLE.
1933
1934worker() ->
1935    worker(0).
1936
1937worker(Number) ->
1938    worker(Number+1).
1939
1940fun_spawn(Fun) ->
1941    spawn_link(erlang, apply, [Fun, []]).
1942
1943fun_spawn(Fun, Args) ->
1944    spawn_link(erlang, apply, [Fun, Args]).
1945
1946
1947start_node(Name) ->
1948    Pa = filename:dirname(code:which(?MODULE)),
1949    Cookie = atom_to_list(erlang:get_cookie()),
1950    test_server:start_node(Name, slave,
1951                           [{args, "-setcookie " ++ Cookie ++" -pa " ++ Pa}]).
1952
1953stop_node(Node) ->
1954    test_server:stop_node(Node).
1955
1956
1957wait_for_empty_runq(DeadLine) ->
1958    case statistics(run_queue) of
1959        0 -> true;
1960        RQLen ->
1961            erlang:display("Waiting for empty run queue"),
1962            MSDL = DeadLine*1000,
1963            wait_for_empty_runq(MSDL, MSDL, RQLen)
1964    end.
1965
1966wait_for_empty_runq(DeadLine, Left, RQLen) when Left =< 0 ->
1967    issue_non_empty_runq_warning(DeadLine, RQLen),
1968    false;
1969wait_for_empty_runq(DeadLine, Left, _RQLen) ->
1970    Wait = 10,
1971    UntilDeadLine = Left - Wait,
1972    receive after Wait -> ok end,
1973    case statistics(run_queue) of
1974        0 ->
1975            erlang:display("Waited for "
1976                           ++ integer_to_list(DeadLine
1977                                              - UntilDeadLine)
1978                           ++ " ms for empty run queue."),
1979            true;
1980        NewRQLen ->
1981            wait_for_empty_runq(DeadLine,
1982                                UntilDeadLine,
1983                                NewRQLen)
1984    end.
1985
1986issue_non_empty_runq_warning(DeadLine, RQLen) ->
1987    PIs = lists:foldl(
1988            fun (P, Acc) ->
1989                    case process_info(P,
1990                                      [status,
1991                                       initial_call,
1992                                       current_function,
1993                                       registered_name,
1994                                       reductions,
1995                                       message_queue_len]) of
1996                        [{status, Runnable} | _] = PI when Runnable /= waiting,
1997                                                           Runnable /= suspended ->
1998                            [[{pid, P} | PI] | Acc];
1999                        _ ->
2000                            Acc
2001                    end
2002            end,
2003            [],
2004            processes()),
2005    io:format("WARNING: Unexpected runnable processes in system (waited ~p sec).~n"
2006              "         Run queue length: ~p~n"
2007              "         Self: ~p~n"
2008              "         Processes info: ~p~n",
2009              [DeadLine div 1000, RQLen, self(), PIs]),
2010    receive after 1000 -> ok end.
2011
2012load_driver(Dir, Driver) ->
2013    case erl_ddll:load_driver(Dir, Driver) of
2014        ok -> ok;
2015        {error, Error} = Res ->
2016            io:format("~s\n", [erl_ddll:format_error(Error)]),
2017            Res
2018    end.
2019