aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/test
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/test')
-rw-r--r--lib/kernel/test/erl_distribution_wb_SUITE.erl58
-rw-r--r--lib/kernel/test/file_SUITE.erl201
-rw-r--r--lib/kernel/test/gen_tcp_api_SUITE.erl7
-rw-r--r--lib/kernel/test/seq_trace_SUITE.erl100
4 files changed, 326 insertions, 40 deletions
diff --git a/lib/kernel/test/erl_distribution_wb_SUITE.erl b/lib/kernel/test/erl_distribution_wb_SUITE.erl
index 8256444bdc..bb42a0ac39 100644
--- a/lib/kernel/test/erl_distribution_wb_SUITE.erl
+++ b/lib/kernel/test/erl_distribution_wb_SUITE.erl
@@ -47,6 +47,9 @@
R
end).
+-define(EPMD_DIST_HIGH, 6).
+-define(EPMD_DIST_LOW, 5).
+
-define(DFLAG_PUBLISHED,1).
-define(DFLAG_ATOM_CACHE,2).
-define(DFLAG_EXTENDED_REFERENCES,4).
@@ -57,15 +60,18 @@
-define(DFLAG_NEW_FUN_TAGS,16#80).
-define(DFLAG_EXTENDED_PIDS_PORTS,16#100).
-define(DFLAG_UTF8_ATOMS, 16#10000).
+-define(DFLAG_BIG_CREATION, 16#40000).
%% From R9 and forward extended references is compulsory
%% From R10 and forward extended pids and ports are compulsory
%% From R20 and forward UTF8 atoms are compulsory
%% From R21 and forward NEW_FUN_TAGS is compulsory (no more tuple fallback {fun, ...})
+%% From R23 and forward BIG_CREATION is compulsory
-define(COMPULSORY_DFLAGS, (?DFLAG_EXTENDED_REFERENCES bor
?DFLAG_EXTENDED_PIDS_PORTS bor
?DFLAG_UTF8_ATOMS bor
- ?DFLAG_NEW_FUN_TAGS)).
+ ?DFLAG_NEW_FUN_TAGS bor
+ ?DFLAG_BIG_CREATION)).
-define(PASS_THROUGH, $p).
@@ -208,9 +214,9 @@ pending_up_md5(Node,OurName,Cookie) ->
{ok, SocketA} = gen_tcp:connect(atom_to_list(NB),PortNo,
[{active,false},
{packet,2}]),
- send_name(SocketA,OurName,5),
+ send_name(SocketA,OurName, ?EPMD_DIST_HIGH),
ok = recv_status(SocketA),
- {hidden,Node,5,HisChallengeA} = recv_challenge(SocketA), % See 1)
+ {hidden,Node,?EPMD_DIST_HIGH,HisChallengeA} = recv_challenge(SocketA), % See 1)
OurChallengeA = gen_challenge(),
OurDigestA = gen_digest(HisChallengeA, Cookie),
send_challenge_reply(SocketA, OurChallengeA, OurDigestA),
@@ -224,11 +230,11 @@ pending_up_md5(Node,OurName,Cookie) ->
{ok, SocketB} = gen_tcp:connect(atom_to_list(NB),PortNo,
[{active,false},
{packet,2}]),
- send_name(SocketB,OurName,5),
+ send_name(SocketB,OurName, ?EPMD_DIST_HIGH),
alive = recv_status(SocketB),
send_status(SocketB, true),
gen_tcp:close(SocketA),
- {hidden,Node,5,HisChallengeB} = recv_challenge(SocketB), % See 1)
+ {hidden,Node,?EPMD_DIST_HIGH,HisChallengeB} = recv_challenge(SocketB), % See 1)
OurChallengeB = gen_challenge(),
OurDigestB = gen_digest(HisChallengeB, Cookie),
send_challenge_reply(SocketB, OurChallengeB, OurDigestB),
@@ -254,7 +260,7 @@ simultaneous_md5(Node, OurName, Cookie) when OurName < Node ->
Else ->
exit(Else)
end,
- EpmdSocket = register(OurName, LSocket, 1, 5),
+ EpmdSocket = register_node(OurName, LSocket, ?EPMD_DIST_LOW, ?EPMD_DIST_HIGH),
{NA, NB} = split(Node),
rpc:cast(Node, net_adm, ping, [OurName]),
receive after 1000 -> ok end,
@@ -262,7 +268,7 @@ simultaneous_md5(Node, OurName, Cookie) when OurName < Node ->
{ok, SocketA} = gen_tcp:connect(atom_to_list(NB),PortNo,
[{active,false},
{packet,2}]),
- send_name(SocketA,OurName,5),
+ send_name(SocketA,OurName, ?EPMD_DIST_HIGH),
%% We are still not marked up on the other side, as our first message
%% is not sent.
SocketB = case gen_tcp:accept(LSocket) of
@@ -275,11 +281,11 @@ simultaneous_md5(Node, OurName, Cookie) when OurName < Node ->
%% Now we are expected to close A
gen_tcp:close(SocketA),
%% But still Socket B will continue
- {normal,Node,5} = recv_name(SocketB), % See 1)
+ {normal,Node,?EPMD_DIST_HIGH} = recv_name(SocketB), % See 1)
send_status(SocketB, ok_simultaneous),
MyChallengeB = gen_challenge(),
- send_challenge(SocketB, OurName, MyChallengeB,5),
- HisChallengeB = recv_challenge_reply(SocketB, MyChallengeB, Cookie),
+ send_challenge(SocketB, OurName, MyChallengeB, ?EPMD_DIST_HIGH),
+ {ok,HisChallengeB} = recv_challenge_reply(SocketB, MyChallengeB, Cookie),
DigestB = gen_digest(HisChallengeB,Cookie),
send_challenge_ack(SocketB, DigestB),
inet:setopts(SocketB, [{active, false},
@@ -301,7 +307,8 @@ simultaneous_md5(Node, OurName, Cookie) when OurName > Node ->
Else ->
exit(Else)
end,
- EpmdSocket = register(OurName, LSocket, 1, 5),
+ EpmdSocket = register_node(OurName, LSocket,
+ ?EPMD_DIST_LOW, ?EPMD_DIST_HIGH),
{NA, NB} = split(Node),
rpc:cast(Node, net_adm, ping, [OurName]),
receive after 1000 -> ok end,
@@ -315,16 +322,16 @@ simultaneous_md5(Node, OurName, Cookie) when OurName > Node ->
Else2 ->
exit(Else2)
end,
- send_name(SocketA,OurName,5),
+ send_name(SocketA,OurName, ?EPMD_DIST_HIGH),
ok_simultaneous = recv_status(SocketA),
%% Socket B should die during this
case catch begin
- {normal,Node,5} = recv_name(SocketB), % See 1)
+ {normal,Node,?EPMD_DIST_HIGH} = recv_name(SocketB), % See 1)
send_status(SocketB, ok_simultaneous),
MyChallengeB = gen_challenge(),
send_challenge(SocketB, OurName, MyChallengeB,
5),
- HisChallengeB = recv_challenge_reply(
+ {ok,HisChallengeB} = recv_challenge_reply(
SocketB,
MyChallengeB,
Cookie),
@@ -346,7 +353,7 @@ simultaneous_md5(Node, OurName, Cookie) when OurName > Node ->
end,
gen_tcp:close(SocketB),
%% But still Socket A will continue
- {hidden,Node,5,HisChallengeA} = recv_challenge(SocketA), % See 1)
+ {hidden,Node,?EPMD_DIST_HIGH,HisChallengeA} = recv_challenge(SocketA), % See 1)
OurChallengeA = gen_challenge(),
OurDigestA = gen_digest(HisChallengeA, Cookie),
send_challenge_reply(SocketA, OurChallengeA, OurDigestA),
@@ -372,7 +379,7 @@ missing_compulsory_dflags(Config) when is_list(Config) ->
[{active,false},
{packet,2}]),
BadNode = list_to_atom(atom_to_list(Name2)++"@"++atom_to_list(NB)),
- send_name(SocketA,BadNode,5,0),
+ send_name(SocketA,BadNode, ?EPMD_DIST_HIGH, 0),
not_allowed = recv_status(SocketA),
gen_tcp:close(SocketA),
stop_node(Node),
@@ -516,16 +523,16 @@ send_challenge_reply(Socket, Challenge, Digest) ->
recv_challenge_reply(Socket, ChallengeA, Cookie) ->
case gen_tcp:recv(Socket, 0) of
- {ok,[$r,CB3,CB2,CB1,CB0 | SumB]} when length(SumB) == 16 ->
+ {ok,[$r,CB3,CB2,CB1,CB0 | SumB]=Data} when length(SumB) == 16 ->
SumA = gen_digest(ChallengeA, Cookie),
ChallengeB = ?u32(CB3,CB2,CB1,CB0),
if SumB == SumA ->
- ChallengeB;
+ {ok,ChallengeB};
true ->
- ?shutdown(bad_challenge_reply)
+ {error,Data}
end;
- _ ->
- ?shutdown(no_node)
+ Err ->
+ {error,Err}
end.
send_challenge_ack(Socket, Digest) ->
@@ -620,6 +627,13 @@ wait_for_reg_reply(Socket, SoFar) ->
receive
{tcp, Socket, Data0} ->
case SoFar ++ Data0 of
+ [$v, Result, A, B, C, D] ->
+ case Result of
+ 0 ->
+ {alive, Socket, ?u32(A, B, C, D)};
+ _ ->
+ {error, duplicate_name}
+ end;
[$y, Result, A, B] ->
case Result of
0 ->
@@ -640,7 +654,7 @@ wait_for_reg_reply(Socket, SoFar) ->
end.
-register(NodeName, ListenSocket, VLow, VHigh) ->
+register_node(NodeName, ListenSocket, VLow, VHigh) ->
{ok,{_,TcpPort}} = inet:sockname(ListenSocket),
case do_register_node(NodeName, TcpPort, VLow, VHigh) of
{alive, Socket, _Creation} ->
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 3bc8e6e828..747f1d9e1b 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2019. 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.
@@ -58,6 +58,8 @@
-export([ file_info_basic_file/1, file_info_basic_directory/1,
file_info_bad/1, file_info_times/1, file_write_file_info/1,
file_wfi_helpers/1]).
+-export([ file_handle_info_basic_file/1, file_handle_info_basic_directory/1,
+ file_handle_info_times/1]).
-export([rename/1, access/1, truncate/1, datasync/1, sync/1,
read_write/1, pread_write/1, append/1, exclusive/1]).
-export([ e_delete/1, e_rename/1, e_make_dir/1, e_del_dir/1]).
@@ -153,7 +155,10 @@ groups() ->
{pos, [], [pos1, pos2, pos3]},
{file_info, [],
[file_info_basic_file, file_info_basic_directory,
- file_info_bad, file_info_times, file_write_file_info,
+ file_info_bad, file_info_times,
+ file_handle_info_basic_file, file_handle_info_basic_directory,
+ file_handle_info_times,
+ file_write_file_info,
file_wfi_helpers]},
{consult, [], [consult1, path_consult]},
{eval, [], [eval1, path_eval]},
@@ -273,11 +278,11 @@ mini_server(Parent) ->
Parent ! {io_request,From,To,{put_chars,Data}},
From ! {io_reply, To, ok},
mini_server(Parent);
- {io_request,From,To,{get_chars,'',N}} ->
+ {io_request,From,To,{get_chars,_Encoding,'',N}} ->
Parent ! {io_request,From,To,{get_chars,'',N}},
From ! {io_reply, To, {ok, lists:duplicate(N,$a)}},
mini_server(Parent);
- {io_request,From,To,{get_line,''}} ->
+ {io_request,From,To,{get_line,_Encoding,''}} ->
Parent ! {io_request,From,To,{get_line,''}},
From ! {io_reply, To, {ok, "hej\n"}},
mini_server(Parent)
@@ -987,6 +992,14 @@ new_modes(Config) when is_list(Config) ->
ok
end,
+ % open directory
+ {ok, Fd9} = ?FILE_MODULE:open(NewDir, [directory]),
+ ok = ?FILE_MODULE:close(Fd9),
+
+ % open raw directory
+ {ok, Fd10} = ?FILE_MODULE:open(NewDir, [raw, directory]),
+ ok = ?FILE_MODULE:close(Fd10),
+
[] = flush(),
ok.
@@ -1236,6 +1249,9 @@ open_errors(Config) when is_list(Config) ->
{error, E4} = ?FILE_MODULE:open(DataDirSlash, [write]),
{eisdir,eisdir,eisdir,eisdir} = {E1,E2,E3,E4},
+ Real = filename:join(DataDir, "realmen.html"),
+ {error, enotdir} = ?FILE_MODULE:open(Real, [directory]),
+
[] = flush(),
ok.
@@ -1406,7 +1422,8 @@ file_info_basic_directory(Config) when is_list(Config) ->
{win32, _} ->
test_directory("/", read_write),
test_directory("c:/", read_write),
- test_directory("c:\\", read_write);
+ test_directory("c:\\", read_write),
+ test_directory("\\\\localhost\\c$", read_write);
_ ->
test_directory("/", read)
end,
@@ -1538,6 +1555,180 @@ filter_atime(Atime, Config) ->
Atime
end.
+%% Test read_file_info on I/O devices.
+
+file_handle_info_basic_file(Config) when is_list(Config) ->
+ RootDir = proplists:get_value(priv_dir, Config),
+
+ %% Create a short file.
+ Name = filename:join(RootDir,
+ atom_to_list(?MODULE)
+ ++"_basic_test.fil"),
+ {ok,Fd1} = ?FILE_MODULE:open(Name, write),
+ io:put_chars(Fd1, "foo bar"),
+ ok = ?FILE_MODULE:close(Fd1),
+
+ %% Test that the file has the expected attributes.
+ %% The times are tricky, so we will save them to a separate test case.
+
+ {ok, Fd} = ?FILE_MODULE:open(Name, read),
+ {ok,FileInfo} = ?FILE_MODULE:read_file_info(Fd),
+ ok = ?FILE_MODULE:close(Fd),
+
+ {ok, FdRaw} = ?FILE_MODULE:open(Name, [read, raw]),
+ {ok,FileInfoRaw} = ?FILE_MODULE:read_file_info(FdRaw),
+ ok = ?FILE_MODULE:close(FdRaw),
+
+ #file_info{size=Size,type=Type,access=Access,
+ atime=AccessTime,mtime=ModifyTime} = FileInfo = FileInfoRaw,
+ io:format("Access ~p, Modify ~p", [AccessTime, ModifyTime]),
+ Size = 7,
+ Type = regular,
+ read_write = Access,
+ true = abs(time_dist(filter_atime(AccessTime, Config),
+ filter_atime(ModifyTime,
+ Config))) < 5,
+ all_integers(tuple_to_list(AccessTime) ++ tuple_to_list(ModifyTime)),
+
+ [] = flush(),
+ ok.
+
+file_handle_info_basic_directory(Config) when is_list(Config) ->
+ %% Note: filename:join/1 removes any trailing slash,
+ %% which is essential for ?FILE_MODULE:file_info/1 to work on
+ %% platforms such as Windows95.
+ RootDir = filename:join([proplists:get_value(priv_dir, Config)]),
+
+ %% Test that the RootDir directory has the expected attributes.
+ test_directory_handle(RootDir, read_write),
+
+ %% Note that on Windows file systems,
+ %% "/" or "c:/" are *NOT* directories.
+ %% Therefore, test that ?FILE_MODULE:file_info/1 behaves as if they were
+ %% directories.
+ case os:type() of
+ {win32, _} ->
+ test_directory_handle("/", read_write),
+ test_directory_handle("c:/", read_write),
+ test_directory_handle("c:\\", read_write),
+ test_directory_handle("\\\\localhost\\c$", read_write);
+ _ ->
+ test_directory_handle("/", read)
+ end,
+ ok.
+
+test_directory_handle(Name, ExpectedAccess) ->
+ {ok, DirFd} = file:open(Name, [read, directory]),
+ try
+ {ok,FileInfo} = ?FILE_MODULE:read_file_info(DirFd),
+ {ok,FileInfo} = ?FILE_MODULE:read_file_info(DirFd, [raw]),
+ #file_info{size=Size,type=Type,access=Access,
+ atime=AccessTime,mtime=ModifyTime} = FileInfo,
+ io:format("Testing directory ~s", [Name]),
+ io:format("Directory size is ~p", [Size]),
+ io:format("Access ~p", [Access]),
+ io:format("Access time ~p; Modify time~p",
+ [AccessTime, ModifyTime]),
+ Type = directory,
+ Access = ExpectedAccess,
+ all_integers(tuple_to_list(AccessTime) ++ tuple_to_list(ModifyTime)),
+ [] = flush(),
+ ok
+ after
+ file:close(DirFd)
+ end.
+
+%% Test that the file times behave as they should.
+
+file_handle_info_times(Config) when is_list(Config) ->
+ %% We have to try this twice, since if the test runs across the change
+ %% of a month the time diff calculations will fail. But it won't happen
+ %% if you run it twice in succession.
+ test_server:m_out_of_n(
+ 1,2,
+ fun() -> file_handle_info_int(Config) end),
+ ok.
+
+file_handle_info_int(Config) ->
+ %% Note: filename:join/1 removes any trailing slash,
+ %% which is essential for ?FILE_MODULE:file_info/1 to work on
+ %% platforms such as Windows95.
+
+ RootDir = filename:join([proplists:get_value(priv_dir, Config)]),
+ io:format("RootDir = ~p", [RootDir]),
+
+ Name = filename:join(RootDir,
+ atom_to_list(?MODULE)
+ ++"_file_info.fil"),
+ {ok,Fd1} = ?FILE_MODULE:open(Name, write),
+ io:put_chars(Fd1,"foo"),
+ {ok,FileInfo1} = ?FILE_MODULE:read_file_info(Fd1),
+ ok = ?FILE_MODULE:close(Fd1),
+
+ {ok,Fd1Raw} = ?FILE_MODULE:open(Name, [read, raw]),
+ {ok,FileInfo1Raw} = ?FILE_MODULE:read_file_info(Fd1Raw),
+ ok = ?FILE_MODULE:close(Fd1Raw),
+
+ %% We assert that everything but the size is the same, on some OSs the
+ %% size may not have been flushed to disc and we do not want to do a
+ %% sync to force it.
+ FileInfo1Raw = FileInfo1#file_info{ size = FileInfo1Raw#file_info.size },
+
+ #file_info{type=regular,atime=AccTime1,mtime=ModTime1} = FileInfo1,
+
+ Now = erlang:localtime(), %???
+ io:format("Now ~p",[Now]),
+ io:format("Open file Acc ~p Mod ~p",[AccTime1,ModTime1]),
+ true = abs(time_dist(filter_atime(Now, Config),
+ filter_atime(AccTime1,
+ Config))) < 8,
+ true = abs(time_dist(Now,ModTime1)) < 8,
+
+ %% Sleep until we can be sure the seconds value has changed.
+ %% Note: FAT-based filesystem (like on Windows 95) have
+ %% a resolution of 2 seconds.
+ timer:sleep(2200),
+
+ %% close the file, and watch the modify date change
+
+ {ok,Fd2} = ?FILE_MODULE:open(Name, read),
+ {ok,FileInfo2} = ?FILE_MODULE:read_file_info(Fd2),
+ ok = ?FILE_MODULE:close(Fd2),
+
+ {ok,Fd2Raw} = ?FILE_MODULE:open(Name, [read, raw]),
+ {ok,FileInfo2Raw} = ?FILE_MODULE:read_file_info(Fd2Raw),
+ ok = ?FILE_MODULE:close(Fd2Raw),
+
+ #file_info{size=Size,type=regular,access=Access,
+ atime=AccTime2,mtime=ModTime2} = FileInfo2 = FileInfo2Raw,
+ io:format("Closed file Acc ~p Mod ~p",[AccTime2,ModTime2]),
+ true = time_dist(ModTime1,ModTime2) >= 0,
+
+ %% this file is supposed to be binary, so it'd better keep it's size
+ Size = 3,
+ Access = read_write,
+
+ %% Do some directory checking
+
+ {ok,Fd3} = ?FILE_MODULE:open(RootDir, [read, directory]),
+ {ok,FileInfo3} = ?FILE_MODULE:read_file_info(Fd3),
+ ok = ?FILE_MODULE:close(Fd3),
+
+ {ok,Fd3Raw} = ?FILE_MODULE:open(RootDir, [read, directory, raw]),
+ {ok,FileInfo3Raw} = ?FILE_MODULE:read_file_info(Fd3Raw),
+ ok = ?FILE_MODULE:close(Fd3Raw),
+
+ #file_info{size=DSize,type=directory,access=DAccess,
+ atime=AccTime3,mtime=ModTime3} = FileInfo3 = FileInfo3Raw,
+ %% this dir was modified only a few secs ago
+ io:format("Dir Acc ~p; Mod ~p; Now ~p", [AccTime3, ModTime3, Now]),
+ true = abs(time_dist(Now,ModTime3)) < 5,
+ DAccess = read_write,
+ io:format("Dir size is ~p",[DSize]),
+
+ [] = flush(),
+ ok.
+
%% Test the write_file_info/2 function.
file_write_file_info(Config) when is_list(Config) ->
diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl
index 1be016444f..00c9dc5ed5 100644
--- a/lib/kernel/test/gen_tcp_api_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_api_SUITE.erl
@@ -594,10 +594,13 @@ unused_ip() ->
io:format("we = ~p, unused_ip = ~p~n", [Hent, IP]),
IP.
-unused_ip(_, _, _, 255) -> error;
+unused_ip(255, 255, 255, 255) -> error;
+unused_ip(255, B, C, D) -> unused_ip(1, B + 1, C, D);
+unused_ip(A, 255, C, D) -> unused_ip(A, 1, C + 1, D);
+unused_ip(A, B, 255, D) -> unused_ip(A, B, 1, D + 1);
unused_ip(A, B, C, D) ->
case inet:gethostbyaddr({A, B, C, D}) of
- {ok, _} -> unused_ip(A, B, C, D+1);
+ {ok, _} -> unused_ip(A + 1, B, C, D);
{error, _} -> {ok, {A, B, C, D}}
end.
diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl
index 83a94ab087..adbcef955c 100644
--- a/lib/kernel/test/seq_trace_SUITE.erl
+++ b/lib/kernel/test/seq_trace_SUITE.erl
@@ -30,7 +30,7 @@
send/1, distributed_send/1, recv/1, distributed_recv/1,
trace_exit/1, distributed_exit/1, call/1, port/1,
match_set_seq_token/1, gc_seq_token/1, label_capability_mismatch/1,
- send_literal/1]).
+ send_literal/1,inherit_on_spawn/1,spawn_flag/1]).
%% internal exports
-export([simple_tracer/2, one_time_receiver/0, one_time_receiver/1,
@@ -53,7 +53,8 @@ all() ->
distributed_send, recv, distributed_recv, trace_exit,
old_heap_token,
distributed_exit, call, port, match_set_seq_token,
- gc_seq_token, label_capability_mismatch].
+ gc_seq_token, label_capability_mismatch,
+ inherit_on_spawn, spawn_flag].
groups() ->
[].
@@ -83,14 +84,29 @@ token_set_get(Config) when is_list(Config) ->
do_token_set_get(timestamp),
do_token_set_get(monotonic_timestamp),
do_token_set_get(strict_monotonic_timestamp).
-
+
+-define(SEQ_TRACE_SEND, 1). %(1 << 0)
+-define(SEQ_TRACE_RECEIVE, 2). %(1 << 1)
+-define(SEQ_TRACE_PRINT, 4). %(1 << 2)
+-define(SEQ_TRACE_NOW_TIMESTAMP, 8). %(1 << 3)
+-define(SEQ_TRACE_STRICT_MON_TIMESTAMP, 16). %(1 << 4)
+-define(SEQ_TRACE_MON_TIMESTAMP, 32). %(1 << 5)
+-define(SEQ_TRACE_SPAWN, 64). %(1 << 6)
+
do_token_set_get(TsType) ->
- io:format("Testing ~p~n", [TsType]),
+ BaseOpts = ?SEQ_TRACE_SEND bor
+ ?SEQ_TRACE_RECEIVE bor
+ ?SEQ_TRACE_PRINT bor
+ ?SEQ_TRACE_SPAWN,
Flags = case TsType of
- timestamp -> 15;
- strict_monotonic_timestamp -> 23;
- monotonic_timestamp -> 39
- end,
+ timestamp ->
+ BaseOpts bor ?SEQ_TRACE_NOW_TIMESTAMP;
+ strict_monotonic_timestamp ->
+ BaseOpts bor ?SEQ_TRACE_STRICT_MON_TIMESTAMP;
+ monotonic_timestamp ->
+ BaseOpts bor ?SEQ_TRACE_MON_TIMESTAMP
+ end,
+ ct:pal("Type ~p, flags = ~p~n", [TsType, Flags]),
Self = self(),
seq_trace:reset_trace(),
%% Test that initial seq_trace is disabled
@@ -102,6 +118,8 @@ do_token_set_get(TsType) ->
{print,true} = seq_trace:get_token(print),
false = seq_trace:set_token(send,true),
{send,true} = seq_trace:get_token(send),
+ false = seq_trace:set_token(spawn,true),
+ {spawn,true} = seq_trace:get_token(spawn),
false = seq_trace:set_token('receive',true),
{'receive',true} = seq_trace:get_token('receive'),
false = seq_trace:set_token(TsType,true),
@@ -466,8 +484,6 @@ call(Config) when is_list(Config) ->
1 =
erlang:trace(Self, true,
[call, set_on_spawn, {tracer, TrB(pid)}]),
- Label = 17,
- seq_trace:set_token(label, Label), % Token enters here!!
RefB = make_ref(),
Pid2B = spawn_link(
fun() ->
@@ -481,6 +497,12 @@ call(Config) when is_list(Config) ->
RefB = call_tracee_1(RefB),
Pid2B ! {self(), msg, RefB}
end),
+
+ %% The token is set *AFTER* spawning to make sure we're testing that the
+ %% token follows on send and not that it inherits on spawn.
+ Label = 17,
+ seq_trace:set_token(label, Label),
+
Pid1B ! {Self, msg, RefB},
%% The message is passed Self -> Pid1B -> Pid2B -> Self, and the
%% seq_trace token follows invisibly. Traced functions are
@@ -501,6 +523,62 @@ call(Config) when is_list(Config) ->
seq_trace:reset_trace(),
ok.
+%% The token should follow spawn, just like it follows messages.
+inherit_on_spawn(Config) when is_list(Config) ->
+ seq_trace:reset_trace(),
+ start_tracer(),
+
+ Ref = make_ref(),
+ seq_trace:set_token(label,Ref),
+ set_token_flags([send]),
+
+ Self = self(),
+ Other = spawn(fun() -> Self ! {gurka,Ref} end),
+
+ receive {gurka,Ref} -> ok end,
+ seq_trace:reset_trace(),
+
+ [{Ref,{send,_,Other,Self,{gurka,Ref}}, _Ts}] = stop_tracer(1),
+
+ ok.
+
+spawn_flag(Config) when is_list(Config) ->
+ seq_trace:reset_trace(),
+ start_tracer(),
+
+ Ref = make_ref(),
+ seq_trace:set_token(label,Ref),
+ set_token_flags([spawn]),
+
+ Self = self(),
+
+ {serial,{0,0}} = seq_trace:get_token(serial),
+
+ %% The serial number is bumped on spawning (just like message passing), so
+ %% our child should inherit a counter of 1.
+ ProcessA = spawn(fun() ->
+ {serial,{0,1}} = seq_trace:get_token(serial),
+ Self ! {a,Ref}
+ end),
+ receive {a,Ref} -> ok end,
+
+ {serial,{1,2}} = seq_trace:get_token(serial),
+
+ ProcessB = spawn(fun() ->
+ {serial,{2,3}} = seq_trace:get_token(serial),
+ Self ! {b,Ref}
+ end),
+ receive {b,Ref} -> ok end,
+
+ {serial,{3,4}} = seq_trace:get_token(serial),
+
+ seq_trace:reset_trace(),
+
+ [{Ref,{spawn,{0,1},Self,ProcessA,[]}, _Ts},
+ {Ref,{spawn,{2,3},Self,ProcessB,[]}, _Ts}] = stop_tracer(2),
+
+ ok.
+
%% Send trace messages to a port.
port(Config) when is_list(Config) ->
lists:foreach(fun (TsType) -> do_port(TsType, Config) end,
@@ -938,7 +1016,7 @@ stop_tracer(N) when is_integer(N) ->
receive
{tracerlog,Data} ->
Data
- after 1000 ->
+ after 5000 ->
{error,timeout}
end
end.