diff options
Diffstat (limited to 'erts/emulator/test')
-rw-r--r-- | erts/emulator/test/bif_SUITE.erl | 131 | ||||
-rw-r--r-- | erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c | 31 | ||||
-rw-r--r-- | erts/emulator/test/erl_link_SUITE.erl | 266 | ||||
-rw-r--r-- | erts/emulator/test/monitor_SUITE.erl | 10 | ||||
-rw-r--r-- | erts/emulator/test/port_SUITE.erl | 9 | ||||
-rw-r--r-- | erts/emulator/test/port_trace_SUITE.erl | 14 | ||||
-rw-r--r-- | erts/emulator/test/process_SUITE.erl | 28 | ||||
-rw-r--r-- | erts/emulator/test/signal_SUITE.erl | 412 | ||||
-rw-r--r-- | erts/emulator/test/trace_SUITE.erl | 91 |
9 files changed, 374 insertions, 618 deletions
diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl index e1b42e5d85..d16c6a320d 100644 --- a/erts/emulator/test/bif_SUITE.erl +++ b/erts/emulator/test/bif_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2016. All Rights Reserved. +%% Copyright Ericsson AB 2005-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -33,7 +33,8 @@ atom_to_binary/1,min_max/1, erlang_halt/1, erl_crash_dump_bytes/1, is_builtin/1, error_stacktrace/1, - error_stacktrace_during_call_trace/1]). + error_stacktrace_during_call_trace/1, + group_leader_prio/1, group_leader_prio_dirty/1]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -46,7 +47,8 @@ all() -> display, display_string, list_to_utf8_atom, atom_to_binary, binary_to_atom, binary_to_existing_atom, erl_crash_dump_bytes, min_max, erlang_halt, is_builtin, - error_stacktrace, error_stacktrace_during_call_trace]. + error_stacktrace, error_stacktrace_during_call_trace, + group_leader_prio, group_leader_prio_dirty]. %% Uses erlang:display to test that erts_printf does not do deep recursion display(Config) when is_list(Config) -> @@ -825,7 +827,6 @@ error_stacktrace_during_call_trace(Config) when is_list(Config) -> end end, ok. - error_stacktrace_test() -> Types = [apply_const_last, apply_const, apply_last, @@ -963,9 +964,119 @@ do_error_1(call) -> erlang:error(id(oops)). +group_leader_prio(Config) when is_list(Config) -> + group_leader_prio_test(false). + +group_leader_prio_dirty(Config) when is_list(Config) -> + group_leader_prio_test(true). + +group_leader_prio_test(Dirty) -> + %% + %% Unfortunately back in the days node local group_leader/2 was not + %% implemented as sending an asynchronous signal to the process to change + %% group leader for. Instead it has always been synchronously changed, and + %% nothing in the documentation have hinted otherwise... Therefore I do not + %% dare the change this. + %% + %% In order to prevent priority inversion, the priority of the receiver of + %% the group leader signal is elevated while handling incoming signals if + %% the sender has a higher priority than the receiver. This test tests that + %% the priority elevation actually works... + %% + Tester = self(), + Init = erlang:whereis(init), + GL = erlang:group_leader(), + process_flag(priority, max), + {TestProcFun, NTestProcs} + = case Dirty of + false -> + %% These processes will handle all incoming signals + %% by them selves... + {fun () -> + Tester ! {alive, self()}, + receive after infinity -> ok end + end, + 100}; + true -> + %% These processes wont handle incoming signals by + %% them selves since they are stuck on dirty schedulers + %% when we try to change group leader. A dirty process + %% signal handler process (system process) will be notified + %% of the need to handle incoming signals for these processes, + %% and will instead handle the signal for these processes... + {fun () -> + %% The following sends the message '{alive, self()}' + %% to Tester once on a dirty io scheduler, then wait + %% there until the process terminates... + erts_debug:dirty_io(alive_waitexiting, Tester) + end, + erlang:system_info(dirty_io_schedulers)} + end, + TPs = lists:map(fun (_) -> + spawn_opt(TestProcFun, + [link, {priority, normal}]) + end, lists:seq(1, NTestProcs)), + lists:foreach(fun (TP) -> receive {alive, TP} -> ok end end, TPs), + TLs = lists:map(fun (_) -> + spawn_opt(fun () -> tok_loop() end, + [link, {priority, high}]) + end, + lists:seq(1, 2*erlang:system_info(schedulers))), + %% Wait to ensure distribution of high prio processes over schedulers... + receive after 1000 -> ok end, + %% + %% Test that we can get group-leader signals through to normal prio + %% processes from a max prio process even though all schedulers are filled + %% with executing high prio processes. + %% + lists:foreach(fun (_) -> + lists:foreach(fun (TP) -> + erlang:yield(), + %% whitebox -- Enqueue some signals on it + %% preventing us from hogging its main lock + %% and set group-leader directly.... + erlang:demonitor(erlang:monitor(process, TP)), + true = erlang:group_leader(Init, TP), + {group_leader, Init} = process_info(TP, group_leader), + erlang:demonitor(erlang:monitor(process, TP)), + true = erlang:group_leader(GL, TP), + {group_leader, GL} = process_info(TP, group_leader) + end, + TPs) + end, + lists:seq(1,100)), + %% + %% Also test when it is exiting... + %% + lists:foreach(fun (TP) -> + erlang:yield(), + M = erlang:monitor(process, TP), + unlink(TP), + exit(TP, bang), + badarg = try + true = erlang:group_leader(Init, TP) + catch + error : What -> What + end, + receive + {'DOWN', M, process, TP, Reason} -> + bang = Reason + end + end, + TPs), + lists:foreach(fun (TL) -> + M = erlang:monitor(process, TL), + unlink(TL), + exit(TL, bang), + receive + {'DOWN', M, process, TL, Reason} -> + bang = Reason + end + end, + TLs), + ok. - -%% Helpers +%% helpers id(I) -> I. @@ -1005,3 +1116,11 @@ hostname([$@ | Hostname]) -> list_to_atom(Hostname); hostname([_C | Cs]) -> hostname(Cs). + +tok_loop() -> + tok_loop(hej). + +tok_loop(hej) -> + tok_loop(hopp); +tok_loop(hopp) -> + tok_loop(hej). diff --git a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c index 2a8b999307..a94a2c0b02 100644 --- a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c +++ b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2009-2017. All Rights Reserved. + * Copyright Ericsson AB 2009-2018. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -112,15 +112,12 @@ static ERL_NIF_TERM send_from_dirty_nif(ErlNifEnv* env, int argc, const ERL_NIF_ { ERL_NIF_TERM result; ErlNifPid pid; - ErlNifEnv* menv; int res; if (!enif_get_local_pid(env, argv[0], &pid)) return enif_make_badarg(env); result = enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_pid(env, &pid)); - menv = enif_alloc_env(); - res = enif_send(env, &pid, menv, result); - enif_free_env(menv); + res = enif_send(env, &pid, NULL, result); if (!res) return enif_make_badarg(env); else @@ -131,15 +128,12 @@ static ERL_NIF_TERM send_wait_from_dirty_nif(ErlNifEnv* env, int argc, const ERL { ERL_NIF_TERM result; ErlNifPid pid; - ErlNifEnv* menv; int res; if (!enif_get_local_pid(env, argv[0], &pid)) return enif_make_badarg(env); result = enif_make_tuple2(env, enif_make_atom(env, "ok"), enif_make_pid(env, &pid)); - menv = enif_alloc_env(); - res = enif_send(env, &pid, menv, result); - enif_free_env(menv); + res = enif_send(env, &pid, NULL, result); #ifdef __WIN32__ Sleep(2000); @@ -211,10 +205,8 @@ dirty_sleeper(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) /* If we get a pid argument, it indicates a process involved in the test wants a message from us. Prior to the sleep we send a 'ready' message, and then after the sleep, send a 'done' message. */ - if (argc == 1 && enif_get_local_pid(env, argv[0], &pid)) { - msg_env = enif_alloc_env(); - enif_send(env, &pid, msg_env, enif_make_atom(msg_env, "ready")); - } + if (argc == 1 && enif_get_local_pid(env, argv[0], &pid)) + enif_send(env, &pid, NULL, enif_make_atom(env, "ready")); #ifdef __WIN32__ Sleep(2000); @@ -222,11 +214,8 @@ dirty_sleeper(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) sleep(2); #endif - if (argc == 1) { - assert(msg_env != NULL); - enif_send(env, &pid, msg_env, enif_make_atom(msg_env, "done")); - enif_free_env(msg_env); - } + if (argc == 1) + enif_send(env, &pid, NULL, enif_make_atom(env, "done")); return enif_make_atom(env, "ok"); } @@ -247,8 +236,8 @@ static ERL_NIF_TERM dirty_call_while_terminated_nif(ErlNifEnv* env, int argc, co self_term = enif_make_pid(env, &self); - result = enif_make_tuple2(env, enif_make_atom(env, "dirty_alive"), self_term); menv = enif_alloc_env(); + result = enif_make_tuple2(menv, enif_make_atom(menv, "dirty_alive"), self_term); res = enif_send(env, &to, menv, result); enif_free_env(menv); if (!res) @@ -259,9 +248,7 @@ static ERL_NIF_TERM dirty_call_while_terminated_nif(ErlNifEnv* env, int argc, co ; result = enif_make_tuple2(env, enif_make_atom(env, "dirty_dead"), self_term); - menv = enif_alloc_env(); - res = enif_send(env, &to, menv, result); - enif_free_env(menv); + res = enif_send(env, &to, NULL, result); #ifdef __WIN32__ Sleep(1000); diff --git a/erts/emulator/test/erl_link_SUITE.erl b/erts/emulator/test/erl_link_SUITE.erl index a66ca7a57d..ed444f2599 100644 --- a/erts/emulator/test/erl_link_SUITE.erl +++ b/erts/emulator/test/erl_link_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2017. All Rights Reserved. +%% Copyright Ericsson AB 2001-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -53,26 +53,17 @@ -export([test_proc/0]). --define(LINK_UNDEF, 0). --define(LINK_PID, 1). --define(LINK_NODE, 3). - - -% These are to be kept in sync with erl_monitors.h --define(MON_ORIGIN, 1). --define(MON_TARGET, 2). - - --record(erl_link, {type = ?LINK_UNDEF, +-record(erl_link, {type, % process | port | dist_process pid = [], - targets = []}). + id}). % This is to be kept in sync with erl_bif_info.c (make_monitor_list) --record(erl_monitor, {type, % MON_ORIGIN or MON_TARGET - ref, +-record(erl_monitor, {type, % process | port | time_offset | dist_process | resource | node | nodes | suspend + dir, % origin | target + ref, % Reference | [] pid, % Process or nodename - name = []}). % registered name or [] + extra = []}). % registered name, integer or, [] suite() -> @@ -106,7 +97,7 @@ end_per_suite(_Config) -> links(Config) when is_list(Config) -> common_link_test(node(), node()), true = link(self()), - [] = find_erl_link(self(), ?LINK_PID, self()), + [] = find_erl_link(self(), process, self()), true = unlink(self()), ok. @@ -191,6 +182,7 @@ monitor_nodes(Config) when is_list(Config) -> monitor_node(A, false), monitor_node(B, true), monitor_node(C, true), + receive after 1000 -> ok end, monitor_node(C, false), monitor_node(C, true), monitor_node(B, true), @@ -304,7 +296,8 @@ run_common_process_monitors(TP1, TP2) -> wait_until(fun () -> is_proc_dead(TP2) end), ok = tp_call(TP1, fun () -> receive - {'DOWN',R2,process,TP2O,bye} -> + {'DOWN',R2,process,TP2O,Reason1} -> + bye = Reason1, ok end end), @@ -313,7 +306,8 @@ run_common_process_monitors(TP1, TP2) -> R3 = tp_call(TP1, fun () -> erlang:monitor(process, TP2) end), ok = tp_call(TP1, fun () -> receive - {'DOWN',R3,process,TP2O,noproc} -> + {'DOWN',R3,process,TP2O,Reason2} -> + noproc = Reason2, ok end end), @@ -698,22 +692,10 @@ test_proc() -> end, test_proc(). -expand_link_list([#erl_link{type = ?LINK_NODE, targets = N} = Rec | T]) -> - lists:duplicate(N,Rec#erl_link{targets = []}) ++ expand_link_list(T); -expand_link_list([#erl_link{targets = [#erl_link{pid = Pid}]} = Rec | T]) -> - [Rec#erl_link{targets = [Pid]} | expand_link_list(T)]; -expand_link_list([#erl_link{targets = [#erl_link{pid = Pid}|TT]} = Rec | T]) -> - [ Rec#erl_link{targets = [Pid]} | expand_link_list( - [Rec#erl_link{targets = TT} | T])]; -expand_link_list([#erl_link{targets = []} = Rec | T]) -> - [Rec | expand_link_list(T)]; -expand_link_list([]) -> - []. - get_local_link_list(Obj) -> case catch erts_debug:get_internal_state({link_list, Obj}) of LL when is_list(LL) -> - expand_link_list(LL); + LL; _ -> [] end. @@ -722,7 +704,7 @@ get_remote_link_list(Node, Obj) -> case catch rpc:call(Node, erts_debug, get_internal_state, [{link_list, Obj}]) of LL when is_list(LL) -> - expand_link_list(LL); + LL; _ -> [] end. @@ -776,82 +758,106 @@ get_monitor_list(undefined) -> find_erl_monitor(Pid, Ref) when is_reference(Ref) -> + MonitorList = get_monitor_list(Pid), + io:format("~p MonitorList: ~p~n", [Pid, MonitorList]), lists:foldl(fun (#erl_monitor{ref = R} = EL, Acc) when R == Ref -> [EL|Acc]; (_, Acc) -> Acc end, [], - get_monitor_list(Pid)). - -% find_erl_link(Obj, Ref) when is_reference(Ref) -> -% lists:foldl(fun (#erl_link{ref = R} = EL, Acc) when R == Ref -> -% [EL|Acc]; -% (_, Acc) -> -% Acc -% end, -% [], -% get_link_list(Obj)). - -find_erl_link(Obj, Type, [Item, Data]) when is_pid(Item); - is_port(Item); - is_atom(Item) -> - lists:foldl(fun (#erl_link{type = T, pid = I, targets = D} = EL, + MonitorList); +find_erl_monitor(Pid, Item) -> + MonitorList = get_monitor_list(Pid), + io:format("~p MonitorList: ~p~n", [Pid, MonitorList]), + lists:foldl(fun (#erl_monitor{pid = I} = EL, Acc) when I == Item -> + [EL|Acc]; + (_, Acc) -> + Acc + end, + [], + MonitorList). + + +find_erl_link(Obj, Type, Item) when is_pid(Item); is_port(Item) -> + LinkList = get_link_list(Obj), + io:format("~p LinkList: ~p~n", [Obj, LinkList]), + lists:foldl(fun (#erl_link{type = T, pid = I} = EL, Acc) when T == Type, I == Item -> - case Data of - D -> - [EL|Acc]; - [] -> - [EL|Acc]; - _ -> - Acc - end; + [EL|Acc]; + (_, Acc) -> + Acc + end, + [], + LinkList); +find_erl_link(Obj, Type, Id) when is_integer(Id) -> + %% Find by Id + LinkList = get_link_list(Obj), + io:format("~p LinkList: ~p~n", [Obj, LinkList]), + lists:foldl(fun (#erl_link{type = T, id = I} = EL, + Acc) when T == Type, I == Id -> + [EL|Acc]; (_, Acc) -> Acc end, [], - get_link_list(Obj)); -find_erl_link(Obj, Type, Item) when is_pid(Item); is_port(Item); is_atom(Item) -> - find_erl_link(Obj, Type, [Item, []]). + LinkList). +get_link_type(A, B) when is_port(A); + is_port(B) -> + port; +get_link_type(A, B) when is_pid(A), + is_pid(B) -> + case node(A) == node(B) of + true -> + process; + false -> + dist_process + end. +check_link(A, B) when node(A) == node(B) -> + LinkType = get_link_type(A, B), + [#erl_link{type = LinkType, + pid = B, + id = Id}] = find_erl_link(A, LinkType, B), + [#erl_link{type = LinkType, + pid = A, + id = Id}] = find_erl_link(B, LinkType, A), + [] = find_erl_link({node(A), node(B)}, + LinkType, + A), + [] = find_erl_link({node(B), node(A)}, + LinkType, + B), + ok; check_link(A, B) -> - [#erl_link{type = ?LINK_PID, + [#erl_link{type = dist_process, pid = B, - targets = []}] = find_erl_link(A, ?LINK_PID, B), - [#erl_link{type = ?LINK_PID, + id = IdA}] = find_erl_link(A, dist_process, B), + [#erl_link{type = dist_process, pid = A, - targets = []}] = find_erl_link(B, ?LINK_PID, A), - case node(A) == node(B) of - false -> - [#erl_link{type = ?LINK_PID, - pid = A, - targets = [B]}] = find_erl_link({node(A), - node(B)}, - ?LINK_PID, - [A, [B]]), - [#erl_link{type = ?LINK_PID, - pid = B, - targets = [A]}] = find_erl_link({node(B), - node(A)}, - ?LINK_PID, - [B, [A]]); - true -> - [] = find_erl_link({node(A), node(B)}, - ?LINK_PID, - [A, [B]]), - [] = find_erl_link({node(B), node(A)}, - ?LINK_PID, - [B, [A]]) - end, + id = IdA}] = find_erl_link({node(A), + node(B)}, + dist_process, + IdA), + [#erl_link{type = dist_process, + pid = A, + id = IdB}] = find_erl_link(B, dist_process, A), + [#erl_link{type = dist_process, + pid = B, + id = IdB}] = find_erl_link({node(B), + node(A)}, + dist_process, + IdB), ok. check_unlink(A, B) -> - [] = find_erl_link(A, ?LINK_PID, B), - [] = find_erl_link(B, ?LINK_PID, A), - [] = find_erl_link({node(A), node(B)}, ?LINK_PID, [A, [B]]), - [] = find_erl_link({node(B), node(A)}, ?LINK_PID, [B, [A]]), + LinkType = get_link_type(A, B), + [] = find_erl_link(A, LinkType, B), + [] = find_erl_link(B, LinkType, A), + [] = find_erl_link({node(A), node(B)}, dist_process, A), + [] = find_erl_link({node(B), node(A)}, dist_process, B), ok. check_process_monitor(From, {Name, Node}, Ref) when is_pid(From), @@ -864,22 +870,26 @@ check_process_monitor(From, {Name, Node}, Ref) when is_pid(From), is_atom(Node), is_reference(Ref) -> MonitoredPid = rpc:call(Node, erlang, whereis, [Name]), - [#erl_monitor{type = ?MON_ORIGIN, + [#erl_monitor{type = dist_process, + dir = origin, ref = Ref, pid = Node, - name = Name}] = find_erl_monitor(From, Ref), - [#erl_monitor{type = ?MON_TARGET, + extra = Name}] = find_erl_monitor(From, Ref), + [#erl_monitor{type = dist_process, + dir = target, ref = Ref, pid = From, - name = Name}] = find_erl_monitor({node(From), Node}, Ref), - [#erl_monitor{type = ?MON_ORIGIN, + extra = Name}] = find_erl_monitor({node(From), Node}, Ref), + [#erl_monitor{type = dist_process, + dir = origin, ref = Ref, pid = MonitoredPid, - name = Name}] = find_erl_monitor({Node, node(From)}, Ref), - [#erl_monitor{type = ?MON_TARGET, + extra = Name}] = find_erl_monitor({Node, node(From)}, Ref), + [#erl_monitor{type = dist_process, + dir = target, ref = Ref, pid = From, - name = Name}] = find_erl_monitor(MonitoredPid, Ref), + extra = Name}] = find_erl_monitor(MonitoredPid, Ref), ok; check_process_monitor(From, Name, Ref) when is_pid(From), is_atom(Name), @@ -887,27 +897,36 @@ check_process_monitor(From, Name, Ref) when is_pid(From), is_reference(Ref) -> MonitoredPid = rpc:call(node(From), erlang, whereis, [Name]), - [#erl_monitor{type = ?MON_ORIGIN, + [#erl_monitor{type = process, + dir = origin, ref = Ref, pid = MonitoredPid, - name = Name}] = find_erl_monitor(From, Ref), + extra = Name}] = find_erl_monitor(From, Ref), - [#erl_monitor{type = ?MON_TARGET, + [#erl_monitor{type = process, + dir = target, ref = Ref, pid = From, - name = Name}] = find_erl_monitor(MonitoredPid,Ref), + extra = Name}] = find_erl_monitor(MonitoredPid,Ref), ok; check_process_monitor(From, To, Ref) when is_pid(From), is_pid(To), is_reference(Ref) -> - OriMon = [#erl_monitor{type = ?MON_ORIGIN, + MonType = case node(From) == node(To) of + true -> process; + false -> dist_process + end, + + OriMon = [#erl_monitor{type = MonType, + dir = origin, ref = Ref, pid = To}], OriMon = find_erl_monitor(From, Ref), - TargMon = [#erl_monitor{type = ?MON_TARGET, + TargMon = [#erl_monitor{type = MonType, + dir = target, ref = Ref, pid = From}], TargMon = find_erl_monitor(To, Ref), @@ -915,7 +934,11 @@ check_process_monitor(From, To, Ref) when is_pid(From), case node(From) == node(To) of false -> - TargMon = find_erl_monitor({node(From), node(To)}, Ref), + DistTargMon = [#erl_monitor{type = dist_process, + dir = target, + ref = Ref, + pid = From}], + DistTargMon = find_erl_monitor({node(From), node(To)}, Ref), OriMon = find_erl_monitor({node(To), node(From)}, Ref); true -> [] = find_erl_monitor({node(From), node(From)}, Ref) @@ -986,19 +1009,36 @@ check_process_demonitor(From, To, Ref) when is_pid(From), ok. no_of_monitor_node(From, Node) when is_pid(From), is_atom(Node) -> - length(find_erl_link(From, ?LINK_NODE, Node)). + case find_erl_monitor(From, Node) of + [] -> 0; + [#erl_monitor{type = node, + dir = origin, + pid = Node, + extra = N}] -> N + end. +check_monitor_node(From, Node, 0) when is_pid(From), + is_atom(Node) -> + [] = find_erl_monitor(From, Node), + [] = find_erl_monitor({node(From), Node}, From); check_monitor_node(From, Node, No) when is_pid(From), is_atom(Node), is_integer(No), - No >= 0 -> - LL = lists:duplicate(No, #erl_link{type = ?LINK_NODE, pid = Node}), - DLL = lists:duplicate(No, #erl_link{type = ?LINK_NODE, pid = From}), - LL = find_erl_link(From, ?LINK_NODE, Node), - DLL = find_erl_link({node(From), Node}, ?LINK_NODE, From), - ok. - - + No > 0 -> + [#erl_monitor{type = node, + dir = origin, + pid = Node, + extra = No}] = find_erl_monitor(From, Node), + [#erl_monitor{type = node, + dir = target, + pid = From}] = find_erl_monitor({node(From), Node}, From). + +connection_id(Node) -> + try + erts_debug:get_internal_state({connection_id, Node}) + catch + _:_ -> -1 + end. hostname() -> from($@, atom_to_list(node())). diff --git a/erts/emulator/test/monitor_SUITE.erl b/erts/emulator/test/monitor_SUITE.erl index 9d772480d9..c7250a9d26 100644 --- a/erts/emulator/test/monitor_SUITE.erl +++ b/erts/emulator/test/monitor_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2017. All Rights Reserved. +%% Copyright Ericsson AB 1999-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -86,7 +86,7 @@ case_2(Config) when is_list(Config) -> R = erlang:monitor(process, B), B ! R, receive - {'EXIT', _} -> ok; + true -> ok; Other -> ct:fail({rec, Other}) end, @@ -98,7 +98,7 @@ case_2a(Config) when is_list(Config) -> {B,R} = spawn_monitor(?MODULE, y2, [self()]), B ! R, receive - {'EXIT', _} -> ok; + true -> ok; Other -> ct:fail({rec, Other}) end, @@ -182,7 +182,7 @@ demon_e_1(Config) when is_list(Config) -> end ), receive {P2, ref, R2} -> - demon_error(R2, badarg), + true = erlang:demonitor(R2), P2 ! {self(), stop}; Other2 -> ct:fail({rec, Other2}) @@ -729,8 +729,8 @@ named_down(Config) when is_list(Config) -> end), ?assertEqual(true, register(Name, NamedProc)), unlink(NamedProc), - exit(NamedProc, bang), Mon = erlang:monitor(process, Name), + exit(NamedProc, bang), receive {'DOWN',Mon, _, _, bang} -> ok after 3000 -> ?assert(false) end, ?assertEqual(true, register(Name, self())), diff --git a/erts/emulator/test/port_SUITE.erl b/erts/emulator/test/port_SUITE.erl index e46665a881..5b39d05df8 100644 --- a/erts/emulator/test/port_SUITE.erl +++ b/erts/emulator/test/port_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2017. All Rights Reserved. +%% Copyright Ericsson AB 1997-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -109,7 +109,6 @@ mon_port_pid_demonitor/1, mon_port_remote_on_remote/1, mon_port_driver_die/1, - mon_port_driver_die_demonitor/1, mul_basic/1, mul_slow_writes/1, name1/1, @@ -180,8 +179,7 @@ all() -> mon_port_bad_named, mon_port_pid_demonitor, mon_port_name_demonitor, - mon_port_driver_die, - mon_port_driver_die_demonitor + mon_port_driver_die ]. groups() -> @@ -2783,7 +2781,7 @@ mon_port_driver_die(Config) -> end, ok. - +-ifdef(DISABLED_TESTCASE). %% 1. Spawn a port which will sleep 3 seconds %% 2. Monitor port %% 3. Port driver and dies horribly (via C driver_failure call). This should @@ -2819,6 +2817,7 @@ mon_port_driver_die_demonitor(Config) -> after 5000 -> ?assert(false) end, ok. +-endif. %% @doc Makes a controllable port for testing. Underlying mechanism of this %% port is not important, only important is our ability to close/kill it or diff --git a/erts/emulator/test/port_trace_SUITE.erl b/erts/emulator/test/port_trace_SUITE.erl index a1986397a8..eba8f194e0 100644 --- a/erts/emulator/test/port_trace_SUITE.erl +++ b/erts/emulator/test/port_trace_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2017. All Rights Reserved. +%% Copyright Ericsson AB 1999-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -202,8 +202,7 @@ ports(_Config) -> erlang:port_close(Prt), [{trace,Prt,closed,normal}, - {trace,Prt,unregister,port_trace_SUITE}, - {trace,Prt,unlink,S}] = flush(), + {trace,Prt,unregister,port_trace_SUITE}] = flush(), ok. @@ -475,8 +474,7 @@ failure_test(Failure, Reason) -> process_flag(trap_exit, false) end, [{trace, Prt, 'receive', {S, {command, Failure}}}, - {trace, Prt, closed, Reason}, - {trace, Prt, unlink, S}] = flush(), + {trace, Prt, closed, Reason}] = flush(), ok. @@ -599,13 +597,11 @@ close(Prt, Flags) -> if Recv, Ports -> [{trace, Prt, 'receive', {S, close}}, - {trace, Prt, closed, normal}, - {trace, Prt, unlink, S}] = flush(); + {trace, Prt, closed, normal}] = flush(); Recv -> [{trace, Prt, 'receive', {S, close}}] = flush(); Ports -> - [{trace, Prt, closed, normal}, - {trace, Prt, unlink, S}] = flush(); + [{trace, Prt, closed, normal}] = flush(); true -> [] = flush() end. diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index a8bcfac84d..7eff786e8b 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2017. All Rights Reserved. +%% Copyright Ericsson AB 1997-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -43,7 +43,6 @@ process_info_lock_reschedule3/1, process_info_garbage_collection/1, bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1, - process_status_exiting/1, otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1, process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1, spawn_opt_heap_size/1, spawn_opt_max_heap_size/1, @@ -80,7 +79,6 @@ all() -> process_info_lock_reschedule2, process_info_lock_reschedule3, process_info_garbage_collection, - process_status_exiting, bump_reductions, low_prio, yield, yield2, otp_4725, bad_register, garbage_collect, process_info_messages, process_flag_badarg, process_flag_heap_size, @@ -841,28 +839,6 @@ process_info_lock_reschedule3(Config) when is_list(Config) -> ct:fail(BadStatus) end. -process_status_exiting(Config) when is_list(Config) -> - %% Make sure that erts_debug:get_internal_state({process_status,P}) - %% returns exiting if it is in status P_EXITING. - erts_debug:set_internal_state(available_internal_state,true), - Prio = process_flag(priority, max), - P = spawn_opt(fun () -> receive after infinity -> ok end end, - [{priority, normal}]), - erlang:yield(), - %% The tok_loop processes are here to make it hard for the exiting - %% process to be scheduled in for exit... - TokLoops = lists:map(fun (_) -> - spawn_opt(fun tok_loop/0, - [link,{priority, high}]) - end, lists:seq(1, erlang:system_info(schedulers_online))), - exit(P, boom), - wait_until(fun() -> - exiting =:= erts_debug:get_internal_state({process_status,P}) - end), - lists:foreach(fun (Tok) -> unlink(Tok), exit(Tok,bang) end, TokLoops), - process_flag(priority, Prio), - ok. - otp_4725(Config) when is_list(Config) -> Tester = self(), Ref1 = make_ref(), @@ -1000,7 +976,7 @@ gv(Key,List) -> %% Tests erlang:bump_reductions/1. bump_reductions(Config) when is_list(Config) -> erlang:garbage_collect(), - receive after 1 -> ok end, % Clear reductions. + erlang:yield(), % Clear reductions. {reductions,R1} = process_info(self(), reductions), true = erlang:bump_reductions(100), {reductions,R2} = process_info(self(), reductions), diff --git a/erts/emulator/test/signal_SUITE.erl b/erts/emulator/test/signal_SUITE.erl index 61a8617165..fab2f45f28 100644 --- a/erts/emulator/test/signal_SUITE.erl +++ b/erts/emulator/test/signal_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2017. All Rights Reserved. +%% Copyright Ericsson AB 2006-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -34,23 +34,9 @@ -export([init_per_testcase/2, end_per_testcase/2]). % Test cases --export([xm_sig_order/1, - pending_exit_unlink_process/1, - pending_exit_unlink_dist_process/1, - pending_exit_unlink_port/1, - pending_exit_trap_exit/1, - pending_exit_receive/1, - pending_exit_exit/1, - pending_exit_gc/1, - pending_exit_is_process_alive/1, - pending_exit_process_display/1, - pending_exit_process_info_1/1, - pending_exit_process_info_2/1, - pending_exit_group_leader/1, - exit_before_pending_exit/1]). +-export([xm_sig_order/1]). init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> - available_internal_state(true), [{testcase, Func}|Config]. end_per_testcase(_Func, _Config) -> @@ -60,24 +46,14 @@ init_per_suite(Config) -> Config. end_per_suite(_Config) -> - available_internal_state(true), - catch erts_debug:set_internal_state(not_running_optimization, true), - available_internal_state(false). + ok. suite() -> [{ct_hooks,[ts_install_cth]}, {timetrap, {minutes, 2}}]. all() -> - [xm_sig_order, pending_exit_unlink_process, - pending_exit_unlink_dist_process, - pending_exit_unlink_port, pending_exit_trap_exit, - pending_exit_receive, pending_exit_trap_exit, - pending_exit_gc, pending_exit_is_process_alive, - pending_exit_process_display, - pending_exit_process_info_1, - pending_exit_process_info_2, pending_exit_group_leader, - exit_before_pending_exit]. + [xm_sig_order]. %% Test that exit signals and messages are received in correct order @@ -113,362 +89,9 @@ xm_sig_order_proc() -> end, xm_sig_order_proc(). -pending_exit_unlink_process(Config) when is_list(Config) -> - pending_exit_test(self(), unlink). - -pending_exit_unlink_dist_process(Config) when is_list(Config) -> - {ok, Node} = start_node(Config), - From = spawn(Node, fun () -> receive after infinity -> ok end end), - Res = pending_exit_test(From, unlink), - stop_node(Node), - Res. - -pending_exit_unlink_port(Config) when is_list(Config) -> - pending_exit_test(hd(erlang:ports()), unlink). - -pending_exit_trap_exit(Config) when is_list(Config) -> - pending_exit_test(self(), trap_exit). - -pending_exit_receive(Config) when is_list(Config) -> - pending_exit_test(self(), 'receive'). - -pending_exit_exit(Config) when is_list(Config) -> - pending_exit_test(self(), exit). - -pending_exit_gc(Config) when is_list(Config) -> - pending_exit_test(self(), gc). - -pending_exit_test(From, Type) -> - OTE = process_flag(trap_exit, true), - Ref = make_ref(), - Master = self(), - ExitBySignal = case Type of - gc -> - lists:duplicate(10000, - exit_by_signal); - _ -> - exit_by_signal - end, - Pid = spawn_link( - fun () -> - receive go -> ok end, - false = have_pending_exit(), - exit = fake_exit(From, - self(), - ExitBySignal), - true = have_pending_exit(), - Master ! {self(), Ref, Type}, - case Type of - gc -> - force_gc(), - erlang:yield(); - unlink -> - unlink(From); - trap_exit -> - process_flag(trap_exit, true); - 'receive' -> - receive _ -> ok - after 0 -> ok - end; - exit -> - ok - end, - exit(exit_by_myself) - end), - Mon = erlang:monitor(process, Pid), - Pid ! go, - Reason = receive - {'DOWN', Mon, process, Pid, R} -> - receive - {Pid, Ref, Type} -> - ok - after 0 -> - ct:fail(premature_exit) - end, - case Type of - exit -> - exit_by_myself = R; - _ -> - ExitBySignal = R - end - end, - receive - {'EXIT', Pid, R2} -> - Reason = R2 - end, - process_flag(trap_exit, OTE), - ok, - {comment, "Test only valid with current SMP emulator."}. - - - -exit_before_pending_exit(Config) when is_list(Config) -> - %% This is a testcase testcase very specific to the smp - %% implementation as it is of the time of writing. - %% - %% The testcase tries to check that a process can - %% exit by itself even though it has a pending exit. - OTE = process_flag(trap_exit, true), - Master = self(), - Tester = spawn_link( - fun () -> - Opts = case {erlang:system_info(run_queues), - erlang:system_info(schedulers_online)} of - {RQ, SO} when RQ =:= 1; SO =:= 1 -> []; - _ -> - process_flag(scheduler, 1), - [{scheduler, 2}] - end, - P = self(), - Exiter = spawn_opt(fun () -> - receive - {exit_me, P, R} -> - exit(P, R) - end - end, Opts), - erlang:yield(), - Exiter ! {exit_me, self(), exited_by_exiter}, - %% We want to get a pending exit - %% before we exit ourselves. We - %% don't want to be scheduled out - %% since we will then see the - %% pending exit. - %% - %% Do something that takes - %% relatively long time but - %% consumes few reductions... - repeat(fun() -> erlang:system_info(procs) end,10), - %% ... then exit. - Master ! {self(), - pending_exit, - have_pending_exit()}, - exit(exited_by_myself) - end), - PendingExit = receive {Tester, pending_exit, PE} -> PE end, - receive - {'EXIT', Tester, exited_by_myself} -> - process_flag(trap_exit, OTE), - ok; - Msg -> - ct:fail({unexpected_message, Msg}) - end, - NoScheds = integer_to_list(erlang:system_info(schedulers_online)), - {comment, - "Was " - ++ case PendingExit of - true -> ""; - false ->"*not*" - end ++ " able to trigger a pending exit. " - ++ "Running on " ++ NoScheds ++ " scheduler(s). " - ++ "This test is only interesting with at least two schedulers."}. - --define(PE_INFO_REPEAT, 100). - -pending_exit_is_process_alive(Config) when is_list(Config) -> - S = exit_op_test_init(), - TestFun = fun (P) -> false = is_process_alive(P) end, - repeated_exit_op_test(TestFun, ?PE_INFO_REPEAT), - verify_pending_exit_success(S), - comment(). - -pending_exit_process_info_1(Config) when is_list(Config) -> - S = exit_op_test_init(), - TestFun = fun (P) -> - undefined = process_info(P) - end, - repeated_exit_op_test(TestFun, ?PE_INFO_REPEAT), - verify_pending_exit_success(S), - comment(). - -pending_exit_process_info_2(Config) when is_list(Config) -> - S0 = exit_op_test_init(), - repeated_exit_op_test(fun (P) -> - undefined = process_info(P, messages) - end, ?PE_INFO_REPEAT), - S1 = verify_pending_exit_success(S0), - repeated_exit_op_test(fun (P) -> - undefined = process_info(P, status) - end, ?PE_INFO_REPEAT), - S2 = verify_pending_exit_success(S1), - repeated_exit_op_test(fun (P) -> - undefined = process_info(P, links) - end, ?PE_INFO_REPEAT), - S3 = verify_pending_exit_success(S2), - repeated_exit_op_test(fun (P) -> - undefined = process_info(P, [messages]) - end, ?PE_INFO_REPEAT), - S4 = verify_pending_exit_success(S3), - repeated_exit_op_test(fun (P) -> - undefined = process_info(P, [status]) - end, ?PE_INFO_REPEAT), - S5 = verify_pending_exit_success(S4), - repeated_exit_op_test(fun (P) -> - undefined = process_info(P, [links]) - end, ?PE_INFO_REPEAT), - S6 = verify_pending_exit_success(S5), - repeated_exit_op_test(fun (P) -> - undefined = process_info(P, [status, - links]) - end, ?PE_INFO_REPEAT), - S7 = verify_pending_exit_success(S6), - repeated_exit_op_test(fun (P) -> - undefined = process_info(P, [messages, - status]) - end, ?PE_INFO_REPEAT), - S8 = verify_pending_exit_success(S7), - repeated_exit_op_test(fun (P) -> - undefined = process_info(P, [messages, - links]) - end, ?PE_INFO_REPEAT), - S9 = verify_pending_exit_success(S8), - repeated_exit_op_test( - fun (P) -> - undefined = process_info(P, [message_queue_len, - status]) - end, ?PE_INFO_REPEAT), - S10 = verify_pending_exit_success(S9), - repeated_exit_op_test(fun (P) -> - undefined = process_info(P, [messages, - links, - status]) - end, ?PE_INFO_REPEAT), - verify_pending_exit_success(S10), - comment(). - -pending_exit_process_display(Config) when is_list(Config) -> - S = exit_op_test_init(), - TestFun = fun (P) -> - badarg = try - erlang:process_display(P, backtrace) - catch - error:badarg -> badarg - end - end, - repeated_exit_op_test(TestFun, ?PE_INFO_REPEAT), - verify_pending_exit_success(S), - comment(). - -pending_exit_group_leader(Config) when is_list(Config) -> - S = exit_op_test_init(), - TestFun = fun (P) -> - badarg = try - group_leader(self(), P) - catch - error:badarg -> badarg - end - end, - repeated_exit_op_test(TestFun, ?PE_INFO_REPEAT), - verify_pending_exit_success(S), - comment(). - %% %% -- Internal utils -------------------------------------------------------- %% -exit_op_test_init() -> - put(no_pending_exit_success, 0), - put(no_pending_exit_tries, 0), - {case {erlang:system_info(run_queues), - erlang:system_info(schedulers_online)} of - {RQ, SO} when RQ =:= 1; SO =:= 1 -> false; - _ -> true - end, 0, 0}. - -verify_pending_exit_success({false, _, _} = S) -> - S; -verify_pending_exit_success({true, S, T}) -> - NewS = get(no_pending_exit_success), - NewT = get(no_pending_exit_tries), - case NewT =:= T of - true -> ok; - _ -> case NewS > S of - true -> ok; - _ -> exit(no_pending_exits) - end - end, - {true, NewS, NewT}. - -comment() -> - {comment, - "Pending exit trigger ratio " - ++ integer_to_list(get(no_pending_exit_success)) - ++ "/" - ++ integer_to_list(get(no_pending_exit_tries)) - ++ "." - ++ case get(not_running_opt_test) of - true -> " No 'not running optimization' to disable."; - _ -> "" - end}. - -repeated_exit_op_test(TestFun, N) -> - WorkFun0 = fun () -> - lists:sort(lists:reverse(lists:seq(1, 1000))) - end, - repeat(fun () -> exit_op_test(TestFun, WorkFun0) end, N), - try erts_debug:set_internal_state(not_running_optimization, false) of - Bool when Bool == true; Bool == false -> - WorkFun1 = fun () -> - erts_debug:set_internal_state(sleep, 0), - lists:sort(lists:reverse(lists:seq(1, 1000))) - end, - repeat(fun () -> - exit_op_test(TestFun, WorkFun1) - end, N) - catch - error:notsup -> put(not_running_opt_test, true) - after - catch erts_debug:set_internal_state(not_running_optimization, true) - end. - -exit_op_test(TestFun, WorkFun) -> - Opts = case {erlang:system_info(run_queues), - erlang:system_info(schedulers_online)} of - {RQ, SO} when RQ =:= 1; SO =:= 1 -> []; - _ -> - process_flag(scheduler, 1), - [{scheduler, 2}] - end, - Master = self(), - Going = make_ref(), - P = spawn_opt(fun () -> - loop(10, WorkFun), - Master ! Going, - loop(infinity, WorkFun) - end, Opts), - receive Going -> ok end, - loop(10, WorkFun), - erlang:yield(), - exit(P, bang), - PE0 = have_pending_exit(P), - TestFun(P), - PE = case PE0 of - true -> true; - _ -> false - end, - case {PE, get(no_pending_exit_success), get(no_pending_exit_tries)} of - {true, undefined, undefined} -> - put(no_pending_exit_success, 1), - put(no_pending_exit_tries, 1); - {false, undefined, undefined} -> - put(no_pending_exit_success, 0), - put(no_pending_exit_tries, 1); - {true, S, T} -> - put(no_pending_exit_success, S+1), - put(no_pending_exit_tries, T+1); - {false, _S, T} -> - put(no_pending_exit_tries, T+1) - end, - ok. - -loop(infinity, WorkFun) -> - do_loop(infinity, WorkFun); -loop(0, _WorkFun) -> - ok; -loop(N, WorkFun) when is_integer(N) -> - do_loop(N-1, WorkFun). - -do_loop(N, WorkFun) -> - WorkFun(), - loop(N, WorkFun). repeat(_Fun, N) when is_integer(N), N =< 0 -> ok; @@ -486,30 +109,3 @@ start_node(Config) -> stop_node(Node) -> test_server:stop_node(Node). - -have_pending_exit() -> - have_pending_exit(self()). - -have_pending_exit(Pid) -> - erts_debug:get_internal_state({have_pending_exit, Pid}). - -force_gc() -> - erts_debug:set_internal_state(force_gc, self()). - -fake_exit(From, To, Reason) -> - erts_debug:set_internal_state(send_fake_exit_signal, {From, To, Reason}). - -available_internal_state(Bool) when Bool == true; Bool == false -> - case {Bool, - (catch erts_debug:get_internal_state(available_internal_state))} of - {true, true} -> - true; - {false, true} -> - erts_debug:set_internal_state(available_internal_state, false), - true; - {true, _} -> - erts_debug:set_internal_state(available_internal_state, true), - false; - {false, _} -> - false - end. diff --git a/erts/emulator/test/trace_SUITE.erl b/erts/emulator/test/trace_SUITE.erl index a81aa64057..def25dba7d 100644 --- a/erts/emulator/test/trace_SUITE.erl +++ b/erts/emulator/test/trace_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2017. All Rights Reserved. +%% Copyright Ericsson AB 1997-2018. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -235,7 +235,7 @@ link_receive_call_correlation(Config) when is_list(Config) -> 1 = erlang:trace(Receiver, true, ['receive', procs, call, timestamp, scheduler_id]), 1 = erlang:trace_pattern({?MODULE, receive_msg, '_'}, [], [local]), - Num = 100000, + Num = 100, (fun F(0) -> []; F(N) -> @@ -255,7 +255,7 @@ link_receive_call_correlation(Config) when is_list(Config) -> Msgs = (fun F() -> receive M -> [M | F()] after 1 -> [] end end)(), - case check_consistent(Receiver, Num, Num, Num, Msgs) of + case check_consistent(Receiver, Num, Num, Num, Msgs, false, undefined) of ok -> ok; {error, Reason} -> @@ -265,20 +265,63 @@ link_receive_call_correlation(Config) when is_list(Config) -> -define(schedid, , _). -check_consistent(_Pid, Recv, Call, _LU, [Msg | _]) when Recv > Call -> +check_consistent(_Pid, Recv, Call, _LU, [Msg | _], _Received, _LinkedN) when Recv > Call -> {error, Msg}; -check_consistent(Pid, Recv, Call, LU, [Msg | Msgs]) -> +check_consistent(Pid, Recv, Call, LU, [Msg | Msgs], false, undefined) -> case Msg of {trace, Pid, 'receive', Recv ?schedid} -> - check_consistent(Pid,Recv - 1, Call, LU, Msgs); + check_consistent(Pid,Recv - 1, Call, LU, Msgs, true, undefined); {trace_ts, Pid, 'receive', Recv ?schedid, _} -> - check_consistent(Pid,Recv - 1, Call, LU, Msgs); + check_consistent(Pid,Recv - 1, Call, LU, Msgs, true, undefined); {trace, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid} -> - check_consistent(Pid,Recv, Call - 1, LU, Msgs); + check_consistent(Pid,Recv, Call - 1, LU, Msgs, false, undefined); {trace_ts, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid, _} -> - check_consistent(Pid,Recv, Call - 1, LU, Msgs); + check_consistent(Pid,Recv, Call - 1, LU, Msgs, false, undefined); + + {trace, Pid, _, _Self ?schedid} -> + check_consistent(Pid, Recv, Call, LU, Msgs, false, undefined); + {trace_ts, Pid, _, _Self ?schedid, _} -> + check_consistent(Pid, Recv, Call, LU, Msgs, false, undefined); + + Msg -> + {error, Msg} + end; +check_consistent(Pid, Recv, Call, LU, [Msg | Msgs], true, undefined) -> + + case Msg of + {trace, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid} -> + check_consistent(Pid,Recv, Call - 1, LU, Msgs, true, undefined); + {trace_ts, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid, _} -> + check_consistent(Pid,Recv, Call - 1, LU, Msgs, true, undefined); + + {trace, Pid, getting_linked, _Self ?schedid} -> + check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, Recv rem 2); + {trace_ts, Pid, getting_linked, _Self ?schedid, _} -> + check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, Recv rem 2); + + {trace, Pid, getting_unlinked, _Self ?schedid} -> + check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, (Recv+1) rem 2); + {trace_ts, Pid, getting_unlinked, _Self ?schedid, _} -> + check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, (Recv+1) rem 2); + + Msg -> + {error, Msg} + end; +check_consistent(Pid, Recv, Call, LU, [Msg | Msgs], true, LinkedN) -> + UnlinkedN = (LinkedN + 1) rem 2, + + case Msg of + {trace, Pid, 'receive', Recv ?schedid} when Recv == LU -> + check_consistent(Pid,Recv - 1, Call, LU, Msgs, true, LinkedN); + {trace_ts, Pid, 'receive', Recv ?schedid, _} when Recv == LU -> + check_consistent(Pid,Recv - 1, Call, LU, Msgs, true, LinkedN); + + {trace, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid} -> + check_consistent(Pid,Recv, Call - 1, LU, Msgs, true, LinkedN); + {trace_ts, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid, _} -> + check_consistent(Pid,Recv, Call - 1, LU, Msgs, true, LinkedN); %% We check that for each receive we have gotten a %% getting_linked or getting_unlinked message. Also @@ -286,38 +329,38 @@ check_consistent(Pid, Recv, Call, LU, [Msg | Msgs]) -> %% 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); + when Recv rem 2 == LinkedN -> + check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, LinkedN); {trace_ts, Pid, getting_linked, _Self ?schedid, _} - when Recv rem 2 == 0, Recv == LU -> - check_consistent(Pid, Recv, Call, LU - 1, Msgs); + when Recv rem 2 == LinkedN -> + check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, LinkedN); {trace, Pid, getting_unlinked, _Self ?schedid} - when Recv rem 2 == 1, Recv == LU -> - check_consistent(Pid, Recv, Call, LU - 1, Msgs); + when Recv rem 2 == UnlinkedN -> + check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, LinkedN); {trace_ts, Pid, getting_unlinked, _Self ?schedid, _} - when Recv rem 2 == 1, Recv == LU -> - check_consistent(Pid, Recv, Call, LU - 1, Msgs); + when Recv rem 2 == UnlinkedN -> + check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, LinkedN); {trace,Pid,'receive',Ignore ?schedid} when Ignore == stop; Ignore == timeout -> - check_consistent(Pid, Recv, Call, LU, Msgs); + check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN); {trace_ts,Pid,'receive',Ignore ?schedid,_} when Ignore == stop; Ignore == timeout -> - check_consistent(Pid, Recv, Call, LU, Msgs); + check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN); {trace, Pid, exit, normal ?schedid} -> - check_consistent(Pid, Recv, Call, LU, Msgs); + check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN); {trace_ts, Pid, exit, normal ?schedid, _} -> - check_consistent(Pid, Recv, Call, LU, Msgs); + check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN); {'EXIT', Pid, normal} -> - check_consistent(Pid, Recv, Call, LU, Msgs); + check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN); Msg -> {error, Msg} end; -check_consistent(_, 0, 0, 0, []) -> +check_consistent(_, 0, 0, 1, [], true, _) -> ok; -check_consistent(_, Recv, Call, LU, []) -> +check_consistent(_, Recv, Call, LU, [], _, _) -> {error,{Recv, Call, LU}}. receive_msg(M) -> |