aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/test/trace_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/test/trace_SUITE.erl')
-rw-r--r--erts/emulator/test/trace_SUITE.erl2562
1 files changed, 1430 insertions, 1132 deletions
diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl
index 0f513f0dcb..da6a6bdea4 100644
--- a/erts/emulator/test/trace_SUITE.erl
+++ b/erts/emulator/test/trace_SUITE.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
%%
%% %CopyrightEnd%
%%
@@ -23,97 +24,164 @@
%%% Tests the trace BIF.
%%%
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2, receive_trace/1, self_send/1,
+-export([all/0, suite/0, link_receive_call_correlation/0,
+ receive_trace/1, link_receive_call_correlation/1, self_send/1,
timeout_trace/1, send_trace/1,
- procs_trace/1, dist_procs_trace/1,
+ procs_trace/1, dist_procs_trace/1, procs_new_trace/1,
suspend/1, mutual_suspend/1, suspend_exit/1, suspender_exit/1,
suspend_system_limit/1, suspend_opts/1, suspend_waiting/1,
new_clear/1, existing_clear/1,
set_on_spawn/1, set_on_first_spawn/1, cpu_timestamp/1,
+ set_on_link/1, set_on_first_link/1,
system_monitor_args/1, more_system_monitor_args/1,
system_monitor_long_gc_1/1, system_monitor_long_gc_2/1,
system_monitor_large_heap_1/1, system_monitor_large_heap_2/1,
system_monitor_long_schedule/1,
bad_flag/1, trace_delivered/1]).
--include_lib("test_server/include/test_server.hrl").
+-include_lib("common_test/include/ct.hrl").
%%% Internal exports
-export([process/1]).
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() ->
+ [{ct_hooks,[ts_install_cth]},
+ {timetrap, {seconds, 5}}].
all() ->
- [cpu_timestamp, receive_trace, self_send, timeout_trace,
+ [cpu_timestamp, receive_trace, link_receive_call_correlation,
+ self_send, timeout_trace,
send_trace, procs_trace, dist_procs_trace, suspend,
mutual_suspend, suspend_exit, suspender_exit,
suspend_system_limit, suspend_opts, suspend_waiting,
new_clear, existing_clear, set_on_spawn,
- set_on_first_spawn, system_monitor_args,
+ set_on_first_spawn, set_on_link, set_on_first_link,
+ system_monitor_args,
more_system_monitor_args, system_monitor_long_gc_1,
system_monitor_long_gc_2, system_monitor_large_heap_1,
- system_monitor_long_schedule,
+ system_monitor_long_schedule,
system_monitor_large_heap_2, bad_flag, trace_delivered].
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
-
-end_per_suite(_Config) ->
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
%% No longer testing anything, just reporting whether cpu_timestamp
%% is enabled or not.
cpu_timestamp(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
-
%% Test whether cpu_timestamp is implemented on this platform.
- ?line Works = try erlang:trace(all, true, [cpu_timestamp]) of
- _ ->
- ?line erlang:trace(all, false, [cpu_timestamp]),
- true
- catch
- error:badarg -> false
- end,
-
- ?line test_server:timetrap_cancel(Dog),
+ Works = try erlang:trace(all, true, [cpu_timestamp]) of
+ _ ->
+ erlang:trace(all, false, [cpu_timestamp]),
+ true
+ catch
+ error:badarg -> false
+ end,
{comment,case Works of
- false -> "cpu_timestamp is NOT implemented/does not work";
- true -> "cpu_timestamp works"
- end}.
+ false -> "cpu_timestamp is NOT implemented/does not work";
+ true -> "cpu_timestamp works"
+ end}.
%% Tests that trace(Pid, How, ['receive']) works.
receive_trace(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
- ?line Receiver = fun_spawn(fun receiver/0),
- ?line process_flag(trap_exit, true),
+ Receiver = fun_spawn(fun receiver/0),
%% Trace the process; make sure that we receive the trace messages.
- ?line 1 = erlang:trace(Receiver, true, ['receive']),
- ?line Hello = {hello, world},
- ?line Receiver ! Hello,
- ?line {trace, Receiver, 'receive', Hello} = receive_first(),
- ?line Hello2 = {hello, again, world},
- ?line Receiver ! Hello2,
- ?line {trace, Receiver, 'receive', Hello2} = receive_first(),
- ?line receive_nothing(),
+ 1 = erlang:trace(Receiver, true, ['receive']),
+ Hello = {hello, world},
+ Receiver ! Hello,
+ {trace, Receiver, 'receive', Hello} = receive_first_trace(),
+ Hello2 = {hello, again, world},
+ Receiver ! Hello2,
+ {trace, Receiver, 'receive', Hello2} = receive_first_trace(),
+ receive_nothing(),
+
+ %% Test 'receive' with matchspec
+ F1 = fun ({Pat, IsMatching}) ->
+ set_trace_pattern('receive', Pat, []),
+ Receiver ! Hello,
+ case IsMatching of
+ true ->
+ {trace, Receiver, 'receive', Hello} = receive_first_trace();
+ false ->
+ ok
+ end,
+ receive_nothing()
+ end,
+ From = self(),
+ Node = node(),
+ lists:foreach(F1, [{no, true},
+ {[{[Node, undefined,"Unexpected"],[],[]}], false},
+ {[{[Node, From,'_'],[],[]}], true},
+ {[{[Node, '$1','_'],[{'=/=','$1',From}],[]}], false},
+ {[{['$1', '_','_'],[{'=:=','$1',Node}],[]}], true},
+ {false, false},
+ {true, true}]),
+
+ %% Remote messages
+ OtherName = atom_to_list(?MODULE)++"_receive_trace",
+ {ok, OtherNode} = start_node(OtherName),
+ RemoteProc = spawn_link(OtherNode, ?MODULE, process, [self()]),
+ io:format("RemoteProc = ~p ~n", [RemoteProc]),
+
+ RemoteProc ! {send_please, Receiver, Hello},
+ {trace, Receiver, 'receive', Hello} = receive_first_trace(),
+ RemoteProc ! {send_please, Receiver, 99},
+ {trace, Receiver, 'receive', 99} = receive_first_trace(),
+
+ %% Remote with matchspec
+ F2 = fun (To, {Pat, IsMatching}) ->
+ set_trace_pattern('receive', Pat, []),
+ RemoteProc ! {send_please, To, Hello},
+ case IsMatching of
+ true ->
+ {trace, Receiver, 'receive', Hello} = receive_first_trace();
+ false ->
+ ok
+ end,
+ receive_nothing()
+ end,
+ F2(Receiver, {no, true}),
+ F2(Receiver, {[{[OtherNode, undefined,"Unexpected"],[],[]}], false}),
+ F2(Receiver, {[{[OtherNode, RemoteProc,'_'],[],[]},
+ {[OtherNode, undefined,'_'],[],[]}], true}),
+ F2(Receiver, {[{[OtherNode, '$1','_'],
+ [{'orelse',{'=:=','$1',undefined},{'=/=',{node,'$1'},{node}}}],
+ []}], true}),
+ F2(Receiver, {[{['$1', '_','_'], [{'=:=','$1',OtherNode}], []}], true}),
+ F2(Receiver, {false, false}),
+ F2(Receiver, {true, true}),
+
+ %% Remote to named with matchspec
+ Name = trace_SUITE_receiver,
+ register(Name, Receiver),
+ NN = {Name, node()},
+ F2(NN, {no, true}),
+ F2(NN, {[{[OtherNode, undefined,"Unexpected"],[],[]}], false}),
+ F2(NN, {[{[OtherNode, RemoteProc,'_'],[],[]},
+ {[OtherNode, undefined,'_'],[],[]}], true}),
+ F2(NN, {[{[OtherNode, '$1','_'],
+ [{'orelse',{'=:=','$1',undefined},{'=/=',{node,'$1'},{node}}}],
+ []}], true}),
+ F2(NN, {[{['$1', '_','_'], [{'==','$1',OtherNode}], []}], true}),
+ F2(NN, {false, false}),
+ F2(NN, {true, true}),
+
+ unlink(RemoteProc),
+ true = stop_node(OtherNode),
+
+ %% Timeout
+ Receiver ! {set_timeout, 10},
+ {trace, Receiver, 'receive', {set_timeout, 10}} = receive_first_trace(),
+ {trace, Receiver, 'receive', timeout} = receive_first_trace(),
+ erlang:trace_pattern('receive', [{[clock_service,undefined,timeout], [], []}], []),
+ Receiver ! {set_timeout, 7},
+ {trace, Receiver, 'receive', timeout} = receive_first_trace(),
+ erlang:trace_pattern('receive', true, []),
%% Another process should not be able to trace Receiver.
- ?line Intruder = fun_spawn(fun() -> erlang:trace(Receiver, true, ['receive']) end),
- ?line {'EXIT', Intruder, {badarg, _}} = receive_first(),
+ process_flag(trap_exit, true),
+ Intruder = fun_spawn(fun() -> erlang:trace(Receiver, true, ['receive']) end),
+ {'EXIT', Intruder, {badarg, _}} = receive_first(),
%% Untrace the process; we should not receive anything.
?line 1 = erlang:trace(Receiver, false, ['receive']),
@@ -121,378 +189,663 @@ receive_trace(Config) when is_list(Config) ->
?line Receiver ! any_garbage,
?line receive_nothing(),
- %% Done.
- ?line test_server:timetrap_cancel(Dog),
+ %% Verify restrictions in matchspec for 'receive'
+ F3 = fun (Pat) -> {'EXIT', {badarg,_}} = (catch erlang:trace_pattern('receive', Pat, [])) end,
+ WC = ['_','_','_'],
+ F3([{WC,[],[{message, {process_dump}}]}]),
+ F3([{WC,[{is_seq_trace}],[]}]),
+ F3([{WC,[],[{set_seq_token,label,4711}]}]),
+ F3([{WC,[],[{get_seq_token}]}]),
+ F3([{WC,[],[{enable_trace,call}]}]),
+ F3([{WC,[],[{enable_trace,self(),call}]}]),
+ F3([{WC,[],[{disable_trace,call}]}]),
+ F3([{WC,[],[{disable_trace,self(),call}]}]),
+ F3([{WC,[],[{trace,[call],[]}]}]),
+ F3([{WC,[],[{trace,self(),[],[call]}]}]),
+ F3([{WC,[],[{caller}]}]),
+ F3([{WC,[],[{silent,true}]}]),
+
ok.
-self_send(doc) -> ["Test that traces are generated for messages sent ",
- "and received to/from self()."];
+%% Tests that receive of a message always happens before a call with
+%% that message and that links/unlinks are ordered together with the
+%% 'receive'.
+link_receive_call_correlation() ->
+ [{timetrap, {minutes, 5}}].
+link_receive_call_correlation(Config) when is_list(Config) ->
+ Receiver = fun_spawn(fun F() ->
+ receive
+ stop -> ok;
+ M -> receive_msg(M), F()
+ end
+ end),
+ process_flag(trap_exit, true),
+
+ %% Trace the process; make sure that we receive the trace messages.
+ 1 = erlang:trace(Receiver, true, ['receive', procs, call, timestamp, scheduler_id]),
+ 1 = erlang:trace_pattern({?MODULE, receive_msg, '_'}, [], [local]),
+
+ Num = 100000,
+
+ (fun F(0) -> [];
+ F(N) ->
+ if N rem 2 == 0 ->
+ link(Receiver);
+ true ->
+ unlink(Receiver)
+ end,
+ [Receiver ! N | F(N-1)]
+ end)(Num),
+
+ Receiver ! stop,
+ MonRef = erlang:monitor(process, Receiver),
+ receive {'DOWN', MonRef, _, _, _} -> ok end,
+ Ref = erlang:trace_delivered(Receiver),
+ receive {trace_delivered, _, Ref} -> ok end,
+
+ Msgs = (fun F() -> receive M -> [M | F()] after 1 -> [] end end)(),
+
+ case check_consistent(Receiver, Num, Num, Num, Msgs) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ ct:log("~p", [Msgs]),
+ ct:fail({error, Reason})
+ end.
+
+-define(schedid, , _).
+
+check_consistent(_Pid, Recv, Call, _LU, [Msg | _]) when Recv > Call ->
+ {error, Msg};
+check_consistent(Pid, Recv, Call, LU, [Msg | Msgs]) ->
+
+ case Msg of
+ {trace, Pid, 'receive', Recv ?schedid} ->
+ check_consistent(Pid,Recv - 1, Call, LU, Msgs);
+ {trace_ts, Pid, 'receive', Recv ?schedid, _} ->
+ check_consistent(Pid,Recv - 1, Call, LU, Msgs);
+
+ {trace, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid} ->
+ check_consistent(Pid,Recv, Call - 1, LU, Msgs);
+ {trace_ts, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid, _} ->
+ check_consistent(Pid,Recv, Call - 1, LU, Msgs);
+
+ %% We check that for each receive we have gotten a
+ %% getting_linked or getting_unlinked message. Also
+ %% if we receive a getting_linked, then the next
+ %% message we expect to receive is an even number
+ %% and odd number for getting_unlinked.
+ {trace, Pid, getting_linked, _Self ?schedid}
+ when Recv rem 2 == 0, Recv == LU ->
+ check_consistent(Pid, Recv, Call, LU - 1, Msgs);
+ {trace_ts, Pid, getting_linked, _Self ?schedid, _}
+ when Recv rem 2 == 0, Recv == LU ->
+ check_consistent(Pid, Recv, Call, LU - 1, Msgs);
+
+ {trace, Pid, getting_unlinked, _Self ?schedid}
+ when Recv rem 2 == 1, Recv == LU ->
+ check_consistent(Pid, Recv, Call, LU - 1, Msgs);
+ {trace_ts, Pid, getting_unlinked, _Self ?schedid, _}
+ when Recv rem 2 == 1, Recv == LU ->
+ check_consistent(Pid, Recv, Call, LU - 1, Msgs);
+
+ {trace,Pid,'receive',Ignore ?schedid}
+ when Ignore == stop; Ignore == timeout ->
+ check_consistent(Pid, Recv, Call, LU, Msgs);
+ {trace_ts,Pid,'receive',Ignore ?schedid,_}
+ when Ignore == stop; Ignore == timeout ->
+ check_consistent(Pid, Recv, Call, LU, Msgs);
+
+ {trace, Pid, exit, normal ?schedid} ->
+ check_consistent(Pid, Recv, Call, LU, Msgs);
+ {trace_ts, Pid, exit, normal ?schedid, _} ->
+ check_consistent(Pid, Recv, Call, LU, Msgs);
+ {'EXIT', Pid, normal} ->
+ check_consistent(Pid, Recv, Call, LU, Msgs);
+ Msg ->
+ {error, Msg}
+ end;
+check_consistent(_, 0, 0, 0, []) ->
+ ok;
+check_consistent(_, Recv, Call, LU, []) ->
+ {error,{Recv, Call, LU}}.
+
+receive_msg(M) ->
+ M.
+
+%% Test that traces are generated for messages sent
+%% and received to/from self().
self_send(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
- ?line Fun =
- fun(Self, Parent) -> receive
- go_ahead ->
- self() ! from_myself,
- Self(Self, Parent);
- from_myself ->
- Parent ! done
- end
- end,
- ?line Self = self(),
- ?line SelfSender = fun_spawn(Fun, [Fun, Self]),
- ?line erlang:trace(SelfSender, true, ['receive', 'send']),
- ?line SelfSender ! go_ahead,
- ?line receive {trace, SelfSender, 'receive', go_ahead} -> ok end,
- ?line receive {trace, SelfSender, 'receive', from_myself} -> ok end,
- ?line receive
- {trace,SelfSender,send,from_myself,SelfSender} -> ok
- end,
- ?line receive {trace,SelfSender,send,done,Self} -> ok end,
- ?line receive done -> ok end,
-
- ?line test_server:timetrap_cancel(Dog),
+ Fun =
+ fun(Self, Parent) -> receive
+ go_ahead ->
+ self() ! from_myself,
+ Self(Self, Parent);
+ from_myself ->
+ Parent ! done
+ end
+ end,
+ Self = self(),
+ SelfSender = fun_spawn(Fun, [Fun, Self]),
+ erlang:trace(SelfSender, true, ['receive', 'send']),
+ SelfSender ! go_ahead,
+ receive {trace, SelfSender, 'receive', go_ahead} -> ok end,
+ receive {trace, SelfSender, 'receive', from_myself} -> ok end,
+ receive
+ {trace,SelfSender,send,from_myself,SelfSender} -> ok
+ end,
+ receive {trace,SelfSender,send,done,Self} -> ok end,
+ receive done -> ok end,
ok.
%% Test that we can receive timeout traces.
timeout_trace(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
-
- ?line Process = fun_spawn(fun process/0),
- ?line 1 = erlang:trace(Process, true, ['receive']),
- ?line Process ! timeout_please,
- ?line {trace, Process, 'receive', timeout_please} = receive_first(),
- ?line {trace, Process, 'receive', timeout} = receive_first(),
- ?line receive_nothing(),
-
- ?line test_server:timetrap_cancel(Dog),
+ Process = fun_spawn(fun process/0),
+ 1 = erlang:trace(Process, true, ['receive']),
+ Process ! timeout_please,
+ {trace, Process, 'receive', timeout_please} = receive_first_trace(),
+ {trace, Process, 'receive', timeout} = receive_first_trace(),
+ receive_nothing(),
ok.
%% Tests that trace(Pid, How, [send]) works.
send_trace(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
- ?line process_flag(trap_exit, true),
- ?line Sender = fun_spawn(fun sender/0),
- ?line Receiver = fun_spawn(fun receiver/0),
+ process_flag(trap_exit, true),
+ Sender = fun_spawn(fun sender/0),
+ Receiver = fun_spawn(fun receiver/0),
%% Check that a message sent to another process is traced.
- ?line 1 = erlang:trace(Sender, true, [send]),
- ?line Sender ! {send_please, Receiver, to_receiver},
- ?line {trace, Sender, send, to_receiver, Receiver} = receive_first(),
- ?line receive_nothing(),
+ 1 = erlang:trace(Sender, true, [send]),
+ F1 = fun (Pat) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, Receiver, to_receiver},
+ {trace, Sender, send, to_receiver, Receiver} = receive_first_trace(),
+ receive_nothing()
+ end,
+ lists:foreach(F1, [no,
+ [{[Receiver,to_receiver],[],[]}],
+ [{['_','_'],[],[]}],
+ [{['$1','_'],[{is_pid,'$1'}],[]}],
+ [{['_','$1'],[{is_atom,'$1'}],[]}],
+ true]),
+
+ %% Test {message, Msg}
+ F1m = fun ({Pat, Msg}) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, Receiver, to_receiver},
+ {trace, Sender, send, to_receiver, Receiver, Msg} = receive_first_trace(),
+ receive_nothing()
+ end,
+ lists:foreach(F1m, [{[{['_','_'],[],[{message, 4711}]}], 4711},
+ {[{['_','_'],[],[{message, "4711"}]}], "4711"}
+ ]),
+
+ %% Test {message, {process_dump}}
+ set_trace_pattern(send, [{['_','_'],[],[{message, {process_dump}}]}], []),
+ Sender ! {send_please, Receiver, to_receiver},
+ {trace, Sender, send, to_receiver, Receiver, ProcDump} = receive_first_trace(),
+ true = is_binary(ProcDump),
+ receive_nothing(),
+
+ %% Same test with false match spec
+ F2 = fun (Pat) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, Receiver, to_receiver},
+ receive_nothing()
+ end,
+ lists:foreach(F2, [[{[Sender,to_receiver],[],[]}],
+ [{[Receiver,nomatch],[],[]}],
+ [{['$1','_'],[{is_atom,'$1'}],[]}],
+ [{['_','$1'],[{is_pid,'$1'}],[]}],
+ false,
+ [{['_','_'],[],[{message,false}]}],
+ [{['_','_'],[],[{silent,true}]}]]),
+ erlang:trace_pattern(send, true, []),
+ erlang:trace(Sender, false, [silent]),
+
+ %% Check that a message sent to another registered process is traced.
+ register(?MODULE,Receiver),
+ F3 = fun (Pat) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, ?MODULE, to_receiver},
+ {trace, Sender, send, to_receiver, ?MODULE} = receive_first_trace(),
+ receive_nothing()
+ end,
+ lists:foreach(F3, [no,
+ [{[?MODULE,to_receiver],[],[]}],
+ [{['_','_'],[],[]}],
+ [{['$1','_'],[{is_atom,'$1'}],[]}],
+ [{['_','$1'],[{is_atom,'$1'}],[]}],
+ true]),
+ %% Again with false match spec
+ F4 = fun (Pat) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, ?MODULE, to_receiver},
+ receive_nothing()
+ end,
+ lists:foreach(F4, [[{[nomatch,to_receiver],[],[]}],
+ [{[?MODULE,nomatch],[],[]}],
+ [{['$1','_'],[{is_pid,'$1'}],[]}],
+ [{['_','$1'],[{is_pid,'$1'}],[]}],
+ [{['_','_'],[],[{message,false}]}],
+ [{['_','_'],[],[{silent,true}]}]
+ ]),
+ unregister(?MODULE),
+ erlang:trace_pattern(send, true, []),
+ erlang:trace(Sender, false, [silent]),
%% Check that a message sent to this process is traced.
- ?line Sender ! {send_please, self(), to_myself},
- ?line receive to_myself -> ok end,
- ?line Self = self(),
- ?line {trace, Sender, send, to_myself, Self} = receive_first(),
- ?line receive_nothing(),
+ F5 = fun (Pat) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, self(), to_myself},
+ receive to_myself -> ok end,
+ Self = self(),
+ {trace, Sender, send, to_myself, Self} = receive_first_trace(),
+ receive_nothing()
+ end,
+ lists:foreach(F5, [no,
+ [{[self(),to_myself],[],[]}],
+ [{['_','_'],[],[]}],
+ true]),
+
+ %% Check that a message sent to dead process is traced.
+ {Pid,Ref} = spawn_monitor(fun() -> ok end),
+ receive {'DOWN',Ref,_,_,_} -> ok end,
+ F6 = fun (Pat) ->
+ set_trace_pattern(send, Pat, []),
+ Sender ! {send_please, Pid, to_dead},
+ {trace, Sender, send_to_non_existing_process, to_dead, Pid} = receive_first_trace(),
+ receive_nothing()
+ end,
+ lists:foreach(F6, [no,
+ [{[Pid,to_dead],[],[]}],
+ [{['_','_'],[],[]}],
+ true]),
+
+ %% Check that a message sent to unknown registrated process is traced.
+ BadargSender = fun_spawn(fun sender/0),
+ 1 = erlang:trace(BadargSender, true, [send]),
+ unlink(BadargSender),
+ BadargSender ! {send_please, not_registered, to_unknown},
+ {trace, BadargSender, send, to_unknown, not_registered} = receive_first_trace(),
+ receive_nothing(),
%% Another process should not be able to trace Sender.
- ?line Intruder = fun_spawn(fun() -> erlang:trace(Sender, true, [send]) end),
- ?line {'EXIT', Intruder, {badarg, _}} = receive_first(),
+ Intruder = fun_spawn(fun() -> erlang:trace(Sender, true, [send]) end),
+ {'EXIT', Intruder, {badarg, _}} = receive_first(),
%% Untrace the sender process and make sure that we receive no more
%% trace messages.
- ?line 1 = erlang:trace(Sender, false, [send]),
- ?line Sender ! {send_please, Receiver, to_receiver},
- ?line Sender ! {send_please, self(), to_myself_again},
- ?line receive to_myself_again -> ok end,
- ?line receive_nothing(),
+ 1 = erlang:trace(Sender, false, [send]),
+ Sender ! {send_please, Receiver, to_receiver},
+ Sender ! {send_please, self(), to_myself_again},
+ receive to_myself_again -> ok end,
+ receive_nothing(),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [global])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [local])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [meta])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [{meta,self()}])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [call_count])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [call_time])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, restart, [])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, pause, [])),
+ {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, [{['_','_'],[],[{caller}]}], [])),
+
%% Done.
- ?line test_server:timetrap_cancel(Dog),
ok.
+set_trace_pattern(_, no, _) -> 0;
+set_trace_pattern(MFA, Pat, Flg) ->
+ R = erlang:trace_pattern(MFA, Pat, Flg),
+ {match_spec, Pat} = erlang:trace_info(MFA, match_spec),
+ R.
+
%% Test trace(Pid, How, [procs]).
procs_trace(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
- ?line Name = list_to_atom(atom_to_list(?MODULE)++"_procs_trace"),
- ?line Self = self(),
- ?line process_flag(trap_exit, true),
+ Name = list_to_atom(atom_to_list(?MODULE)++"_procs_trace"),
+ Self = self(),
+ process_flag(trap_exit, true),
%%
- ?line Proc1 = spawn_link(?MODULE, process, [Self]),
- ?line io:format("Proc1 = ~p ~n", [Proc1]),
- ?line Proc2 = spawn(?MODULE, process, [Self]),
- ?line io:format("Proc2 = ~p ~n", [Proc2]),
+ Proc1 = spawn_link(?MODULE, process, [Self]),
+ io:format("Proc1 = ~p ~n", [Proc1]),
+ Proc2 = spawn(?MODULE, process, [Self]),
+ io:format("Proc2 = ~p ~n", [Proc2]),
%%
- ?line 1 = erlang:trace(Proc1, true, [procs]),
- ?line MFA = {?MODULE, process, [Self]},
+ 1 = erlang:trace(Proc1, true, [procs, set_on_first_spawn]),
+ MFA = {?MODULE, process, [Self]},
%%
%% spawn, link
- ?line Proc1 ! {spawn_link_please, Self, MFA},
- ?line Proc3 = receive {spawned, Proc1, P3} -> P3 end,
- ?line {trace, Proc1, spawn, Proc3, MFA} = receive_first(),
- ?line io:format("Proc3 = ~p ~n", [Proc3]),
- ?line {trace, Proc1, link, Proc3} = receive_first(),
- ?line receive_nothing(),
+ Proc1 ! {spawn_link_please, Self, MFA},
+ Proc3 = receive {spawned, Proc1, P3} -> P3 end,
+ receive {trace, Proc3, spawned, Proc1, MFA} -> ok end,
+ receive {trace, Proc3, getting_linked, Proc1} -> ok end,
+ {trace, Proc1, spawn, Proc3, MFA} = receive_first_trace(),
+ io:format("Proc3 = ~p ~n", [Proc3]),
+ {trace, Proc1, link, Proc3} = receive_first_trace(),
+ receive_nothing(),
%%
%% getting_unlinked by exit()
- ?line Proc1 ! {trap_exit_please, true},
- ?line Reason3 = make_ref(),
- ?line Proc1 ! {send_please, Proc3, {exit_please, Reason3}},
- ?line receive {Proc1, {'EXIT', Proc3, Reason3}} -> ok end,
- ?line {trace, Proc1, getting_unlinked, Proc3} = receive_first(),
- ?line Proc1 ! {trap_exit_please, false},
- ?line receive_nothing(),
+ Proc1 ! {trap_exit_please, true},
+ Reason3 = make_ref(),
+ Proc1 ! {send_please, Proc3, {exit_please, Reason3}},
+ receive {Proc1, {'EXIT', Proc3, Reason3}} -> ok end,
+ receive {trace, Proc3, exit, Reason3} -> ok end,
+ {trace, Proc1, getting_unlinked, Proc3} = receive_first_trace(),
+ Proc1 ! {trap_exit_please, false},
+ receive_nothing(),
%%
%% link
- ?line Proc1 ! {link_please, Proc2},
- ?line {trace, Proc1, link, Proc2} = receive_first(),
- ?line receive_nothing(),
+ Proc1 ! {link_please, Proc2},
+ {trace, Proc1, link, Proc2} = receive_first_trace(),
+ receive_nothing(),
%%
%% unlink
- ?line Proc1 ! {unlink_please, Proc2},
- ?line {trace, Proc1, unlink, Proc2} = receive_first(),
- ?line receive_nothing(),
+ Proc1 ! {unlink_please, Proc2},
+ {trace, Proc1, unlink, Proc2} = receive_first_trace(),
+ receive_nothing(),
%%
%% getting_linked
- ?line Proc2 ! {link_please, Proc1},
- ?line {trace, Proc1, getting_linked, Proc2} = receive_first(),
- ?line receive_nothing(),
+ Proc2 ! {link_please, Proc1},
+ {trace, Proc1, getting_linked, Proc2} = receive_first_trace(),
+ receive_nothing(),
%%
%% getting_unlinked
- ?line Proc2 ! {unlink_please, Proc1},
- ?line {trace, Proc1, getting_unlinked, Proc2} = receive_first(),
- ?line receive_nothing(),
+ Proc2 ! {unlink_please, Proc1},
+ {trace, Proc1, getting_unlinked, Proc2} = receive_first_trace(),
+ receive_nothing(),
%%
%% register
- ?line true = register(Name, Proc1),
- ?line {trace, Proc1, register, Name} = receive_first(),
- ?line receive_nothing(),
+ true = register(Name, Proc1),
+ {trace, Proc1, register, Name} = receive_first_trace(),
+ receive_nothing(),
%%
%% unregister
- ?line true = unregister(Name),
- ?line {trace, Proc1, unregister, Name} = receive_first(),
- ?line receive_nothing(),
+ true = unregister(Name),
+ {trace, Proc1, unregister, Name} = receive_first_trace(),
+ receive_nothing(),
%%
%% exit (with registered name, due to link)
- ?line Reason4 = make_ref(),
- ?line Proc1 ! {spawn_link_please, Self, MFA},
- ?line Proc4 = receive {spawned, Proc1, P4} -> P4 end,
- ?line {trace, Proc1, spawn, Proc4, MFA} = receive_first(),
- ?line io:format("Proc4 = ~p ~n", [Proc4]),
- ?line {trace, Proc1, link, Proc4} = receive_first(),
- ?line Proc1 ! {register_please, Name, Proc1},
- ?line {trace, Proc1, register, Name} = receive_first(),
- ?line Proc4 ! {exit_please, Reason4},
- ?line receive {'EXIT', Proc1, Reason4} -> ok end,
- ?line {trace, Proc1, exit, Reason4} = receive_first(),
- ?line {trace, Proc1, unregister, Name} = receive_first(),
- ?line receive_nothing(),
+ Reason4 = make_ref(),
+ Proc1 ! {spawn_link_please, Self, MFA},
+ Proc4 = receive {spawned, Proc1, P4} -> P4 end,
+ {trace, Proc1, spawn, Proc4, MFA} = receive_first_trace(),
+ io:format("Proc4 = ~p ~n", [Proc4]),
+ {trace, Proc1, link, Proc4} = receive_first_trace(),
+ Proc1 ! {register_please, Name, Proc1},
+ {trace, Proc1, register, Name} = receive_first_trace(),
+ Proc4 ! {exit_please, Reason4},
+ receive {'EXIT', Proc1, Reason4} -> ok end,
+ {trace, Proc1, exit, Reason4} = receive_first_trace(),
+ {trace, Proc1, unregister, Name} = receive_first_trace(),
+ receive_nothing(),
%%
%% exit (not linked to tracing process)
- ?line 1 = erlang:trace(Proc2, true, [procs]),
- ?line Reason2 = make_ref(),
- ?line Proc2 ! {exit_please, Reason2},
- ?line {trace, Proc2, exit, Reason2} = receive_first(),
- ?line receive_nothing(),
- %%
- %% Done.
- ?line test_server:timetrap_cancel(Dog),
+ 1 = erlang:trace(Proc2, true, [procs]),
+ Reason2 = make_ref(),
+ Proc2 ! {exit_please, Reason2},
+ {trace, Proc2, exit, Reason2} = receive_first_trace(),
+ receive_nothing(),
ok.
dist_procs_trace(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(15)),
- ?line OtherName = atom_to_list(?MODULE)++"_dist_procs_trace",
- ?line {ok, OtherNode} = start_node(OtherName),
- ?line Self = self(),
- ?line process_flag(trap_exit, true),
+ ct:timetrap({seconds, 15}),
+ OtherName = atom_to_list(?MODULE)++"_dist_procs_trace",
+ {ok, OtherNode} = start_node(OtherName),
+ Self = self(),
+ process_flag(trap_exit, true),
%%
- ?line Proc1 = spawn_link(?MODULE, process, [Self]),
- ?line io:format("Proc1 = ~p ~n", [Proc1]),
- ?line Proc2 = spawn(OtherNode, ?MODULE, process, [Self]),
- ?line io:format("Proc2 = ~p ~n", [Proc2]),
+ Proc1 = spawn_link(?MODULE, process, [Self]),
+ io:format("Proc1 = ~p ~n", [Proc1]),
+ Proc2 = spawn(OtherNode, ?MODULE, process, [Self]),
+ io:format("Proc2 = ~p ~n", [Proc2]),
%%
- ?line 1 = erlang:trace(Proc1, true, [procs]),
- ?line MFA = {?MODULE, process, [Self]},
+ 1 = erlang:trace(Proc1, true, [procs]),
+ MFA = {?MODULE, process, [Self]},
%%
%% getting_unlinked by exit()
- ?line Proc1 ! {spawn_link_please, Self, OtherNode, MFA},
- ?line Proc1 ! {trap_exit_please, true},
- ?line Proc3 = receive {spawned, Proc1, P3} -> P3 end,
- ?line io:format("Proc3 = ~p ~n", [Proc3]),
- ?line {trace, Proc1, getting_linked, Proc3} = receive_first(),
- ?line Reason3 = make_ref(),
- ?line Proc1 ! {send_please, Proc3, {exit_please, Reason3}},
- ?line receive {Proc1, {'EXIT', Proc3, Reason3}} -> ok end,
- ?line {trace, Proc1, getting_unlinked, Proc3} = receive_first(),
- ?line Proc1 ! {trap_exit_please, false},
- ?line receive_nothing(),
+ Proc1 ! {spawn_link_please, Self, OtherNode, MFA},
+ Proc1 ! {trap_exit_please, true},
+ Proc3 = receive {spawned, Proc1, P3} -> P3 end,
+ io:format("Proc3 = ~p ~n", [Proc3]),
+ {trace, Proc1, getting_linked, Proc3} = receive_first_trace(),
+ Reason3 = make_ref(),
+ Proc1 ! {send_please, Proc3, {exit_please, Reason3}},
+ receive {Proc1, {'EXIT', Proc3, Reason3}} -> ok end,
+ {trace, Proc1, getting_unlinked, Proc3} = receive_first_trace(),
+ Proc1 ! {trap_exit_please, false},
+ receive_nothing(),
%%
%% link
- ?line Proc1 ! {link_please, Proc2},
- ?line {trace, Proc1, link, Proc2} = receive_first(),
- ?line receive_nothing(),
+ Proc1 ! {link_please, Proc2},
+ {trace, Proc1, link, Proc2} = receive_first_trace(),
+ receive_nothing(),
%%
%% unlink
- ?line Proc1 ! {unlink_please, Proc2},
- ?line {trace, Proc1, unlink, Proc2} = receive_first(),
- ?line receive_nothing(),
+ Proc1 ! {unlink_please, Proc2},
+ {trace, Proc1, unlink, Proc2} = receive_first_trace(),
+ receive_nothing(),
%%
%% getting_linked
- ?line Proc2 ! {link_please, Proc1},
- ?line {trace, Proc1, getting_linked, Proc2} = receive_first(),
- ?line receive_nothing(),
+ Proc2 ! {link_please, Proc1},
+ {trace, Proc1, getting_linked, Proc2} = receive_first_trace(),
+ receive_nothing(),
%%
%% getting_unlinked
- ?line Proc2 ! {unlink_please, Proc1},
- ?line {trace, Proc1, getting_unlinked, Proc2} = receive_first(),
- ?line receive_nothing(),
+ Proc2 ! {unlink_please, Proc1},
+ {trace, Proc1, getting_unlinked, Proc2} = receive_first_trace(),
+ receive_nothing(),
+
%%
%% exit (with registered name, due to link)
- ?line Name = list_to_atom(OtherName),
- ?line Reason2 = make_ref(),
- ?line Proc1 ! {link_please, Proc2},
- ?line {trace, Proc1, link, Proc2} = receive_first(),
- ?line Proc1 ! {register_please, Name, Proc1},
- ?line {trace, Proc1, register, Name} = receive_first(),
- ?line Proc2 ! {exit_please, Reason2},
- ?line receive {'EXIT', Proc1, Reason2} -> ok end,
- ?line {trace, Proc1, exit, Reason2} = receive_first(),
- ?line {trace, Proc1, unregister, Name} = receive_first(),
- ?line receive_nothing(),
+ Name = list_to_atom(OtherName),
+ Reason2 = make_ref(),
+ Proc1 ! {link_please, Proc2},
+ {trace, Proc1, link, Proc2} = receive_first_trace(),
+ Proc1 ! {register_please, Name, Proc1},
+ {trace, Proc1, register, Name} = receive_first_trace(),
+ Proc2 ! {exit_please, Reason2},
+ receive {'EXIT', Proc1, Reason2} -> ok end,
+ {trace, Proc1, exit, Reason2} = receive_first_trace(),
+ {trace, Proc1, unregister, Name} = receive_first_trace(),
+ receive_nothing(),
%%
%% Done.
- ?line true = stop_node(OtherNode),
- ?line test_server:timetrap_cancel(Dog),
+ true = stop_node(OtherNode),
ok.
+%% Test trace(new, How, [procs]).
+procs_new_trace(Config) when is_list(Config) ->
+ Self = self(),
+ process_flag(trap_exit, true),
+ %%
+ Proc1 = spawn_link(?MODULE, process, [Self]),
+ io:format("Proc1 = ~p ~n", [Proc1]),
+ %%
+ 0 = erlang:trace(new, true, [procs]),
+
+ MFA = {?MODULE, process, [Self]},
+ %%
+ %% spawn, link
+ Proc1 ! {spawn_link_please, Self, MFA},
+ Proc3 = receive {spawned, Proc1, P3} -> P3 end,
+ receive {trace, Proc3, spawned, Proc1, MFA} -> ok end,
+ receive {trace, Proc3, getting_linked, Proc1} -> ok end,
+ io:format("Proc3 = ~p ~n", [Proc3]),
+ receive_nothing(),
+ %%
+ %%
+ %% exit (not linked to tracing process)
+ Reason1 = make_ref(),
+ Proc1 ! {exit_please, Reason1},
+ receive {'EXIT', Proc1, Reason1} -> ok end,
+ {trace, Proc3, exit, Reason1} = receive_first_trace(),
+ receive_nothing(),
+ ok.
%% Tests trace(Pid, How, [set_on_spawn]).
set_on_spawn(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
- ?line Listener = fun_spawn(fun process/0),
+ Listener = fun_spawn(fun process/0),
%% Create and trace a process with the set_on_spawn flag.
%% Make sure it is traced.
- ?line Father_SOS = fun_spawn(fun process/0),
- ?line 1 = erlang:trace(Father_SOS, true, [send, set_on_spawn]),
- ?line true = is_send_traced(Father_SOS, Listener, sos_father),
+ Father_SOS = fun_spawn(fun process/0),
+ 1 = erlang:trace(Father_SOS, true, [send, set_on_spawn]),
+ true = is_send_traced(Father_SOS, Listener, sos_father),
%% Have the process spawn of two children and test that they
%% are traced.
- ?line [Child1, Child2] = spawn_children(Father_SOS, 2),
- ?line true = is_send_traced(Child1, Listener, child1),
- ?line true = is_send_traced(Child2, Listener, child2),
+ [Child1, Child2] = spawn_children(Father_SOS, 2),
+ true = is_send_traced(Child1, Listener, child1),
+ true = is_send_traced(Child2, Listener, child2),
%% Second generation.
[Child11, Child12] = spawn_children(Child1, 2),
- ?line true = is_send_traced(Child11, Listener, child11),
- ?line true = is_send_traced(Child12, Listener, child12),
-
- %% Done.
- ?line test_server:timetrap_cancel(Dog),
+ true = is_send_traced(Child11, Listener, child11),
+ true = is_send_traced(Child12, Listener, child12),
ok.
%% Tests trace(Pid, How, [set_on_first_spawn]).
set_on_first_spawn(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(10)),
- ?line Listener = fun_spawn(fun process/0),
+ ct:timetrap({seconds, 10}),
+ Listener = fun_spawn(fun process/0),
%% Create and trace a process with the set_on_first_spawn flag.
%% Make sure it is traced.
- ?line Parent = fun_spawn(fun process/0),
- ?line 1 = erlang:trace(Parent, true, [send, set_on_first_spawn]),
- ?line is_send_traced(Parent, Listener, sos_father),
+ Parent = fun_spawn(fun process/0),
+ 1 = erlang:trace(Parent, true, [send, set_on_first_spawn]),
+ is_send_traced(Parent, Listener, sos_father),
%% Have the process spawn off three children and test that the
%% first is traced.
- ?line [Child1, Child2, Child3] = spawn_children(Parent, 3),
- ?line true = is_send_traced(Child1, Listener, child1),
- ?line false = is_send_traced(Child2, Listener, child2),
- ?line false = is_send_traced(Child3, Listener, child3),
- ?line receive_nothing(),
+ [Child1, Child2, Child3] = spawn_children(Parent, 3),
+ true = is_send_traced(Child1, Listener, child1),
+ false = is_send_traced(Child2, Listener, child2),
+ false = is_send_traced(Child3, Listener, child3),
+ receive_nothing(),
+ ok.
- %% Done.
- ?line test_server:timetrap_cancel(Dog),
+%% Tests trace(Pid, How, [set_on_link]).
+
+set_on_link(Config) ->
+ Listener = fun_spawn(fun process/0),
+
+ %% Create and trace a process with the set_on_link flag.
+ %% Make sure it is traced.
+ Father_SOL = fun_spawn(fun process/0),
+ 1 = erlang:trace(Father_SOL, true, [send, set_on_link]),
+ true = is_send_traced(Father_SOL, Listener, sol_father),
+
+ %% Have the process spawn of two children and test that they
+ %% are traced.
+ [Child1, Child2] = spawn_children(Father_SOL, 2),
+ true = is_send_traced(Child1, Listener, child1),
+ true = is_send_traced(Child2, Listener, child2),
+
+ %% Second generation.
+ [Child11, Child12] = spawn_children(Child1, 2),
+ true = is_send_traced(Child11, Listener, child11),
+ true = is_send_traced(Child12, Listener, child12),
ok.
+%% Tests trace(Pid, How, [set_on_first_spawn]).
+
+set_on_first_link(Config) ->
+ ct:timetrap({seconds, 10}),
+ Listener = fun_spawn(fun process/0),
-system_monitor_args(doc) ->
- ["Tests arguments to erlang:system_monitor/0-2)"];
+ %% Create and trace a process with the set_on_first_spawn flag.
+ %% Make sure it is traced.
+ Parent = fun_spawn(fun process/0),
+ 1 = erlang:trace(Parent, true, [send, set_on_first_link]),
+ is_send_traced(Parent, Listener, sol_father),
+
+ %% Have the process spawn off three children and test that the
+ %% first is traced.
+ [Child1, Child2, Child3] = spawn_children(Parent, 3),
+ true = is_send_traced(Child1, Listener, child1),
+ false = is_send_traced(Child2, Listener, child2),
+ false = is_send_traced(Child3, Listener, child3),
+ receive_nothing(),
+ ok.
+
+
+
+%% Tests arguments to erlang:system_monitor/0,1,2
system_monitor_args(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
- ?line Self = self(),
+ Self = self(),
%%
- ?line OldMonitor = erlang:system_monitor(undefined),
- ?line undefined = erlang:system_monitor(Self, [{long_gc,0}]),
- ?line MinT = case erlang:system_monitor() of
- {Self,[{long_gc,T}]} when is_integer(T), T > 0 -> T;
- Other1 -> test_server:fault(Other1)
- end,
- ?line {Self,[{long_gc,MinT}]} = erlang:system_monitor(),
- ?line {Self,[{long_gc,MinT}]} =
- erlang:system_monitor({Self,[{large_heap,0}]}),
- ?line MinN = case erlang:system_monitor() of
- {Self,[{large_heap,N}]} when is_integer(N), N > 0 -> N;
- Other2 -> test_server:fault(Other2)
- end,
- ?line {Self,[{large_heap,MinN}]} = erlang:system_monitor(),
- ?line {Self,[{large_heap,MinN}]} =
- erlang:system_monitor(Self, [busy_port]),
- ?line {Self,[busy_port]} = erlang:system_monitor(),
- ?line {Self,[busy_port]} =
- erlang:system_monitor({Self,[busy_dist_port]}),
- ?line {Self,[busy_dist_port]} = erlang:system_monitor(),
- ?line All = lists:sort([busy_port,busy_dist_port,
- {long_gc,1},{large_heap,65535}]),
- ?line {Self,[busy_dist_port]} = erlang:system_monitor(Self, All),
- ?line {Self,A1} = erlang:system_monitor(),
- ?line All = lists:sort(A1),
- ?line {Self,A1} = erlang:system_monitor(Self, []),
- ?line Pid = spawn(fun () -> receive {Self,die} -> exit(die) end end),
- ?line Mref = erlang:monitor(process, Pid),
- ?line undefined = erlang:system_monitor(Pid, All),
- ?line {Pid,A2} = erlang:system_monitor(),
- ?line All = lists:sort(A2),
- ?line Pid ! {Self,die},
- ?line receive {'DOWN',Mref,_,_,_} -> ok end,
- ?line undefined = erlang:system_monitor(OldMonitor),
- ?line erlang:yield(),
- ?line OldMonitor = erlang:system_monitor(),
+ OldMonitor = erlang:system_monitor(undefined),
+ undefined = erlang:system_monitor(Self, [{long_gc,0}]),
+ MinT = case erlang:system_monitor() of
+ {Self,[{long_gc,T}]} when is_integer(T), T > 0 -> T;
+ Other1 -> test_server:fault(Other1)
+ end,
+ {Self,[{long_gc,MinT}]} = erlang:system_monitor(),
+ {Self,[{long_gc,MinT}]} =
+ erlang:system_monitor({Self,[{large_heap,0}]}),
+ MinN = case erlang:system_monitor() of
+ {Self,[{large_heap,N}]} when is_integer(N), N > 0 -> N;
+ Other2 -> test_server:fault(Other2)
+ end,
+ {Self,[{large_heap,MinN}]} = erlang:system_monitor(),
+ {Self,[{large_heap,MinN}]} =
+ erlang:system_monitor(Self, [busy_port]),
+ {Self,[busy_port]} = erlang:system_monitor(),
+ {Self,[busy_port]} =
+ erlang:system_monitor({Self,[busy_dist_port]}),
+ {Self,[busy_dist_port]} = erlang:system_monitor(),
+ All = lists:sort([busy_port,busy_dist_port,
+ {long_gc,1},{large_heap,65535}]),
+ {Self,[busy_dist_port]} = erlang:system_monitor(Self, All),
+ {Self,A1} = erlang:system_monitor(),
+ All = lists:sort(A1),
+ {Self,A1} = erlang:system_monitor(Self, []),
+ Pid = spawn(fun () -> receive {Self,die} -> exit(die) end end),
+ Mref = erlang:monitor(process, Pid),
+ undefined = erlang:system_monitor(Pid, All),
+ {Pid,A2} = erlang:system_monitor(),
+ All = lists:sort(A2),
+ Pid ! {Self,die},
+ receive {'DOWN',Mref,_,_,_} -> ok end,
+ undefined = erlang:system_monitor(OldMonitor),
+ erlang:yield(),
+ OldMonitor = erlang:system_monitor(),
%%
- ?line {'EXIT',{badarg,_}} = (catch erlang:system_monitor(atom)),
- ?line {'EXIT',{badarg,_}} = (catch erlang:system_monitor({})),
- ?line {'EXIT',{badarg,_}} = (catch erlang:system_monitor({1})),
- ?line {'EXIT',{badarg,_}} = (catch erlang:system_monitor({1,2,3})),
- ?line {'EXIT',{badarg,_}} =
- (catch erlang:system_monitor({Self,atom})),
- ?line {'EXIT',{badarg,_}} =
- (catch erlang:system_monitor(atom, atom)),
- ?line {'EXIT',{badarg,_}} =
- (catch erlang:system_monitor({Self,[busy_port|busy_dist_port]})),
- ?line {'EXIT',{badarg,_}} =
- (catch erlang:system_monitor(Self, [{long_gc,-1}])),
- ?line {'EXIT',{badarg,_}} =
- (catch erlang:system_monitor({Self,[{long_gc,atom}]})),
- ?line {'EXIT',{badarg,_}} =
- (catch erlang:system_monitor(Self,[{large_heap,-1}])),
- ?line {'EXIT',{badarg,_}} =
- (catch erlang:system_monitor({Self,[{large_heap,atom}]})),
- %% Done.
- ?line test_server:timetrap_cancel(Dog),
+ {'EXIT',{badarg,_}} = (catch erlang:system_monitor(atom)),
+ {'EXIT',{badarg,_}} = (catch erlang:system_monitor({})),
+ {'EXIT',{badarg,_}} = (catch erlang:system_monitor({1})),
+ {'EXIT',{badarg,_}} = (catch erlang:system_monitor({1,2,3})),
+ {'EXIT',{badarg,_}} =
+ (catch erlang:system_monitor({Self,atom})),
+ {'EXIT',{badarg,_}} =
+ (catch erlang:system_monitor(atom, atom)),
+ {'EXIT',{badarg,_}} =
+ (catch erlang:system_monitor({Self,[busy_port|busy_dist_port]})),
+ {'EXIT',{badarg,_}} =
+ (catch erlang:system_monitor(Self, [{long_gc,-1}])),
+ {'EXIT',{badarg,_}} =
+ (catch erlang:system_monitor({Self,[{long_gc,atom}]})),
+ {'EXIT',{badarg,_}} =
+ (catch erlang:system_monitor(Self,[{large_heap,-1}])),
+ {'EXIT',{badarg,_}} =
+ (catch erlang:system_monitor({Self,[{large_heap,atom}]})),
ok.
-more_system_monitor_args(doc) ->
- ["Tests arguments to erlang:system_monitor/0-2)"];
+%% Tests arguments to erlang:system_monitor/0,1,2
more_system_monitor_args(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
-
- ?line try_l(64000),
- ?line try_l(16#7ffffff),
- ?line try_l(16#3fffffff),
- ?line try_l(16#7fffffff),
- ?line try_l(16#ffffffff),
-
- %% Done.
- ?line test_server:timetrap_cancel(Dog),
+ try_l(64000),
+ try_l(16#7ffffff),
+ try_l(16#3fffffff),
+ try_l(16#7fffffff),
+ try_l(16#ffffffff),
ok.
try_l(Val) ->
@@ -500,29 +853,29 @@ try_l(Val) ->
Arbitrary1 = 77777,
Arbitrary2 = 88888,
- ?line erlang:system_monitor(undefined),
+ erlang:system_monitor(undefined),
- ?line undefined = erlang:system_monitor(Self, [{long_gc,Val},{large_heap,Arbitrary1}]),
+ undefined = erlang:system_monitor(Self, [{long_gc,Val},{large_heap,Arbitrary1}]),
- ?line {Self,Comb0} = erlang:system_monitor(Self, [{long_gc,Arbitrary2},{large_heap,Val}]),
- ?line [{large_heap,Arbitrary1},{long_gc,Val}] = lists:sort(Comb0),
+ {Self,Comb0} = erlang:system_monitor(Self, [{long_gc,Arbitrary2},{large_heap,Val}]),
+ [{large_heap,Arbitrary1},{long_gc,Val}] = lists:sort(Comb0),
- ?line {Self,Comb1} = erlang:system_monitor(undefined),
- ?line [{large_heap,Val},{long_gc,Arbitrary2}] = lists:sort(Comb1).
+ {Self,Comb1} = erlang:system_monitor(undefined),
+ [{large_heap,Val},{long_gc,Arbitrary2}] = lists:sort(Comb1).
monitor_sys(Parent) ->
receive
- {monitor,Pid,long_schedule,Data} when is_pid(Pid) ->
- io:format("Long schedule of ~w: ~w~n",[Pid,Data]),
- Parent ! {Pid,Data},
- monitor_sys(Parent);
- {monitor,Port,long_schedule,Data} when is_port(Port) ->
- {name,Name} = erlang:port_info(Port,name),
- io:format("Long schedule of ~w (~p): ~w~n",[Port,Name,Data]),
- Parent ! {Port,Data},
- monitor_sys(Parent);
- Other ->
- erlang:display(Other)
+ {monitor,Pid,long_schedule,Data} when is_pid(Pid) ->
+ io:format("Long schedule of ~w: ~w~n",[Pid,Data]),
+ Parent ! {Pid,Data},
+ monitor_sys(Parent);
+ {monitor,Port,long_schedule,Data} when is_port(Port) ->
+ {name,Name} = erlang:port_info(Port,name),
+ io:format("Long schedule of ~w (~p): ~w~n",[Port,Name,Data]),
+ Parent ! {Port,Data},
+ monitor_sys(Parent);
+ Other ->
+ erlang:display(Other)
end.
start_monitor() ->
@@ -532,18 +885,15 @@ start_monitor() ->
erlang:yield(), % Need to be rescheduled for the trace to take
ok.
-system_monitor_long_schedule(suite) ->
- [];
-system_monitor_long_schedule(doc) ->
- ["Tests erlang:system_monitor(Pid, [{long_schedule,Time}])"];
+%% Tests erlang:system_monitor(Pid, [{long_schedule,Time}])
system_monitor_long_schedule(Config) when is_list(Config) ->
- Path = ?config(data_dir, Config),
+ Path = proplists:get_value(data_dir, Config),
erl_ddll:start(),
case (catch load_driver(Path, slow_drv)) of
- ok ->
- do_system_monitor_long_schedule();
- _Error ->
- {skip, "Unable to load slow_drv (windows or no usleep()?)"}
+ ok ->
+ do_system_monitor_long_schedule();
+ _Error ->
+ {skip, "Unable to load slow_drv (windows or no usleep()?)"}
end.
do_system_monitor_long_schedule() ->
start_monitor(),
@@ -551,18 +901,18 @@ do_system_monitor_long_schedule() ->
"ok" = erlang:port_control(Port,0,[]),
Self = self(),
receive
- {Self,L} when is_list(L) ->
- ok
+ {Self,L} when is_list(L) ->
+ ok
after 1000 ->
- ?t:fail(no_trace_of_pid)
+ ct:fail(no_trace_of_pid)
end,
"ok" = erlang:port_control(Port,1,[]),
"ok" = erlang:port_control(Port,2,[]),
receive
- {Port,LL} when is_list(LL) ->
- ok
+ {Port,LL} when is_list(LL) ->
+ ok
after 1000 ->
- ?t:fail(no_trace_of_port)
+ ct:fail(no_trace_of_port)
end,
port_close(Port),
erlang:system_monitor(undefined),
@@ -571,214 +921,200 @@ do_system_monitor_long_schedule() ->
-define(LONG_GC_SLEEP, 670).
-system_monitor_long_gc_1(suite) ->
- [];
-system_monitor_long_gc_1(doc) ->
- ["Tests erlang:system_monitor(Pid, [{long_gc,Time}])"];
+%% Tests erlang:system_monitor(Pid, [{long_gc,Time}])
system_monitor_long_gc_1(Config) when is_list(Config) ->
erts_debug:set_internal_state(available_internal_state, true),
try
- case erts_debug:get_internal_state(force_heap_frags) of
- true ->
- {skip,"emulator with FORCE_HEAP_FRAGS defined"};
- false ->
- %% Add ?LONG_GC_SLEEP ms to all gc
- ?line erts_debug:set_internal_state(test_long_gc_sleep,
- ?LONG_GC_SLEEP),
- ?line LoadFun = fun () ->
- garbage_collect(),
- self()
- end,
- ?line long_gc(LoadFun, false)
- end
+ case erts_debug:get_internal_state(force_heap_frags) of
+ true ->
+ {skip,"emulator with FORCE_HEAP_FRAGS defined"};
+ false ->
+ %% Add ?LONG_GC_SLEEP ms to all gc
+ erts_debug:set_internal_state(test_long_gc_sleep,
+ ?LONG_GC_SLEEP),
+ LoadFun = fun () ->
+ garbage_collect(),
+ self()
+ end,
+ long_gc(LoadFun, false)
+ end
after
- erts_debug:set_internal_state(test_long_gc_sleep, 0),
- erts_debug:set_internal_state(available_internal_state, false)
+ erts_debug:set_internal_state(test_long_gc_sleep, 0),
+ erts_debug:set_internal_state(available_internal_state, false)
end.
-system_monitor_long_gc_2(suite) ->
- [];
-system_monitor_long_gc_2(doc) ->
- ["Tests erlang:system_monitor(Pid, [{long_gc,Time}])"];
+%% Tests erlang:system_monitor(Pid, [{long_gc,Time}])
system_monitor_long_gc_2(Config) when is_list(Config) ->
erts_debug:set_internal_state(available_internal_state, true),
try
- case erts_debug:get_internal_state(force_heap_frags) of
- true ->
- {skip,"emulator with FORCE_HEAP_FRAGS defined"};
- false ->
- %% Add ?LONG_GC_SLEEP ms to all gc
- ?line erts_debug:set_internal_state(test_long_gc_sleep,
- ?LONG_GC_SLEEP),
- ?line Parent = self(),
- ?line LoadFun =
- fun () ->
- Ref = make_ref(),
- Pid =
- spawn_link(
- fun () ->
- garbage_collect(),
- Parent ! {Ref, self()}
- end),
- receive {Ref, Pid} -> Pid end
- end,
- ?line long_gc(LoadFun, true),
- ?line long_gc(LoadFun, true),
- ?line long_gc(LoadFun, true)
- end
+ case erts_debug:get_internal_state(force_heap_frags) of
+ true ->
+ {skip,"emulator with FORCE_HEAP_FRAGS defined"};
+ false ->
+ %% Add ?LONG_GC_SLEEP ms to all gc
+ erts_debug:set_internal_state(test_long_gc_sleep,
+ ?LONG_GC_SLEEP),
+ Parent = self(),
+ LoadFun =
+ fun () ->
+ Ref = make_ref(),
+ Pid =
+ spawn_link(
+ fun () ->
+ garbage_collect(),
+ Parent ! {Ref, self()}
+ end),
+ receive {Ref, Pid} -> Pid end
+ end,
+ long_gc(LoadFun, true),
+ long_gc(LoadFun, true),
+ long_gc(LoadFun, true)
+ end
after
- erts_debug:set_internal_state(test_long_gc_sleep, 0),
- erts_debug:set_internal_state(available_internal_state, false)
+ erts_debug:set_internal_state(test_long_gc_sleep, 0),
+ erts_debug:set_internal_state(available_internal_state, false)
end.
long_gc(LoadFun, ExpectMonMsg) ->
- ?line Self = self(),
- ?line Time = 1,
- ?line OldMonitor = erlang:system_monitor(Self, [{long_gc,Time}]),
- ?line Pid = LoadFun(),
- ?line Ref = erlang:trace_delivered(Pid),
- ?line receive {trace_delivered, Pid, Ref} -> ok end,
- ?line {Self,[{long_gc,Time}]} = erlang:system_monitor(OldMonitor),
- ?line case {long_gc_check(Pid, Time, undefined), ExpectMonMsg} of
- {ok, true} when Pid =/= Self ->
- ok;
- {ok, false} ->
- ?line ?t:fail(unexpected_system_monitor_message_received);
- {undefined, false} ->
- ok;
- {undefined, true} ->
- ?line ?t:fail(no_system_monitor_message_received)
- end.
+ Self = self(),
+ Time = 1,
+ OldMonitor = erlang:system_monitor(Self, [{long_gc,Time}]),
+ Pid = LoadFun(),
+ Ref = erlang:trace_delivered(Pid),
+ receive {trace_delivered, Pid, Ref} -> ok end,
+ {Self,[{long_gc,Time}]} = erlang:system_monitor(OldMonitor),
+ case {long_gc_check(Pid, Time, undefined), ExpectMonMsg} of
+ {ok, true} when Pid =/= Self ->
+ ok;
+ {ok, false} ->
+ ct:fail(unexpected_system_monitor_message_received);
+ {undefined, false} ->
+ ok;
+ {undefined, true} ->
+ ct:fail(no_system_monitor_message_received)
+ end.
long_gc_check(Pid, Time, Result) ->
receive
- {monitor,Pid,long_gc,L} = Monitor ->
- case lists:foldl(
- fun (_, error) ->
- error;
- ({timeout,T}, N) when is_integer(T),
- Time =< T, T =< 10*?LONG_GC_SLEEP ->
- %% OTP-7622. The time T must be within reasonable limits
- %% for the test to pass.
- N-1;
- ({heap_size,_}, N) ->
- N-1;
- ({old_heap_size,_}, N) ->
- N-1;
- ({stack_size,_}, N) ->
- N-1;
- ({mbuf_size,_}, N) ->
- N-1;
- ({heap_block_size,_}, N) ->
- N-1;
- ({old_heap_block_size,_}, N) ->
- N-1;
- (_, _) ->
- error
- end, 7, L) of
- 0 ->
- long_gc_check(Pid, Time, ok);
- error ->
- {error,Monitor}
- end;
- {monitor,_,long_gc,_} ->
- long_gc_check(Pid, Time, Result);
- Other ->
- {error,Other}
+ {monitor,Pid,long_gc,L} = Monitor ->
+ case lists:foldl(
+ fun (_, error) ->
+ error;
+ ({timeout,T}, N) when is_integer(T),
+ Time =< T, T =< 10*?LONG_GC_SLEEP ->
+ %% OTP-7622. The time T must be within reasonable limits
+ %% for the test to pass.
+ N-1;
+ ({heap_size,_}, N) ->
+ N-1;
+ ({old_heap_size,_}, N) ->
+ N-1;
+ ({stack_size,_}, N) ->
+ N-1;
+ ({mbuf_size,_}, N) ->
+ N-1;
+ ({heap_block_size,_}, N) ->
+ N-1;
+ ({old_heap_block_size,_}, N) ->
+ N-1;
+ (_, _) ->
+ error
+ end, 7, L) of
+ 0 ->
+ long_gc_check(Pid, Time, ok);
+ error ->
+ {error,Monitor}
+ end;
+ {monitor,_,long_gc,_} ->
+ long_gc_check(Pid, Time, Result);
+ Other ->
+ {error,Other}
after 0 ->
- Result
+ Result
end.
-system_monitor_large_heap_1(suite) ->
- [];
-system_monitor_large_heap_1(doc) ->
- ["Tests erlang:system_monitor(Pid, [{large_heap,Size}])"];
+%% Tests erlang:system_monitor(Pid, [{large_heap,Size}])
system_monitor_large_heap_1(Config) when is_list(Config) ->
- ?line LoadFun =
- fun (Size) ->
- List = seq(1,2*Size),
- garbage_collect(),
- true = lists:prefix([1], List),
- self()
- end,
- ?line large_heap(LoadFun, false).
-
-system_monitor_large_heap_2(suite) ->
- [];
-system_monitor_large_heap_2(doc) ->
- ["Tests erlang:system_monitor(Pid, [{large_heap,Size}])"];
+ LoadFun =
+ fun (Size) ->
+ List = seq(1,2*Size),
+ garbage_collect(),
+ true = lists:prefix([1], List),
+ self()
+ end,
+ large_heap(LoadFun, false).
+
+%% Tests erlang:system_monitor(Pid, [{large_heap,Size}])
system_monitor_large_heap_2(Config) when is_list(Config) ->
- ?line Parent = self(),
- ?line LoadFun =
- fun (Size) ->
- Ref = make_ref(),
- Pid =
- spawn_opt(fun () ->
- garbage_collect(),
- Parent ! {Ref, self()}
- end,
- [link, {min_heap_size, 2*Size}]),
- receive {Ref, Pid} -> Pid end
- end,
- ?line large_heap(LoadFun, true).
+ Parent = self(),
+ LoadFun =
+ fun (Size) ->
+ Ref = make_ref(),
+ Pid =
+ spawn_opt(fun () ->
+ garbage_collect(),
+ Parent ! {Ref, self()}
+ end,
+ [link, {min_heap_size, 2*Size}]),
+ receive {Ref, Pid} -> Pid end
+ end,
+ large_heap(LoadFun, true).
large_heap(LoadFun, ExpectMonMsg) ->
- ?line Dog = test_server:timetrap(test_server:seconds(20)),
- %%
- ?line Size = 65535,
- ?line Self = self(),
- ?line NewMonitor = {Self,[{large_heap,Size}]},
- ?line OldMonitor = erlang:system_monitor(NewMonitor),
- ?line Pid = LoadFun(Size),
- ?line Ref = erlang:trace_delivered(Pid),
- ?line receive {trace_delivered, Pid, Ref} -> ok end,
- ?line {Self,[{large_heap,Size}]} = erlang:system_monitor(OldMonitor),
- ?line case {large_heap_check(Pid, Size, undefined), ExpectMonMsg} of
- {ok, true} when Pid =/= Self ->
- ?line ok;
- {ok, false} ->
- ?line ?t:fail(unexpected_system_monitor_message_received);
- {undefined, false} ->
- ?line ok;
- {undefined, true} ->
- ?line ?t:fail(no_system_monitor_message_received)
- end,
+ ct:timetrap({seconds, 20}),
%%
- ?line test_server:timetrap_cancel(Dog),
+ Size = 65535,
+ Self = self(),
+ NewMonitor = {Self,[{large_heap,Size}]},
+ OldMonitor = erlang:system_monitor(NewMonitor),
+ Pid = LoadFun(Size),
+ Ref = erlang:trace_delivered(Pid),
+ receive {trace_delivered, Pid, Ref} -> ok end,
+ {Self,[{large_heap,Size}]} = erlang:system_monitor(OldMonitor),
+ case {large_heap_check(Pid, Size, undefined), ExpectMonMsg} of
+ {ok, true} when Pid =/= Self ->
+ ok;
+ {ok, false} ->
+ ct:fail(unexpected_system_monitor_message_received);
+ {undefined, false} ->
+ ok;
+ {undefined, true} ->
+ ct:fail(no_system_monitor_message_received)
+ end,
ok.
large_heap_check(Pid, Size, Result) ->
receive
- {monitor,Pid,large_heap,L} = Monitor ->
- case lists:foldl(
- fun (_, error) ->
- error;
- ({heap_size,_}, N) ->
- N-1;
- ({old_heap_size,_}, N) ->
- N-1;
- ({stack_size,_}, N) ->
- N-1;
- ({mbuf_size,_}, N) ->
- N-1;
- ({heap_block_size,_}, N) ->
- N-1;
- ({old_heap_block_size,_}, N) ->
- N-1;
- (_, _) ->
- error
- end, 6, L) of
- 0 ->
- large_heap_check(Pid, Size, ok);
- error ->
- {error,Monitor}
- end;
- {monitor,_,large_heap,_} ->
- large_heap_check(Pid, Size, Result);
- Other ->
- {error,Other}
+ {monitor,Pid,large_heap,L} = Monitor ->
+ case lists:foldl(
+ fun (_, error) ->
+ error;
+ ({heap_size,_}, N) ->
+ N-1;
+ ({old_heap_size,_}, N) ->
+ N-1;
+ ({stack_size,_}, N) ->
+ N-1;
+ ({mbuf_size,_}, N) ->
+ N-1;
+ ({heap_block_size,_}, N) ->
+ N-1;
+ ({old_heap_block_size,_}, N) ->
+ N-1;
+ (_, _) ->
+ error
+ end, 6, L) of
+ 0 ->
+ large_heap_check(Pid, Size, ok);
+ error ->
+ {error,Monitor}
+ end;
+ {monitor,_,large_heap,_} ->
+ large_heap_check(Pid, Size, Result);
+ Other ->
+ {error,Other}
after 0 ->
- Result
+ Result
end.
seq(N, M) ->
@@ -793,11 +1129,11 @@ seq(N, M, R) ->
is_send_traced(Pid, Listener, Msg) ->
Pid ! {send_please, Listener, Msg},
receive
- Any ->
- {trace, Pid, send, Msg, Listener} = Any,
- true
+ Any ->
+ {trace, Pid, send, Msg, Listener} = Any,
+ true
after 1000 ->
- false
+ false
end.
%% This procedure assumes that the Parent process is send traced.
@@ -811,146 +1147,131 @@ spawn_children(Parent, Number, Result) ->
Self = self(),
Parent ! {spawn_please, Self, fun process/0},
Child =
- receive
- {trace, Parent, send, {spawned, Pid}, Self} -> Pid
- end,
receive
- {spawned, Child} ->
- spawn_children(Parent, Number-1, [Child|Result])
+ {trace, Parent, send, {spawned, Pid}, Self} -> Pid
+ end,
+ receive
+ {spawned, Child} ->
+ spawn_children(Parent, Number-1, [Child|Result])
end.
-suspend(doc) -> "Test erlang:suspend/1 and erlang:resume/1.";
+%% Test erlang:suspend/1 and erlang:resume/1.
suspend(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:minutes(2)),
-
- ?line Worker = fun_spawn(fun worker/0),
+ ct:timetrap({minutes,2}),
+ Worker = fun_spawn(fun worker/0),
%% Suspend a process and test that it is suspended.
- ?line ok = do_suspend(Worker, 10000),
-
- %% Done.
- ?line test_server:timetrap_cancel(Dog),
+ ok = do_suspend(Worker, 10000),
ok.
do_suspend(_Pid, 0) ->
- ?line ok;
+ ok;
do_suspend(Pid, N) ->
%% Suspend a process and test that it is suspended.
- ?line true = erlang:suspend_process(Pid),
- ?line {status, suspended} = process_info(Pid, status),
+ true = erlang:suspend_process(Pid),
+ {status, suspended} = process_info(Pid, status),
%% Unsuspend the process and make sure it starts working.
- ?line true = erlang:resume_process(Pid),
- ?line case process_info(Pid, status) of
- {status, runnable} -> ?line ok;
- {status, running} -> ?line ok;
- {status, garbage_collecting} -> ?line ok;
- ST -> ?line ?t:fail(ST)
- end,
- ?line erlang:yield(),
- ?line do_suspend(Pid, N-1).
-
-
-
-mutual_suspend(doc) ->
- [];
-mutual_suspend(suite) ->
- [];
+ true = erlang:resume_process(Pid),
+ case process_info(Pid, status) of
+ {status, runnable} -> ok;
+ {status, running} -> ok;
+ {status, garbage_collecting} -> ok;
+ ST -> ct:fail(ST)
+ end,
+ erlang:yield(),
+ do_suspend(Pid, N-1).
+
+
+
mutual_suspend(Config) when is_list(Config) ->
- ?line TimeoutSecs = 5*60,
- ?line Dog = test_server:timetrap(test_server:minutes(TimeoutSecs)),
- ?line Parent = self(),
- ?line Fun = fun () ->
- receive
- {go, Pid} ->
- do_mutual_suspend(Pid, 100000)
- end,
- Parent ! {done, self()},
- receive after infinity -> ok end
- end,
- ?line P1 = spawn_link(Fun),
- ?line P2 = spawn_link(Fun),
- ?line T1 = erlang:start_timer((TimeoutSecs - 5)*1000, self(), oops),
- ?line T2 = erlang:start_timer((TimeoutSecs - 5)*1000, self(), oops),
- ?line P1 ! {go, P2},
- ?line P2 ! {go, P1},
- ?line Res1 = receive
- {done, P1} -> done;
- {timeout,T1,_} -> timeout
- end,
- ?line Res2 = receive
- {done, P2} -> done;
- {timeout,T2,_} -> timeout
- end,
- ?line P1S = process_info(P1, status),
- ?line P2S = process_info(P2, status),
- ?line ?t:format("P1S=~p P2S=~p", [P1S, P2S]),
- ?line false = {status, suspended} == P1S,
- ?line false = {status, suspended} == P2S,
- ?line unlink(P1), exit(P1, bang),
- ?line unlink(P2), exit(P2, bang),
- ?line done = Res1,
- ?line done = Res2,
- %% Done.
- ?line test_server:timetrap_cancel(Dog),
- ?line ok.
-
+ TimeoutSecs = 5*60,
+ ct:timetrap({seconds, TimeoutSecs}),
+ Parent = self(),
+ Fun = fun () ->
+ receive
+ {go, Pid} ->
+ do_mutual_suspend(Pid, 100000)
+ end,
+ Parent ! {done, self()},
+ receive after infinity -> ok end
+ end,
+ P1 = spawn_link(Fun),
+ P2 = spawn_link(Fun),
+ T1 = erlang:start_timer((TimeoutSecs - 5)*1000, self(), oops),
+ T2 = erlang:start_timer((TimeoutSecs - 5)*1000, self(), oops),
+ P1 ! {go, P2},
+ P2 ! {go, P1},
+ Res1 = receive
+ {done, P1} -> done;
+ {timeout,T1,_} -> timeout
+ end,
+ Res2 = receive
+ {done, P2} -> done;
+ {timeout,T2,_} -> timeout
+ end,
+ P1S = process_info(P1, status),
+ P2S = process_info(P2, status),
+ io:format("P1S=~p P2S=~p", [P1S, P2S]),
+ false = {status, suspended} == P1S,
+ false = {status, suspended} == P2S,
+ unlink(P1), exit(P1, bang),
+ unlink(P2), exit(P2, bang),
+ done = Res1,
+ done = Res2,
+ ok.
+
do_mutual_suspend(_Pid, 0) ->
- ?line ok;
+ ok;
do_mutual_suspend(Pid, N) ->
%% Suspend a process and test that it is suspended.
- ?line true = erlang:suspend_process(Pid),
- ?line {status, suspended} = process_info(Pid, status),
+ true = erlang:suspend_process(Pid),
+ {status, suspended} = process_info(Pid, status),
%% Unsuspend the process.
- ?line true = erlang:resume_process(Pid),
- ?line do_mutual_suspend(Pid, N-1).
+ true = erlang:resume_process(Pid),
+ do_mutual_suspend(Pid, N-1).
-suspend_exit(doc) ->
- [];
-suspend_exit(suite) ->
- [];
suspend_exit(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:minutes(2)),
- ?line random:seed(4711,17,4711),
- ?line do_suspend_exit(5000),
- ?line test_server:timetrap_cancel(Dog),
- ?line ok.
+ ct:timetrap({minutes, 2}),
+ rand:seed(exsplus, {4711,17,4711}),
+ do_suspend_exit(5000),
+ ok.
do_suspend_exit(0) ->
- ?line ok;
+ ok;
do_suspend_exit(N) ->
- ?line Work = random:uniform(50),
- ?line Parent = self(),
- ?line {Suspendee, Mon2}
- = spawn_monitor(fun () ->
- suspend_exit_work(Work),
- exit(normal)
- end),
- ?line {Suspender, Mon1}
- = spawn_monitor(
- fun () ->
- suspend_exit_work(Work div 2),
- Parent ! {doing_suspend, self()},
- case catch erlang:suspend_process(Suspendee) of
- {'EXIT', _} ->
- ok;
- true ->
- ?line erlang:resume_process(Suspendee)
- end
- end),
- ?line receive
- {doing_suspend, Suspender} ->
- case N rem 2 of
- 0 -> exit(Suspender, bang);
- 1 -> ok
- end
- end,
- ?line receive {'DOWN', Mon1, process, Suspender, _} -> ok end,
- ?line receive {'DOWN', Mon2, process, Suspendee, _} -> ok end,
- ?line do_suspend_exit(N-1).
-
-
-
-
+ Work = rand:uniform(50),
+ Parent = self(),
+ {Suspendee, Mon2}
+ = spawn_monitor(fun () ->
+ suspend_exit_work(Work),
+ exit(normal)
+ end),
+ {Suspender, Mon1}
+ = spawn_monitor(
+ fun () ->
+ suspend_exit_work(Work div 2),
+ Parent ! {doing_suspend, self()},
+ case catch erlang:suspend_process(Suspendee) of
+ {'EXIT', _} ->
+ ok;
+ true ->
+ erlang:resume_process(Suspendee)
+ end
+ end),
+ receive
+ {doing_suspend, Suspender} ->
+ case N rem 2 of
+ 0 -> exit(Suspender, bang);
+ 1 -> ok
+ end
+ end,
+ receive {'DOWN', Mon1, process, Suspender, _} -> ok end,
+ receive {'DOWN', Mon2, process, Suspendee, _} -> ok end,
+ do_suspend_exit(N-1).
+
+
+
+
suspend_exit_work(0) ->
ok;
suspend_exit_work(N) ->
@@ -962,320 +1283,305 @@ suspend_exit_work(N) ->
chk_suspended(P, Bool, Line) ->
{Bool, Line} = {({status, suspended} == process_info(P, status)), Line}.
-suspender_exit(doc) ->
- [];
-suspender_exit(suite) ->
- [];
suspender_exit(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:minutes(3)),
- ?line P1 = spawn_link(fun () -> receive after infinity -> ok end end),
- ?line {'EXIT', _} = (catch erlang:resume_process(P1)),
- ?line {P2, M2} = spawn_monitor(
- fun () ->
- ?CHK_SUSPENDED(P1, false),
- erlang:suspend_process(P1),
- ?CHK_SUSPENDED(P1, true),
- erlang:suspend_process(P1),
- erlang:suspend_process(P1),
- erlang:suspend_process(P1),
- ?CHK_SUSPENDED(P1, true),
- erlang:resume_process(P1),
- erlang:resume_process(P1),
- erlang:resume_process(P1),
- ?CHK_SUSPENDED(P1, true),
- erlang:resume_process(P1),
- ?CHK_SUSPENDED(P1, false),
- erlang:suspend_process(P1),
- erlang:suspend_process(P1),
- erlang:suspend_process(P1),
- ?CHK_SUSPENDED(P1, true),
- exit(bang)
- end),
- ?line receive
- {'DOWN', M2,process,P2,R2} ->
- ?line bang = R2,
- ?line ?CHK_SUSPENDED(P1, false)
- end,
- ?line Parent = self(),
- ?line {P3, M3} = spawn_monitor(
- fun () ->
- erlang:suspend_process(P1),
- ?CHK_SUSPENDED(P1, true),
- Parent ! self(),
- receive after infinity -> ok end
- end),
- ?line {P4, M4} = spawn_monitor(
- fun () ->
- erlang:suspend_process(P1),
- ?CHK_SUSPENDED(P1, true),
- Parent ! self(),
- receive after infinity -> ok end
- end),
- ?line {P5, M5} = spawn_monitor(
- fun () ->
- erlang:suspend_process(P1),
- ?CHK_SUSPENDED(P1, true),
- Parent ! self(),
- receive after infinity -> ok end
- end),
- ?line {P6, M6} = spawn_monitor(
- fun () ->
- erlang:suspend_process(P1),
- ?CHK_SUSPENDED(P1, true),
- Parent ! self(),
- receive after infinity -> ok end
- end),
- ?line {P7, M7} = spawn_monitor(
- fun () ->
- erlang:suspend_process(P1),
- ?CHK_SUSPENDED(P1, true),
- Parent ! self(),
- receive after infinity -> ok end
- end),
- ?line receive P3 -> ok end,
- ?line receive P4 -> ok end,
- ?line receive P5 -> ok end,
- ?line receive P6 -> ok end,
- ?line receive P7 -> ok end,
- ?line ?CHK_SUSPENDED(P1, true),
- ?line exit(P3, bang),
- ?line receive
- {'DOWN',M3,process,P3,R3} ->
- ?line bang = R3,
- ?line ?CHK_SUSPENDED(P1, true)
- end,
- ?line exit(P4, bang),
- ?line receive
- {'DOWN',M4,process,P4,R4} ->
- ?line bang = R4,
- ?line ?CHK_SUSPENDED(P1, true)
- end,
- ?line exit(P5, bang),
- ?line receive
- {'DOWN',M5,process,P5,R5} ->
- ?line bang = R5,
- ?line ?CHK_SUSPENDED(P1, true)
- end,
- ?line exit(P6, bang),
- ?line receive
- {'DOWN',M6,process,P6,R6} ->
- ?line bang = R6,
- ?line ?CHK_SUSPENDED(P1, true)
- end,
- ?line exit(P7, bang),
- ?line receive
- {'DOWN',M7,process,P7,R7} ->
- ?line bang = R7,
- ?line ?CHK_SUSPENDED(P1, false)
- end,
- ?line unlink(P1),
- ?line exit(P1, bong),
- ?line test_server:timetrap_cancel(Dog),
- ?line ok.
-
-suspend_system_limit(doc) ->
- [];
-suspend_system_limit(suite) ->
- [];
+ ct:timetrap({minutes, 3}),
+ P1 = spawn_link(fun () -> receive after infinity -> ok end end),
+ {'EXIT', _} = (catch erlang:resume_process(P1)),
+ {P2, M2} = spawn_monitor(
+ fun () ->
+ ?CHK_SUSPENDED(P1, false),
+ erlang:suspend_process(P1),
+ ?CHK_SUSPENDED(P1, true),
+ erlang:suspend_process(P1),
+ erlang:suspend_process(P1),
+ erlang:suspend_process(P1),
+ ?CHK_SUSPENDED(P1, true),
+ erlang:resume_process(P1),
+ erlang:resume_process(P1),
+ erlang:resume_process(P1),
+ ?CHK_SUSPENDED(P1, true),
+ erlang:resume_process(P1),
+ ?CHK_SUSPENDED(P1, false),
+ erlang:suspend_process(P1),
+ erlang:suspend_process(P1),
+ erlang:suspend_process(P1),
+ ?CHK_SUSPENDED(P1, true),
+ exit(bang)
+ end),
+ receive
+ {'DOWN', M2,process,P2,R2} ->
+ bang = R2,
+ ?CHK_SUSPENDED(P1, false)
+ end,
+ Parent = self(),
+ {P3, M3} = spawn_monitor(
+ fun () ->
+ erlang:suspend_process(P1),
+ ?CHK_SUSPENDED(P1, true),
+ Parent ! self(),
+ receive after infinity -> ok end
+ end),
+ {P4, M4} = spawn_monitor(
+ fun () ->
+ erlang:suspend_process(P1),
+ ?CHK_SUSPENDED(P1, true),
+ Parent ! self(),
+ receive after infinity -> ok end
+ end),
+ {P5, M5} = spawn_monitor(
+ fun () ->
+ erlang:suspend_process(P1),
+ ?CHK_SUSPENDED(P1, true),
+ Parent ! self(),
+ receive after infinity -> ok end
+ end),
+ {P6, M6} = spawn_monitor(
+ fun () ->
+ erlang:suspend_process(P1),
+ ?CHK_SUSPENDED(P1, true),
+ Parent ! self(),
+ receive after infinity -> ok end
+ end),
+ {P7, M7} = spawn_monitor(
+ fun () ->
+ erlang:suspend_process(P1),
+ ?CHK_SUSPENDED(P1, true),
+ Parent ! self(),
+ receive after infinity -> ok end
+ end),
+ receive P3 -> ok end,
+ receive P4 -> ok end,
+ receive P5 -> ok end,
+ receive P6 -> ok end,
+ receive P7 -> ok end,
+ ?CHK_SUSPENDED(P1, true),
+ exit(P3, bang),
+ receive
+ {'DOWN',M3,process,P3,R3} ->
+ bang = R3,
+ ?CHK_SUSPENDED(P1, true)
+ end,
+ exit(P4, bang),
+ receive
+ {'DOWN',M4,process,P4,R4} ->
+ bang = R4,
+ ?CHK_SUSPENDED(P1, true)
+ end,
+ exit(P5, bang),
+ receive
+ {'DOWN',M5,process,P5,R5} ->
+ bang = R5,
+ ?CHK_SUSPENDED(P1, true)
+ end,
+ exit(P6, bang),
+ receive
+ {'DOWN',M6,process,P6,R6} ->
+ bang = R6,
+ ?CHK_SUSPENDED(P1, true)
+ end,
+ exit(P7, bang),
+ receive
+ {'DOWN',M7,process,P7,R7} ->
+ bang = R7,
+ ?CHK_SUSPENDED(P1, false)
+ end,
+ unlink(P1),
+ exit(P1, bong),
+ ok.
+
suspend_system_limit(Config) when is_list(Config) ->
case os:getenv("ERL_EXTREME_TESTING") of
- "true" ->
- ?line Dog = test_server:timetrap(test_server:minutes(3*60)),
- ?line P = spawn_link(fun () -> receive after infinity -> ok end end),
- ?line suspend_until_system_limit(P),
- ?line unlink(P),
- ?line exit(P, bye),
- ?line test_server:timetrap_cancel(Dog),
- ?line ok;
- _ ->
- {skip, "Takes too long time for normal testing"}
+ "true" ->
+ ct:timetrap({minutes, 3*60}),
+ P = spawn_link(fun () -> receive after infinity -> ok end end),
+ suspend_until_system_limit(P),
+ unlink(P),
+ exit(P, bye),
+ ok;
+ _ ->
+ {skip, "Takes too long time for normal testing"}
end.
suspend_until_system_limit(P) ->
- ?line suspend_until_system_limit(P, 0, 0).
+ suspend_until_system_limit(P, 0, 0).
suspend_until_system_limit(P, N, M) ->
NewM = case M of
- 1 ->
- ?line ?CHK_SUSPENDED(P, true), 2;
- 1000000 ->
- erlang:display(N), 1;
- _ ->
- M+1
- end,
- ?line case catch erlang:suspend_process(P) of
- true ->
- suspend_until_system_limit(P, N+1, NewM);
- {'EXIT', R} when R == system_limit;
- element(1, R) == system_limit ->
- ?line ?t:format("system limit at ~p~n", [N]),
- ?line resume_from_system_limit(P, N, 0);
- Error ->
- ?line ?t:fail(Error)
- end.
+ 1 ->
+ ?CHK_SUSPENDED(P, true), 2;
+ 1000000 ->
+ erlang:display(N), 1;
+ _ ->
+ M+1
+ end,
+ case catch erlang:suspend_process(P) of
+ true ->
+ suspend_until_system_limit(P, N+1, NewM);
+ {'EXIT', R} when R == system_limit;
+ element(1, R) == system_limit ->
+ io:format("system limit at ~p~n", [N]),
+ resume_from_system_limit(P, N, 0);
+ Error ->
+ ct:fail(Error)
+ end.
resume_from_system_limit(P, 0, _) ->
- ?line ?CHK_SUSPENDED(P, false),
- ?line {'EXIT', _} = (catch erlang:resume_process(P)),
- ?line ok;
+ ?CHK_SUSPENDED(P, false),
+ {'EXIT', _} = (catch erlang:resume_process(P)),
+ ok;
resume_from_system_limit(P, N, M) ->
- ?line NewM = case M of
- 1 ->
- ?line ?CHK_SUSPENDED(P, true), 2;
- 1000000 ->
- erlang:display(N), 1;
- _ ->
- M+1
- end,
- ?line erlang:resume_process(P),
- ?line resume_from_system_limit(P, N-1, NewM).
+ NewM = case M of
+ 1 ->
+ ?CHK_SUSPENDED(P, true), 2;
+ 1000000 ->
+ erlang:display(N), 1;
+ _ ->
+ M+1
+ end,
+ erlang:resume_process(P),
+ resume_from_system_limit(P, N-1, NewM).
-record(susp_info, {async = 0,
- dbl_async = 0,
- synced = 0,
- async_once = 0}).
-
-suspend_opts(doc) ->
- [];
-suspend_opts(suite) ->
- [];
+ dbl_async = 0,
+ synced = 0,
+ async_once = 0}).
+
suspend_opts(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:minutes(3)),
- ?line Self = self(),
- ?line wait_for_empty_runq(10),
- ?line Tok = spawn_link(fun () ->
- Self ! self(),
- tok_trace_loop(Self, 0, 1000000000)
- end),
- ?line TC = 1000,
- ?line receive Tok -> ok end,
- ?line SF = fun (N, #susp_info {async = A,
- dbl_async = AA,
- synced = S,
- async_once = AO} = Acc) ->
- ?line erlang:suspend_process(Tok, [asynchronous]),
- ?line Res = case {suspend_count(Tok), N rem 4} of
- {0, 2} ->
- ?line erlang:suspend_process(Tok,
- [asynchronous]),
- case suspend_count(Tok) of
- 2 ->
- ?line erlang:resume_process(Tok),
- ?line Acc#susp_info{async = A+1};
- 0 ->
- ?line erlang:resume_process(Tok),
- ?line Acc#susp_info{async = A+1,
- dbl_async = AA+1}
- end;
- {0, 1} ->
- ?line erlang:suspend_process(Tok,
- [asynchronous,
- unless_suspending]),
- case suspend_count(Tok) of
- 1 ->
- ?line Acc#susp_info{async = A+1};
- 0 ->
- ?line Acc#susp_info{async = A+1,
- async_once = AO+1}
- end;
- {0, 0} ->
- ?line erlang:suspend_process(Tok,
- [unless_suspending]),
- ?line 1 = suspend_count(Tok),
- ?line Acc#susp_info{async = A+1,
- synced = S+1};
- {0, _} ->
- ?line Acc#susp_info{async = A+1};
- _ ->
- Acc
- end,
- ?line erlang:resume_process(Tok),
- ?line erlang:yield(),
- ?line Res
- end,
- ?line SI = repeat_acc(SF, TC, #susp_info{}),
- ?line erlang:suspend_process(Tok, [asynchronous]),
+ ct:timetrap({minutes, 3}),
+ Self = self(),
+ wait_for_empty_runq(10),
+ Tok = spawn_link(fun () ->
+ Self ! self(),
+ tok_trace_loop(Self, 0, 1000000000)
+ end),
+ TC = 1000,
+ receive Tok -> ok end,
+ SF = fun (N, #susp_info {async = A,
+ dbl_async = AA,
+ synced = S,
+ async_once = AO} = Acc) ->
+ erlang:suspend_process(Tok, [asynchronous]),
+ Res = case {suspend_count(Tok), N rem 4} of
+ {0, 2} ->
+ erlang:suspend_process(Tok,
+ [asynchronous]),
+ case suspend_count(Tok) of
+ 2 ->
+ erlang:resume_process(Tok),
+ Acc#susp_info{async = A+1};
+ 0 ->
+ erlang:resume_process(Tok),
+ Acc#susp_info{async = A+1,
+ dbl_async = AA+1}
+ end;
+ {0, 1} ->
+ erlang:suspend_process(Tok,
+ [asynchronous,
+ unless_suspending]),
+ case suspend_count(Tok) of
+ 1 ->
+ Acc#susp_info{async = A+1};
+ 0 ->
+ Acc#susp_info{async = A+1,
+ async_once = AO+1}
+ end;
+ {0, 0} ->
+ erlang:suspend_process(Tok,
+ [unless_suspending]),
+ 1 = suspend_count(Tok),
+ Acc#susp_info{async = A+1,
+ synced = S+1};
+ {0, _} ->
+ Acc#susp_info{async = A+1};
+ _ ->
+ Acc
+ end,
+ erlang:resume_process(Tok),
+ erlang:yield(),
+ Res
+ end,
+ SI = repeat_acc(SF, TC, #susp_info{}),
+ erlang:suspend_process(Tok, [asynchronous]),
%% Verify that it eventually suspends
- ?line WaitTime0 = 10,
- ?line WaitTime1 = case {erlang:system_info(debug_compiled),
- erlang:system_info(lock_checking)} of
- {false, false} ->
- WaitTime0;
- {false, true} ->
- WaitTime0*5;
- _ ->
- WaitTime0*10
- end,
- ?line WaitTime = case {erlang:system_info(schedulers_online),
- erlang:system_info(logical_processors)} of
- {Schdlrs, CPUs} when is_integer(CPUs),
- Schdlrs =< CPUs ->
- WaitTime1;
- _ ->
- WaitTime1*10
- end,
- ?line receive after WaitTime -> ok end,
- ?line 1 = suspend_count(Tok),
- ?line erlang:suspend_process(Tok, [asynchronous]),
- ?line 2 = suspend_count(Tok),
- ?line erlang:suspend_process(Tok, [asynchronous]),
- ?line 3 = suspend_count(Tok),
- ?line erlang:suspend_process(Tok),
- ?line 4 = suspend_count(Tok),
- ?line erlang:suspend_process(Tok),
- ?line 5 = suspend_count(Tok),
- ?line erlang:suspend_process(Tok, [unless_suspending]),
- ?line 5 = suspend_count(Tok),
- ?line erlang:suspend_process(Tok, [unless_suspending,
- asynchronous]),
- ?line 5 = suspend_count(Tok),
- ?line erlang:resume_process(Tok),
- ?line erlang:resume_process(Tok),
- ?line erlang:resume_process(Tok),
- ?line erlang:resume_process(Tok),
- ?line 1 = suspend_count(Tok),
- ?line ?t:format("Main suspends: ~p~n"
- "Main async: ~p~n"
- "Double async: ~p~n"
- "Async once: ~p~n"
- "Synced: ~p~n",
- [TC,
- SI#susp_info.async,
- SI#susp_info.dbl_async,
- SI#susp_info.async_once,
- SI#susp_info.synced]),
- ?line case erlang:system_info(schedulers_online) of
- 1 ->
- ?line ok;
- _ ->
- ?line true = SI#susp_info.async =/= 0
- end,
- ?line unlink(Tok),
- ?line exit(Tok, bang),
- ?line test_server:timetrap_cancel(Dog),
- ?line ok.
+ WaitTime0 = 10,
+ WaitTime1 = case {erlang:system_info(debug_compiled),
+ erlang:system_info(lock_checking)} of
+ {false, false} ->
+ WaitTime0;
+ {false, true} ->
+ WaitTime0*5;
+ _ ->
+ WaitTime0*10
+ end,
+ WaitTime = case {erlang:system_info(schedulers_online),
+ erlang:system_info(logical_processors)} of
+ {Schdlrs, CPUs} when is_integer(CPUs),
+ Schdlrs =< CPUs ->
+ WaitTime1;
+ _ ->
+ WaitTime1*10
+ end,
+ receive after WaitTime -> ok end,
+ 1 = suspend_count(Tok),
+ erlang:suspend_process(Tok, [asynchronous]),
+ 2 = suspend_count(Tok),
+ erlang:suspend_process(Tok, [asynchronous]),
+ 3 = suspend_count(Tok),
+ erlang:suspend_process(Tok),
+ 4 = suspend_count(Tok),
+ erlang:suspend_process(Tok),
+ 5 = suspend_count(Tok),
+ erlang:suspend_process(Tok, [unless_suspending]),
+ 5 = suspend_count(Tok),
+ erlang:suspend_process(Tok, [unless_suspending,
+ asynchronous]),
+ 5 = suspend_count(Tok),
+ erlang:resume_process(Tok),
+ erlang:resume_process(Tok),
+ erlang:resume_process(Tok),
+ erlang:resume_process(Tok),
+ 1 = suspend_count(Tok),
+ io:format("Main suspends: ~p~n"
+ "Main async: ~p~n"
+ "Double async: ~p~n"
+ "Async once: ~p~n"
+ "Synced: ~p~n",
+ [TC,
+ SI#susp_info.async,
+ SI#susp_info.dbl_async,
+ SI#susp_info.async_once,
+ SI#susp_info.synced]),
+ case erlang:system_info(schedulers_online) of
+ 1 ->
+ ok;
+ _ ->
+ true = SI#susp_info.async =/= 0
+ end,
+ unlink(Tok),
+ exit(Tok, bang),
+ ok.
suspend_count(Suspendee) ->
suspend_count(self(), Suspendee).
suspend_count(Suspender, Suspendee) ->
{suspending, SList} = process_info(Suspender, suspending),
-
+
case lists:keysearch(Suspendee, 1, SList) of
- {value, {_Suspendee, 0, 0}} ->
- ?line ?t:fail({bad_suspendee_list, SList});
- {value, {Suspendee, Count, 0}} when is_integer(Count), Count > 0 ->
- {status, suspended} = process_info(Suspendee, status),
- Count;
- {value, {Suspendee, 0, Outstanding}} when is_integer(Outstanding),
- Outstanding > 0 ->
- 0;
- false ->
- 0;
- Error ->
- ?line ?t:fail({bad_suspendee_list, Error, SList})
+ {value, {_Suspendee, 0, 0}} ->
+ ct:fail({bad_suspendee_list, SList});
+ {value, {Suspendee, Count, 0}} when is_integer(Count), Count > 0 ->
+ {status, suspended} = process_info(Suspendee, status),
+ Count;
+ {value, {Suspendee, 0, Outstanding}} when is_integer(Outstanding),
+ Outstanding > 0 ->
+ 0;
+ false ->
+ 0;
+ Error ->
+ ct:fail({bad_suspendee_list, Error, SList})
end.
-
+
repeat_acc(Fun, N, Acc) ->
repeat_acc(Fun, 0, N, Acc).
@@ -1283,121 +1589,101 @@ repeat_acc(_Fun, N, N, Acc) ->
Acc;
repeat_acc(Fun, N, M, Acc) ->
repeat_acc(Fun, N+1, M, Fun(N, Acc)).
-
+
%% Tests that waiting process can be suspended
%% (bug in R2D and earlier; see OTP-1488).
-suspend_waiting(doc) -> "Test that a waiting process can be suspended.";
+%% Test that a waiting process can be suspended.
suspend_waiting(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
-
- ?line Process = fun_spawn(fun process/0),
- ?line receive after 1 -> ok end,
- ?line true = erlang:suspend_process(Process),
- ?line {status, suspended} = process_info(Process, status),
-
- %% Done.
- ?line test_server:timetrap_cancel(Dog),
+ Process = fun_spawn(fun process/0),
+ receive after 1 -> ok end,
+ true = erlang:suspend_process(Process),
+ {status, suspended} = process_info(Process, status),
ok.
-
-new_clear(doc) ->
- "Test that erlang:trace(new, true, ...) is cleared when tracer dies.";
+%% Test that erlang:trace(new, true, ...) is cleared when tracer dies.
new_clear(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
-
- ?line Tracer = spawn(fun receiver/0),
- ?line 0 = erlang:trace(new, true, [send, {tracer, Tracer}]),
- ?line {flags, [send]} = erlang:trace_info(new, flags),
- ?line {tracer, Tracer} = erlang:trace_info(new, tracer),
- ?line Mref = erlang:monitor(process, Tracer),
- ?line true = exit(Tracer, done),
+ Tracer = spawn(fun receiver/0),
+ 0 = erlang:trace(new, true, [send, {tracer, Tracer}]),
+ {flags, [send]} = erlang:trace_info(new, flags),
+ {tracer, Tracer} = erlang:trace_info(new, tracer),
+ Mref = erlang:monitor(process, Tracer),
+ true = exit(Tracer, done),
receive
- {'DOWN',Mref,_,_,_} -> ok
+ {'DOWN',Mref,_,_,_} -> ok
end,
- ?line {flags, []} = erlang:trace_info(new, flags),
- ?line {tracer, []} = erlang:trace_info(new, tracer),
-
- %% Done.
- ?line test_server:timetrap_cancel(Dog),
-
+ {flags, []} = erlang:trace_info(new, flags),
+ {tracer, []} = erlang:trace_info(new, tracer),
ok.
-existing_clear(doc) ->
- "Test that erlang:trace(all, false, ...) works without tracer.";
+%% Test that erlang:trace(all, false, ...) works without tracer.
existing_clear(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
- ?line Self = self(),
-
- ?line Tracer = fun_spawn(fun receiver/0),
- ?line N = erlang:trace(existing, true, [send, {tracer, Tracer}]),
- ?line {flags, [send]} = erlang:trace_info(Self, flags),
- ?line {tracer, Tracer} = erlang:trace_info(Self, tracer),
- ?line M = erlang:trace(all, false, [all]),
- ?line io:format("Started trace on ~p processes and stopped on ~p~n",
- [N, M]),
- ?line {flags, []} = erlang:trace_info(Self, flags),
- ?line {tracer, []} = erlang:trace_info(Self, tracer),
- ?line M = N + 1, % Since trace could not be enabled on the tracer.
+ Self = self(),
+
+ Tracer = fun_spawn(fun receiver/0),
+ N = erlang:trace(existing, true, [send, {tracer, Tracer}]),
+ {flags, [send]} = erlang:trace_info(Self, flags),
+ {tracer, Tracer} = erlang:trace_info(Self, tracer),
+ M = erlang:trace(all, false, [all]),
+ io:format("Started trace on ~p processes and stopped on ~p~n",
+ [N, M]),
+ {flags, []} = erlang:trace_info(Self, flags),
+ {tracer, []} = erlang:trace_info(Self, tracer),
+ M = N, % Used to be N + 1, but from 19.0 the tracer is also traced
- %% Done.
- ?line test_server:timetrap_cancel(Dog),
ok.
-bad_flag(doc) -> "Test that an invalid flag cause badarg";
-bad_flag(suite) -> [];
+%% Test that an invalid flag cause badarg
bad_flag(Config) when is_list(Config) ->
%% A bad flag could deadlock the SMP emulator in erts-5.5
- ?line {'EXIT', {badarg, _}} = (catch erlang:trace(new,
- true,
- [not_a_valid_flag])),
- ?line ok.
+ {'EXIT', {badarg, _}} = (catch erlang:trace(new,
+ true,
+ [not_a_valid_flag])),
+ ok.
-trace_delivered(doc) -> "Test erlang:trace_delivered/1";
-trace_delivered(suite) -> [];
+%% Test erlang:trace_delivered/1
trace_delivered(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(60)),
- ?line TokLoops = 10000,
- ?line Go = make_ref(),
- ?line Parent = self(),
- ?line Tok = spawn(fun () ->
- receive Go -> gone end,
- tok_trace_loop(Parent, 0, TokLoops)
- end),
- ?line 1 = erlang:trace(Tok, true, [procs]),
- ?line Mon = erlang:monitor(process, Tok),
- ?line NoOfTraceMessages = 4*TokLoops + 1,
- ?line io:format("Expect a total of ~p trace messages~n",
- [NoOfTraceMessages]),
- ?line Tok ! Go,
- ?line NoOfTraceMessages = drop_trace_until_down(Tok, Mon),
- ?line receive
- Msg ->
- ?line ?t:fail({unexpected_message, Msg})
- after 1000 ->
- ?line test_server:timetrap_cancel(Dog),
- ?line ok
- end.
+ ct:timetrap({minutes, 1}),
+ TokLoops = 10000,
+ Go = make_ref(),
+ Parent = self(),
+ Tok = spawn(fun () ->
+ receive Go -> gone end,
+ tok_trace_loop(Parent, 0, TokLoops)
+ end),
+ 1 = erlang:trace(Tok, true, [procs]),
+ Mon = erlang:monitor(process, Tok),
+ NoOfTraceMessages = 4*TokLoops + 1,
+ io:format("Expect a total of ~p trace messages~n",
+ [NoOfTraceMessages]),
+ Tok ! Go,
+ NoOfTraceMessages = drop_trace_until_down(Tok, Mon),
+ receive
+ Msg ->
+ ct:fail({unexpected_message, Msg})
+ after 1000 ->
+ ok
+ end.
drop_trace_until_down(Proc, Mon) ->
drop_trace_until_down(Proc, Mon, false, 0, 0).
drop_trace_until_down(Proc, Mon, TDRef, N, D) ->
case receive Msg -> Msg end of
- {trace_delivered, Proc, TDRef} ->
- io:format("~p trace messages on 'DOWN'~n", [D]),
- io:format("Got a total of ~p trace messages~n", [N]),
- N;
- {'DOWN', Mon, process, Proc, _} ->
- Ref = erlang:trace_delivered(Proc),
- drop_trace_until_down(Proc, Mon, Ref, N, N);
- Trace when is_tuple(Trace),
- element(1, Trace) == trace,
- element(2, Trace) == Proc ->
- drop_trace_until_down(Proc, Mon, TDRef, N+1, D)
+ {trace_delivered, Proc, TDRef} ->
+ io:format("~p trace messages on 'DOWN'~n", [D]),
+ io:format("Got a total of ~p trace messages~n", [N]),
+ N;
+ {'DOWN', Mon, process, Proc, _} ->
+ Ref = erlang:trace_delivered(Proc),
+ drop_trace_until_down(Proc, Mon, Ref, N, N);
+ Trace when is_tuple(Trace),
+ element(1, Trace) == trace,
+ element(2, Trace) == Proc ->
+ drop_trace_until_down(Proc, Mon, TDRef, N+1, D)
end.
tok_trace_loop(_, N, N) ->
@@ -1414,57 +1700,64 @@ tok_trace_loop(Parent, N, M) ->
receive_first() ->
receive
- Any -> Any
+ Any -> Any
+ end.
+
+%% Waits for and returns the first message in the message queue.
+
+receive_first_trace() ->
+ receive
+ Any when element(1,Any) =:= trace; element(1,Any) =:= trace_ts -> Any
end.
%% Ensures that there is no message in the message queue.
receive_nothing() ->
receive
- Any ->
- test_server:fail({unexpected_message, Any})
- after 200 ->
+ Any ->
+ ct:fail({unexpected_message, Any})
+ after 100 ->
ok
end.
-
+
%%% Models for various kinds of processes.
process(Dest) ->
receive
- {send_please, To, What} ->
- To ! What,
- process(Dest);
- {spawn_link_please, ReplyTo, {M, F, A}} ->
- Pid = spawn_link(M, F, A),
- ReplyTo ! {spawned, self(), Pid},
- process(Dest);
- {spawn_link_please, ReplyTo, Node, {M, F, A}} ->
- Pid = spawn_link(Node, M, F, A),
- ReplyTo ! {spawned, self(), Pid},
- process(Dest);
- {link_please, Pid} ->
- link(Pid),
- process(Dest);
- {unlink_please, Pid} ->
- unlink(Pid),
- process(Dest);
- {register_please, Name, Pid} ->
- register(Name, Pid),
- process(Dest);
- {unregister_please, Name} ->
- unregister(Name),
- process(Dest);
- {exit_please, Reason} ->
- exit(Reason);
- {trap_exit_please, State} ->
- process_flag(trap_exit, State),
- process(Dest);
- Other ->
- Dest ! {self(), Other},
- process(Dest)
+ {send_please, To, What} ->
+ To ! What,
+ process(Dest);
+ {spawn_link_please, ReplyTo, {M, F, A}} ->
+ Pid = spawn_link(M, F, A),
+ ReplyTo ! {spawned, self(), Pid},
+ process(Dest);
+ {spawn_link_please, ReplyTo, Node, {M, F, A}} ->
+ Pid = spawn_link(Node, M, F, A),
+ ReplyTo ! {spawned, self(), Pid},
+ process(Dest);
+ {link_please, Pid} ->
+ link(Pid),
+ process(Dest);
+ {unlink_please, Pid} ->
+ unlink(Pid),
+ process(Dest);
+ {register_please, Name, Pid} ->
+ register(Name, Pid),
+ process(Dest);
+ {unregister_please, Name} ->
+ unregister(Name),
+ process(Dest);
+ {exit_please, Reason} ->
+ exit(Reason);
+ {trap_exit_please, State} ->
+ process_flag(trap_exit, State),
+ process(Dest);
+ Other ->
+ Dest ! {self(), Other},
+ process(Dest)
after 3000 ->
- exit(timeout)
+ exit(timeout)
end.
@@ -1472,17 +1765,17 @@ process(Dest) ->
process() ->
receive
- {spawn_please, ReplyTo, Fun} ->
- Pid = fun_spawn(Fun),
- ReplyTo ! {spawned, Pid},
- process();
- {send_please, To, What} ->
- To ! What,
- process();
- timeout_please ->
- receive after 1 -> process() end;
- _Other ->
- process()
+ {spawn_please, ReplyTo, Fun} ->
+ Pid = fun_spawn(Fun),
+ ReplyTo ! {spawned, Pid},
+ process();
+ {send_please, To, What} ->
+ To ! What,
+ process();
+ timeout_please ->
+ receive after 1 -> process() end;
+ _Other ->
+ process()
end.
@@ -1490,18 +1783,23 @@ process() ->
sender() ->
receive
- {send_please, To, What} ->
- To ! What,
- sender()
+ {send_please, To, What} ->
+ To ! What,
+ sender()
end.
%% Just consumes messages from its message queue.
receiver() ->
- receive
- _Any -> receiver()
- end.
+ receiver(infinity).
+
+receiver(Timeout) ->
+ receiver(receive
+ {set_timeout, NewTimeout} -> NewTimeout;
+ _Any -> Timeout
+ after Timeout -> infinity %% reset
+ end).
%% Works as long as it receives CPU time. Will always be RUNNABLE.
@@ -1521,8 +1819,8 @@ fun_spawn(Fun, Args) ->
start_node(Name) ->
Pa = filename:dirname(code:which(?MODULE)),
Cookie = atom_to_list(erlang:get_cookie()),
- test_server:start_node(Name, slave,
- [{args, "-setcookie " ++ Cookie ++" -pa " ++ Pa}]).
+ test_server:start_node(Name, slave,
+ [{args, "-setcookie " ++ Cookie ++" -pa " ++ Pa}]).
stop_node(Node) ->
test_server:stop_node(Node).
@@ -1530,11 +1828,11 @@ stop_node(Node) ->
wait_for_empty_runq(DeadLine) ->
case statistics(run_queue) of
- 0 -> true;
- RQLen ->
- erlang:display("Waiting for empty run queue"),
- MSDL = DeadLine*1000,
- wait_for_empty_runq(MSDL, MSDL, RQLen)
+ 0 -> true;
+ RQLen ->
+ erlang:display("Waiting for empty run queue"),
+ MSDL = DeadLine*1000,
+ wait_for_empty_runq(MSDL, MSDL, RQLen)
end.
wait_for_empty_runq(DeadLine, Left, RQLen) when Left =< 0 ->
@@ -1545,48 +1843,48 @@ wait_for_empty_runq(DeadLine, Left, _RQLen) ->
UntilDeadLine = Left - Wait,
receive after Wait -> ok end,
case statistics(run_queue) of
- 0 ->
- erlang:display("Waited for "
- ++ integer_to_list(DeadLine
- - UntilDeadLine)
- ++ " ms for empty run queue."),
- true;
- NewRQLen ->
- wait_for_empty_runq(DeadLine,
- UntilDeadLine,
- NewRQLen)
+ 0 ->
+ erlang:display("Waited for "
+ ++ integer_to_list(DeadLine
+ - UntilDeadLine)
+ ++ " ms for empty run queue."),
+ true;
+ NewRQLen ->
+ wait_for_empty_runq(DeadLine,
+ UntilDeadLine,
+ NewRQLen)
end.
issue_non_empty_runq_warning(DeadLine, RQLen) ->
PIs = lists:foldl(
- fun (P, Acc) ->
- case process_info(P,
- [status,
- initial_call,
- current_function,
- registered_name,
- reductions,
- message_queue_len]) of
- [{status, Runnable} | _] = PI when Runnable /= waiting,
- Runnable /= suspended ->
- [[{pid, P} | PI] | Acc];
- _ ->
- Acc
- end
- end,
- [],
- processes()),
- ?t:format("WARNING: Unexpected runnable processes in system (waited ~p sec).~n"
- " Run queue length: ~p~n"
- " Self: ~p~n"
- " Processes info: ~p~n",
- [DeadLine div 1000, RQLen, self(), PIs]),
+ fun (P, Acc) ->
+ case process_info(P,
+ [status,
+ initial_call,
+ current_function,
+ registered_name,
+ reductions,
+ message_queue_len]) of
+ [{status, Runnable} | _] = PI when Runnable /= waiting,
+ Runnable /= suspended ->
+ [[{pid, P} | PI] | Acc];
+ _ ->
+ Acc
+ end
+ end,
+ [],
+ processes()),
+ io:format("WARNING: Unexpected runnable processes in system (waited ~p sec).~n"
+ " Run queue length: ~p~n"
+ " Self: ~p~n"
+ " Processes info: ~p~n",
+ [DeadLine div 1000, RQLen, self(), PIs]),
receive after 1000 -> ok end.
load_driver(Dir, Driver) ->
case erl_ddll:load_driver(Dir, Driver) of
- ok -> ok;
- {error, Error} = Res ->
- io:format("~s\n", [erl_ddll:format_error(Error)]),
- Res
+ ok -> ok;
+ {error, Error} = Res ->
+ io:format("~s\n", [erl_ddll:format_error(Error)]),
+ Res
end.