1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2004-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%%% Purpose : Compiles various modules with tough code 21 22-module(receive_SUITE). 23 24-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 25 init_per_group/2,end_per_group/2, 26 init_per_testcase/2,end_per_testcase/2, 27 export/1,recv/1,coverage/1,otp_7980/1,ref_opt/1, 28 wait/1,recv_in_try/1,double_recv/1]). 29 30-include_lib("common_test/include/ct.hrl"). 31 32init_per_testcase(_Case, Config) -> 33 Config. 34 35end_per_testcase(_Case, _Config) -> 36 ok. 37 38suite() -> 39 [{ct_hooks,[ts_install_cth]}, 40 {timetrap,{minutes,2}}]. 41 42all() -> 43 [{group,p}]. 44 45groups() -> 46 [{p,test_lib:parallel(), 47 [recv,coverage,otp_7980,ref_opt,export,wait, 48 recv_in_try,double_recv]}]. 49 50 51init_per_suite(Config) -> 52 test_lib:recompile(?MODULE), 53 Config. 54 55end_per_suite(_Config) -> 56 ok. 57 58init_per_group(_GroupName, Config) -> 59 Config. 60 61end_per_group(_GroupName, Config) -> 62 Config. 63 64-record(state, {ena = true}). 65 66recv(Config) when is_list(Config) -> 67 Pid = spawn_link(fun() -> loop(#state{}) end), 68 Self = self(), 69 Pid ! {Self,test}, 70 receive 71 {ok,test} -> ok; 72 {error,Other} -> 73 io:format("Got unpexected ~p", [Other]), 74 ct:fail(unexpected) 75 after 10000 -> 76 ct:fail(no_answer) 77 end, 78 receive 79 X -> 80 io:format("Unexpected extra message: ~p", [X]), 81 ct:fail(unexpected) 82 after 10 -> 83 ok 84 end, 85 ok. 86 87loop(S) -> 88 receive 89 _ when S#state.ena == false -> 90 loop(S); 91 {P,test} -> 92 P ! {ok,test}, 93 loop(S); 94 _X -> 95 loop(S) 96 end. 97 98coverage(Config) when is_list(Config) -> 99 do_link(self()), 100 do_unlink(self()), 101 do_monitor_node(node(), true), 102 do_monitor_node(node(), false), 103 do_group_leader(group_leader(), self()), 104 id(node(self())), 105 106 erlang:'!'(self(), {a,10}), 107 self() ! {b,20}, 108 [{a,10},{b,20}] = receive_all(), 109 self() ! {c,42}, 110 receive 111 {c,42} -> 112 ok 113 after infinity -> 114 exit(cant_happen) 115 end, 116 117 self() ! 17, 118 self() ! 19, 119 59 = tuple_to_values(infinity, x), 120 61 = tuple_to_values(999999, x), 121 0 = tuple_to_values(1, x), 122 123 {'EXIT',{{badmap,[]},_}} = (catch monitor_plus_badmap(self())), 124 125 ok. 126 127monitor_plus_badmap(Pid) -> 128 monitor(process, Pid) + []#{}. 129 130receive_all() -> 131 receive 132 Any -> 133 [Any|receive_all()] 134 after 0 -> 135 [] 136 end. 137 138do_monitor_node(Node, Bool) -> 139 monitor_node(Node, Bool). 140 141do_link(Pid) -> 142 link(Pid). 143 144do_unlink(Pid) -> 145 unlink(Pid). 146 147do_group_leader(Leader, Pid) -> 148 group_leader(Leader, Pid). 149 150 151%% cover sys_core_fold:tuple_to_values/2 152tuple_to_values(infinity, X) -> 153 {A,B} = case X of 154 x -> 155 receive 156 Any -> 157 {42,Any} 158 end 159 end, 160 A+B; 161tuple_to_values(Timeout, X) -> 162 {A,B} = case X of 163 x -> 164 receive 165 Any -> 166 {42,Any} 167 after Timeout -> 168 {0,0} 169 end 170 end, 171 A+B. 172 173%% OTP-7980. Thanks to Vincent de Phily. The following code would 174%% be inccorrectly optimized by beam_jump. 175 176otp_7980(Config) when is_list(Config) -> 177 7 = otp_7980_add_clients(10), 178 ok. 179 180otp_7980_add_clients(Count) -> 181 Timeout = 42, 182 lists:foldl(fun(_, N) -> 183 case N of 184 1 -> ok; 185 _ -> receive after Timeout -> ok end 186 end, 187 N - 1 188 end, Count, [1,2,3]). 189 190ref_opt(Config) when is_list(Config) -> 191 case ?MODULE of 192 receive_SUITE -> ref_opt_1(Config); 193 _ -> {skip,"Enough to run this case once."} 194 end. 195 196ref_opt_1(Config) -> 197 DataDir = proplists:get_value(data_dir, Config), 198 PrivDir = proplists:get_value(priv_dir, Config), 199 Sources = filelib:wildcard(filename:join([DataDir,"ref_opt","*.{erl,S}"])), 200 test_lib:p_run(fun(Src) -> 201 do_ref_opt(Src, PrivDir) 202 end, Sources), 203 cover_recv_instructions(), 204 ok. 205 206do_ref_opt(Source, PrivDir) -> 207 try 208 Ext = filename:extension(Source), 209 {ok,Mod} = compile:file(Source, [report_errors,report_warnings, 210 {outdir,PrivDir}] ++ 211 [from_asm || Ext =:= ".S" ]), 212 Base = filename:rootname(filename:basename(Source), Ext), 213 code:purge(list_to_atom(Base)), 214 BeamFile = filename:join(PrivDir, Base), 215 code:load_abs(BeamFile), 216 ok = Mod:Mod(), 217 {beam_file,Mod,_,_,_,Code} = beam_disasm:file(BeamFile), 218 case Base of 219 "no_"++_ -> 220 [] = collect_recv_opt_instrs(Code); 221 "yes_"++_ -> 222 [{recv_mark,{f,L}},{recv_set,{f,L}}] = 223 collect_recv_opt_instrs(Code) 224 end, 225 ok 226 catch Class:Error:Stk -> 227 io:format("~s: ~p ~p\n~p\n", [Source,Class,Error,Stk]), 228 error 229 end. 230 231collect_recv_opt_instrs(Code) -> 232 L = [ [I || I <- Is, 233 begin 234 case I of 235 {recv_mark,{f,_}} -> true; 236 {recv_set,{f,_}} -> true; 237 _ -> false 238 end 239 end] || {function,_,_,_,Is} <- Code], 240 lists:append(L). 241 242cover_recv_instructions() -> 243 %% We want to cover the handling of recv_mark and recv_set in beam_utils. 244 %% Since those instructions are introduced in a late optimization pass, 245 %% beam_utils:live_opt() will not see them unless the compilation is 246 %% started from a .S file. The compile_SUITE:asm/1 test case will 247 %% compile all test suite files to .S and then run them through the 248 %% compiler again. 249 %% 250 %% Here will we will ensure that this modules contains recv_mark 251 %% and recv_set instructions. 252 Pid = spawn_link(fun() -> 253 receive {Parent,Ref} -> 254 Parent ! Ref 255 end 256 end), 257 Ref = make_ref(), 258 Pid ! {self(),Ref}, 259 receive 260 Ref -> ok 261 end. 262 263export(Config) when is_list(Config) -> 264 Ref = make_ref(), 265 self() ! {result,Ref,42}, 266 42 = export_1(Ref), 267 {error,timeout} = export_1(Ref), 268 269 self() ! {result,Ref}, 270 {ok,Ref} = export_2(), 271 272 ok. 273 274export_1(Reference) -> 275 id(Reference), 276 receive 277 {result,Reference,Result} -> 278 Result 279 after 1 -> 280 Result = {error,timeout} 281 end, 282 %% Result ({x,1}) is used, but not the return value ({x,0}) 283 %% of the receive. Used to be incorrectly optimized 284 %% by beam_block. 285 id({build,self()}), 286 Result. 287 288export_2() -> 289 receive {result,Result} -> ok end, 290 {ok,Result}. 291 292wait(Config) when is_list(Config) -> 293 self() ! <<42>>, 294 <<42>> = wait_1(r, 1, 2), 295 {1,2,3} = wait_1(1, 2, 3), 296 {'EXIT',{timeout_value,_}} = (catch receive after [] -> timeout end), 297 ok. 298 299wait_1(r, _, _) -> 300 receive 301 B when byte_size(B) > 0 -> 302 B 303 end; 304%% beam_utils would wrongly assume that wait/1 could fall through 305%% to the next clause. 306wait_1(A, B, C) -> 307 {A,B,C}. 308 309recv_in_try(_Config) -> 310 self() ! {ok,fh}, {ok,fh} = recv_in_try(infinity, native), 311 self() ! {ok,ignored}, {ok,42} = recv_in_try(infinity, plain), 312 self() ! {error,ignored}, nok = recv_in_try(infinity, plain), 313 timeout = recv_in_try(1, plain), 314 ok. 315 316recv_in_try(Timeout, Format) -> 317 try 318 receive 319 {Status,History} -> 320 %% {test,is_tuple,{f,148},[{x,0}]}. 321 %% {test,test_arity,{f,148},[{x,0},2]}. 322 %% {get_tuple_element,{x,0},0,{y,1}}. %y1 is fragile. 323 %% 324 %% %% Here the fragility of y1 would be be progated to 325 %% %% the 'catch' below. Incorrect, since get_tuple_element 326 %% %% can't fail. 327 %% {get_tuple_element,{x,0},1,{x,2}}. 328 %% 329 %% remove_message. %y1 fragility cleared. 330 FH = case Format of 331 native -> 332 id(History); 333 plain -> 334 id(42) 335 end, 336 case Status of 337 ok -> 338 {ok,FH}; 339 error -> 340 nok 341 end 342 after Timeout -> 343 timeout 344 end 345 catch 346 %% The fragility of y1 incorrectly propagated to here. 347 %% beam_validator would complain. 348 throw:{error,Reason} -> 349 {nok,Reason} 350 end. 351 352%% ERL-703. The compiler would crash because beam_utils:anno_defs/1 353%% failed to take into account that code after loop_rec_end is 354%% unreachable. 355 356double_recv(_Config) -> 357 self() ! {more,{a,term}}, 358 ok = do_double_recv({more,{a,term}}, any), 359 self() ! message, 360 ok = do_double_recv(whatever, message), 361 362 error = do_double_recv({more,42}, whatever), 363 error = do_double_recv(whatever, whatever), 364 ok. 365 366do_double_recv({more, Rest}, _Msg) -> 367 receive 368 {more, Rest} -> 369 ok 370 after 0 -> 371 error 372 end; 373do_double_recv(_, Msg) -> 374 receive 375 Msg -> 376 ok 377 after 0 -> 378 error 379 end. 380 381id(I) -> I. 382