aboutsummaryrefslogblamecommitdiffstats
path: root/erts/emulator/test/code_SUITE_data/call_purged_fun_tester.erl
blob: 699f0c11618faee4e1cf38e3c49547a02d45c6a7 (plain) (tree)
1
2
3
4
5
6
7
8



                                


                                          
                             
















                                                                               






                                                
                                                                 
 

                                                          
 
                                                   


                                                         









                                                                                 
 
                                  








                                                        
                                                     
 



                                                   
                                                        
 
                                            


                                                                                      

                                  
                                   
                                                     
                                                                 
                               
 
                                     
 
                                            


                                                                                      
                                  
                                            


                                                                                      

                                  

                                                     
                                                                 


                                                     
                                                                 
                               
 
                            

                           
                                               
                            

                           
                                               
                            

                           
                                               


                     


                                                   
            

                                                       



                    


                                                    
            


                                                   





                                                      







                                          
                  
                        


































                                                               
-module(call_purged_fun_tester).

-export([do/4]).

%% Resurrect line macro when hipe compiled
-ifdef(hipe).
-define(line, put(the_line,?LINE),).
do(Priv, Data, Type, Opts) ->
    try do_it(Priv, Data, Type, Opts)
    catch
        C:E ->
            ST = erlang:get_stacktrace(),
            io:format("Caught exception from line ~p:\n~p\n",
                      [get(the_line), ST]),
            io:format("Message queue: ~p\n", [process_info(self(), messages)]),
            erlang:raise(C, E, ST)
    end.
-else.
-define(line,).
do(P,D,T,O) ->
    do_it(P,D,T,O).
-endif.


do_it(Priv, Data, Type, Opts) ->
    File = filename:join(Data, "my_code_test2"),
    Code = filename:join(Priv, "my_code_test2"),

    catch erlang:purge_module(my_code_test2),
    catch erlang:delete_module(my_code_test2),
    catch erlang:purge_module(my_code_test2),

    ?line {ok,my_code_test2} = c:c(File, [{outdir,Priv} | Opts]),

    ?line IsNative = lists:member(native,Opts),
    ?line IsNative = code:is_module_native(my_code_test2),

    ?line T = ets:new(my_code_test2_fun_table, []),
    ets:insert(T, {my_fun,my_code_test2:make_fun(4711)}),
    ets:insert(T, {my_fun2,my_code_test2:make_fun2()}),

    Papa = self(),
    {P0,M0} = spawn_monitor(fun () ->
                                    [{my_fun2,F2}] = ets:lookup(T, my_fun2),
                                    F2(fun () ->
                                               Papa ! {self(),"going to sleep"},
                                               receive {Papa,"wake up"} -> ok end
                                       end,
                                       fun () -> ok end),
                                    exit(completed)
                            end),

    ?line PurgeType = case Type of
		    code_gone ->
			ok = file:delete(Code++".beam"),
			true;
		    code_reload ->
			true;
		    code_there ->
			false
		end,

    ?line true = erlang:delete_module(my_code_test2),

    ?line ok = receive {P0, "going to sleep"} -> ok
               after 1000 -> timeout
               end,

    ?line Purge = start_purge(my_code_test2, PurgeType),

    ?line {P1, M1} = spawn_monitor(fun () ->
                                           ?line [{my_fun,F}] = ets:lookup(T, my_fun),
                                           ?line 4712 = F(1),
                                           exit(completed)
			     end),

   ?line ok =  wait_until(fun () ->
                                  {status, suspended}
                                      == process_info(P1, status)
                          end),

    ?line ok = continue_purge(Purge),

    ?line {P2, M2} = spawn_monitor(fun () ->
                                           ?line [{my_fun,F}] = ets:lookup(T, my_fun),
                                           ?line 4713 = F(2),
                                           exit(completed)
			     end),
    ?line {P3, M3} = spawn_monitor(fun () ->
                                           ?line [{my_fun,F}] = ets:lookup(T, my_fun),
                                           ?line 4714 = F(3),
                                           exit(completed)
			     end),

    ?line ok = wait_until(fun () ->
                                  {status, suspended}
                                      == process_info(P2, status)
                          end),
    ?line ok = wait_until(fun () ->
                                  {status, suspended}
                                      == process_info(P3, status)
                          end),

    ?line {current_function,
     {erts_code_purger,
      pending_purge_lambda,
      3}} = process_info(P1, current_function),
    ?line {current_function,
     {erts_code_purger,
      pending_purge_lambda,
      3}} = process_info(P2, current_function),
    ?line {current_function,
     {erts_code_purger,
      pending_purge_lambda,
      3}} = process_info(P3, current_function),

    case Type of
	code_there ->
	    ?line false = complete_purge(Purge),
            P0 ! {self(), "wake up"},
            ?line completed = wait_for_down(P0,M0);
	_ ->
	    ?line {true, true} = complete_purge(Purge),
            ?line killed = wait_for_down(P0,M0)
    end,

    case Type of
	code_gone ->
            ?line {undef, _} = wait_for_down(P1,M1),
            ?line {undef, _} = wait_for_down(P2,M2),
            ?line {undef, _} = wait_for_down(P3,M3);
	_ ->
            ?line completed = wait_for_down(P1,M1),
            ?line completed = wait_for_down(P2,M2),
            ?line completed = wait_for_down(P3,M3),
	    catch erlang:purge_module(my_code_test2),
	    catch erlang:delete_module(my_code_test2),
	    catch erlang:purge_module(my_code_test2)
    end,
    ok.

wait_for_down(P,M) ->
    receive
        {'DOWN', M, process, P, Reason} ->
            Reason
    after 1000 ->
            timeout
    end.

wait_until(Fun) ->
    wait_until(Fun, 20).

wait_until(Fun, N) ->
    case {Fun(),N} of
	{true, _} ->
	    ok;
        {false, 0} ->
            timeout;
	{false, _} ->
	    receive after 100 -> ok end,
	    wait_until(Fun, N-1)
    end.

start_purge(Mod, Type) when is_atom(Mod)
			    andalso ((Type == true)
				     orelse (Type == false)) ->
    Ref = make_ref(),
    erts_code_purger ! {test_purge, Mod, self(), Type, Ref},
    receive
	{started, Ref} ->
	    Ref
    end.

continue_purge(Ref) when is_reference(Ref) ->
    erts_code_purger ! {continue, Ref},
    receive
	{continued, Ref} ->
	    ok
    end.

complete_purge(Ref) when is_reference(Ref) ->
    erts_code_purger ! {complete, Ref},
    receive
	{test_purge, Res, Ref} ->
	    Res
    end.