aboutsummaryrefslogblamecommitdiffstats
path: root/erts/emulator/test/after_SUITE.erl
blob: 40fd2e65008444694c299d9a2db5f5245fdc1eff (plain) (tree)
1
2
3
4
5


                   
                                                        
   










                                                                           







                       
                                           
 
                        
                                                         
                                                                    

                                                
 



                       


                                 
 
         

                                                          
                                                              
 



                                                        
                                           

                       
                                                      


                                                   
                                

                                                                               
                                               
                                       
                                          



                                                                           
























































































                                                                                                         
                                        



















                                            
                                        













































                                                                              






















                                                                     
%%
%% %CopyrightBegin%
%% 
%% Copyright Ericsson AB 1997-2011. 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.
%% You may obtain a copy of the License at
%%
%%     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%
%%

-module(after_SUITE).

%% Tests receive after.

-include_lib("common_test/include/ct.hrl").

-export([all/0, suite/0,
	 t_after/1, receive_after/1, receive_after_big/1,
	 receive_after_errors/1, receive_var_zero/1, receive_zero/1,
	 multi_timeout/1, receive_after_32bit/1,
	 receive_after_blast/1]).

%% Internal exports.

-export([timeout_g/0]).

suite() ->
    [{ct_hooks,[ts_install_cth]},
     {timetrap, {minutes, 4}}].

all() -> 
    [t_after, receive_after, receive_after_big,
     receive_after_errors, receive_var_zero, receive_zero,
     multi_timeout, receive_after_32bit, receive_after_blast].

%% Tests for an old round-off error in 'receive after'."
t_after(Config) when is_list(Config) ->
    ?line spawn(fun frequent_process/0),
    ?line Period = test_server:minutes(1),
    ?line Before = erlang:monotonic_time(),
    receive
	after Period ->
		?line After = erlang:monotonic_time(),
		?line report(Period, Before, After)
	end.

report(Period, Before, After) ->
    case erlang:convert_time_unit(After - Before, native, 100*1000) / Period of
	Percent when Percent > 100.10 ->
	    ct:fail({too_inaccurate, Percent});
	Percent when Percent < 100.0 ->
	    ct:fail({too_early, Percent});
	Percent ->
	    Comment = io_lib:format("Elapsed/expected: ~.2f %", [Percent]),
	    {comment, lists:flatten(Comment)}
    end.

frequent_process() ->
    receive
	after 100 ->
		?line frequent_process()
	end.

receive_after(doc) ->
    "Test that 'receive after' works (doesn't hang). "
    "The test takes 10 seconds to complete.";
receive_after(Config) when is_list(Config) ->
    ?line receive_after1(5000).

receive_after1(1) ->
    ?line io:format("Testing: receive after ~p~n", [1]), 
    ?line receive after 1 -> ok end;
receive_after1(N) -> 
    ?line io:format("Testing: receive after ~p~n", [N]), 
    ?line receive after N -> receive_after1(N div 2) end.

receive_after_big(Config) when is_list(Config) ->
    %% Test that 'receive after' with a 32 bit number works.
    receive_after_big1(16#f7654321),
    receive_after_big2().

receive_after_big1(Timeout) ->
    Self = self(),
    erlang:yield(),
    spawn(fun() -> Self ! here_is_a_message end),
    ok = receive
	     here_is_a_message ->
		 ok
	 after Timeout ->
		 %% We test that the timeout can be set,
		 %% not that an timeout occurs after the appropriate delay
		 %% (48 days, 56 minutes, 48 seconds)!
		 timeout
	 end.

receive_after_big2() ->
    Self = self(),
    erlang:yield(),
    spawn(fun() -> Self ! here_is_a_message end),
    ok = receive
	     here_is_a_message ->
		 ok
	 after 16#f7999977 ->
		 %% We only test that the timeout can be set.
		 timeout
	 end.

-define(TryAfter(Timeout), 
	{'EXIT',{timeout_value,_}} = (catch receive mission -> exit(impossible) after Timeout -> ok end),
	{'EXIT',{timeout_value,_}} = (catch receive after Timeout -> ok end),
	try_after(Timeout)).

%% Test error cases for 'receive after'.
receive_after_errors(Config) when is_list(Config) ->
    ?line ?TryAfter(-1),
    ?line ?TryAfter(0.0),
    ?line ?TryAfter(3.14),
    ?line ?TryAfter(16#100000000),
    ?line ?TryAfter(392347129847294724972398472984729847129874),
    ?line ?TryAfter(16#3fffffffffffffff),
    ?line ?TryAfter(16#ffffffffffffffff),
    ?line ?TryAfter(-16#100000000),
    ?line ?TryAfter(-3891278094774921784123987129848),
    ?line ?TryAfter(xxx),
    ok.

try_after(Timeout) ->
    {'EXIT',{timeout_value,_}} = (catch receive after Timeout -> ok end).

receive_var_zero(doc) -> "Test 'after Z', when Z == 0.";
receive_var_zero(Config) when is_list(Config) ->
    self() ! x,
    self() ! y,
    Z = zero(),
    timeout = receive
		  z -> ok
	      after Z -> timeout
	      end,
    timeout = receive
	      after Z -> timeout
	      end,
    self() ! w,
    receive
	x -> ok;
	Other ->
	    ct:fail({bad_message,Other})
    end.

zero() -> 0.

%% Test 'after 0'.
receive_zero(Config) when is_list(Config) ->
    self() ! x,
    self() ! y,
    timeout = receive
		  z -> ok
	      after 0 ->
		      timeout
	      end,
    self() ! w,
    timeout = receive
              after 0 -> timeout
              end,
    receive
	x -> ok;
	Other ->
	    ct:fail({bad_message,Other})
    end.

multi_timeout(doc) ->
    "Test for catching invalid assertion in erl_message.c (in queue_message)."
    "This failed (dumped core) with debug-compiled emulator.";
multi_timeout(Config) when is_list(Config) ->
    ?line P = spawn(?MODULE, timeout_g, []),
    ?line P ! a,
    ?line P ! b,
    ?line receive
	  after 1000 -> ok
	  end,
    ?line P ! c,
    ?line receive
	  after 1000 -> ok
	  end,
    ?line P ! d,
    ok.

timeout_g() ->
    ?line receive
	a -> ok
    end,
    ?line receive
	  after 100000 -> ok
	  end,
    ok.

%% OTP-7493: Timeout for 32 bit numbers (such as 16#ffffFFFF) could
%% timeout at once.
receive_after_32bit(Config) when is_list(Config) ->
    T = 16#ffffFFFF,
    Pids = [spawn_link(fun() -> recv_after_32bit(I, T) end) ||
	       I <- lists:seq(1, 2048)],

    %% Wait two seconds for any of the processes to timeout too early.
    receive after 2000 -> ok end,

    %% Kill the processes.
    [begin unlink(Pid), exit(Pid, kill) end || Pid <- Pids],
    ok.

recv_after_32bit(I, T) when I rem 2 =:= 0 ->
    receive after T -> exit(timeout) end;
recv_after_32bit(_, _) ->
    receive after 16#ffffFFFF -> exit(timeout) end.

blaster() ->
    receive
	{go, TimeoutTime} ->
	    Tmo = TimeoutTime - erlang:monotonic_time(milli_seconds),
	    receive after Tmo -> ok end
    end.

spawn_blasters(0) ->
    [];
spawn_blasters(N) ->
    [spawn_monitor(fun () -> blaster() end)|spawn_blasters(N-1)].

receive_after_blast(Config) when is_list(Config) ->
    PMs = spawn_blasters(10000),
    TimeoutTime = erlang:monotonic_time(milli_seconds) + 5000,
    lists:foreach(fun ({P, _}) -> P ! {go, TimeoutTime} end, PMs),
    lists:foreach(fun ({P, M}) ->
			  receive
			      {'DOWN', M, process, P, normal} ->
				  ok
			  end
		  end, PMs).