1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1999-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21-module(ref_SUITE). 22 23-export([all/0, suite/0]). 24-export([wrap_1/1]). 25-export([compare_list/1, compare_ets/1]). 26-export([internal_size/1, external_size/1]). 27 28-export([init_per_testcase/2, end_per_testcase/2]). 29 30-export([loop_ref/1]). 31 32-include_lib("common_test/include/ct.hrl"). 33 34suite() -> 35 [{ct_hooks,[ts_install_cth]}, 36 {timetrap, {minutes, 2}}]. 37 38init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> 39 [{testcase, Func}|Config]. 40 41end_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> 42 ok. 43 44all() -> 45 [wrap_1, compare_list, compare_ets, internal_size, external_size]. 46 47%% Check that refs don't wrap around easily. 48wrap_1(Config) when is_list(Config) -> 49 spawn_link(?MODULE, loop_ref, [self()]), 50 receive 51 done -> 52 ct:fail(wrapfast) 53 after 30000 -> 54 ok 55 end, 56 ok. 57 58loop_ref(Parent) -> 59 Ref0 = make_ref(), 60 loop_ref(Ref0, first, 0), 61 Parent ! done. 62 63loop_ref(R, R, _) -> ok; 64loop_ref(R0, _, N) -> 65 loop_ref(R0, make_ref(), N+1). 66 67%% Check that ref ordering works 68compare_list(Config) when is_list(Config) -> 69 %% Although this test uses external refs, it would apply the same to plain refs 70 ExtRef1 = <<131,114,0,3,100,0,3,110,64,98,3, 0,0,173,156, 0,216,0,4, 0,0,0,0>>, 71 ExtRef2 = <<131,114,0,3,100,0,3,110,64,98,3, 0,1,31,27, 129,4,0,1, 0,0,0,0>>, 72 73 Ref1 = binary_to_term(ExtRef1), %% #Ref<n@b.0.14155780.44444> 74 Ref2 = binary_to_term(ExtRef2), %% #Ref<n@b.0.2164523009.73499> 75 OrderedList = [Ref1, Ref2], 76 OrderedList = lists:sort(OrderedList), 77 ok. 78 79%% This is the scarier case since it makes terms "invisible" in ets or Mnesia 80%% (the underlying fault cause is the same as compare_list/1) 81compare_ets(Config) when is_list(Config) -> 82 W2s = [610350147,899574699,2994196869,686384822,2397690439, 923302211], 83 ExtRefBase = <<131,114,0,3,100,0,3,110,64,98,3>>, 84 ExtRefs = [<<ExtRefBase/binary, 1:32, W2:32, 0:32>> || W2 <- W2s], 85 Refs = [binary_to_term(Bin) || Bin <- ExtRefs], 86 87 Ets = ets:new(refbug, [ordered_set]), 88 ets:insert(Ets, [{Ref,Ref} || Ref <- Refs]), 89 0 = length([R || R <- ets:tab2list(Ets), ets:lookup(Ets, element(1,R)) == []]), 90 ok. 91 92internal_size(Config) when is_list(Config) -> 93 %% Verifies that the range of heap size used for internal references 94 %% matches what the documentation say in the advanced chapter of the 95 %% efficiency guide. Note that the values in the efficiency guide 96 %% also add the word referencing the heap structure. 97 98 %% Ordinary internal reference 99 ORef = check_internal_size(make_ref()), 100 io:format("ORef = ~p~n", [ORef]), 101 102 %% Internal pid reference (reference containing a pid) 103 PRef = check_internal_size(alias()), 104 io:format("PRef = ~p~n", [PRef]), 105 106 %% Internal magic reference 107 MRef = check_internal_size(ets:new(blipp, [])), 108 io:format("MRef = ~p~n", [MRef]), 109 110 ok. 111 112check_internal_size(Ref) when is_reference(Ref), node(Ref) == node() -> 113 case erlang:system_info(wordsize) of 114 4 -> 115 case erts_debug:size(Ref) of 116 Sz when 3 =< Sz, Sz =< 6 -> 117 Sz; 118 Sz -> 119 error({internal_ref_size_out_of_range, Sz}) 120 end; 121 8 -> 122 case erts_debug:size(Ref) of 123 Sz when 3 =< Sz, Sz =< 5 -> 124 Sz; 125 Sz -> 126 error({internal_ref_size_out_of_range, Sz}) 127 end 128 end. 129 130external_size(Config) when is_list(Config) -> 131 %% Verifies that the range of heap size used for external references 132 %% matches what the documentation say in the advanced chapter of the 133 %% efficiency guide. Note that the values in the efficiency guide 134 %% also add the word referencing the heap structure. 135 {ok, Node} = start_node(Config), 136 137 %% Ordinary external reference 138 ORef = check_external_size(erpc:call(Node, fun () -> make_ref() end)), 139 io:format("ORef = ~p~n", [ORef]), 140 141 %% External pid reference (reference containing a pid) (nothing produce 142 %% this yet, but we need to handle it) 143 PRef = check_external_size(erts_test_utils:mk_ext_ref({Node, 4711}, 144 [1, 2, 3, 4, 5])), 145 io:format("PRef = ~p~n", [PRef]), 146 147 148 stop_node(Node), 149 ok. 150 151check_external_size(Ref) when is_reference(Ref) -> 152 case erlang:system_info(wordsize) of 153 4 -> 154 case erts_debug:size(Ref) of 155 Sz when 6 =< Sz, Sz =< 8 -> 156 Sz; 157 Sz -> 158 error({internal_ref_size_out_of_range, Sz}) 159 end; 160 8 -> 161 case erts_debug:size(Ref) of 162 Sz when 5 =< Sz, Sz =< 6 -> 163 Sz; 164 Sz -> 165 error({internal_ref_size_out_of_range, Sz}) 166 end 167 end. 168 169%% Internal stuff... 170 171make_nodename(Config) when is_list(Config) -> 172 list_to_atom(atom_to_list(?MODULE) 173 ++ "-" 174 ++ atom_to_list(proplists:get_value(testcase, Config)) 175 ++ "-" 176 ++ integer_to_list(erlang:system_time(second)) 177 ++ "-" 178 ++ integer_to_list(erlang:unique_integer([positive]))). 179 180start_node(Config) -> 181 start_node(Config, ""). 182 183start_node(Config, Args) when is_list(Config) -> 184 Pa = filename:dirname(code:which(?MODULE)), 185 Name = make_nodename(Config), 186 test_server:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]). 187 188stop_node(Node) -> 189 test_server:stop_node(Node). 190