1: %%
    2: %% %CopyrightBegin%
    3: %%
    4: %% Copyright Ericsson AB 1997-2013. All Rights Reserved.
    5: %%
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %%
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %%
   17: %% %CopyrightEnd%
   18: %%
   19: 
   20: -module(process_SUITE).
   21: 
   22: %% Tests processes, trapping exit messages and the BIFs:
   23: %% 	exit/1
   24: %%	exit/2
   25: %%	process_info/1,2
   26: %%	register/2 (partially)
   27: 
   28: -include_lib("test_server/include/test_server.hrl").
   29: 
   30: -define(heap_binary_size, 64).
   31: 
   32: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   33: 	 init_per_group/2,end_per_group/2, spawn_with_binaries/1,
   34: 	 t_exit_1/1, t_exit_2_other/1, t_exit_2_other_normal/1,
   35: 	 self_exit/1, normal_suicide_exit/1, abnormal_suicide_exit/1,
   36: 	 t_exit_2_catch/1, trap_exit_badarg/1, trap_exit_badarg_in_bif/1,
   37: 	 exit_and_timeout/1, exit_twice/1,
   38: 	 t_process_info/1, process_info_other/1, process_info_other_msg/1,
   39: 	 process_info_other_dist_msg/1,
   40: 	 process_info_2_list/1, process_info_lock_reschedule/1,
   41: 	 process_info_lock_reschedule2/1,
   42: 	 process_info_lock_reschedule3/1,
   43: 	 bump_reductions/1, low_prio/1, binary_owner/1, yield/1, yield2/1,
   44: 	 process_status_exiting/1,
   45: 	 otp_4725/1, bad_register/1, garbage_collect/1, otp_6237/1,
   46: 	 process_info_messages/1, process_flag_badarg/1, process_flag_heap_size/1,
   47: 	 spawn_opt_heap_size/1,
   48: 	 processes_large_tab/1, processes_default_tab/1, processes_small_tab/1,
   49: 	 processes_this_tab/1, processes_apply_trap/1,
   50: 	 processes_last_call_trap/1, processes_gc_trap/1,
   51: 	 processes_term_proc_list/1,
   52: 	 otp_7738_waiting/1, otp_7738_suspended/1,
   53: 	 otp_7738_resume/1,
   54: 	 garb_other_running/1]).
   55: -export([prio_server/2, prio_client/2]).
   56: 
   57: -export([init_per_testcase/2, end_per_testcase/2]).
   58: 
   59: -export([hangaround/2, processes_bif_test/0, do_processes/1,
   60: 	 processes_term_proc_list_test/1]).
   61: 
   62: suite() -> [{ct_hooks,[ts_install_cth]}].
   63: 
   64: all() -> 
   65:     [spawn_with_binaries, t_exit_1, {group, t_exit_2},
   66:      trap_exit_badarg, trap_exit_badarg_in_bif,
   67:      t_process_info, process_info_other, process_info_other_msg,
   68:      process_info_other_dist_msg, process_info_2_list,
   69:      process_info_lock_reschedule,
   70:      process_info_lock_reschedule2,
   71:      process_info_lock_reschedule3, process_status_exiting,
   72:      bump_reductions, low_prio, yield, yield2, otp_4725,
   73:      bad_register, garbage_collect, process_info_messages,
   74:      process_flag_badarg, process_flag_heap_size,
   75:      spawn_opt_heap_size, otp_6237, {group, processes_bif},
   76:      {group, otp_7738}, garb_other_running].
   77: 
   78: groups() -> 
   79:     [{t_exit_2, [],
   80:       [t_exit_2_other, t_exit_2_other_normal, self_exit,
   81:        normal_suicide_exit, abnormal_suicide_exit,
   82:        t_exit_2_catch, exit_and_timeout, exit_twice]},
   83:      {processes_bif, [],
   84:       [processes_large_tab, processes_default_tab,
   85:        processes_small_tab, processes_this_tab,
   86:        processes_last_call_trap, processes_apply_trap,
   87:        processes_gc_trap, processes_term_proc_list]},
   88:      {otp_7738, [],
   89:       [otp_7738_waiting, otp_7738_suspended,
   90:        otp_7738_resume]}].
   91: 
   92: init_per_suite(Config) ->
   93:     A0 = case application:start(sasl) of
   94: 	     ok -> [sasl];
   95: 	     _ -> []
   96: 	 end,
   97:     A = case application:start(os_mon) of
   98: 	     ok -> [os_mon|A0];
   99: 	     _ -> A0
  100: 	 end,
  101:     [{started_apps, A}|Config].
  102: 
  103: end_per_suite(Config) ->
  104:     As = ?config(started_apps, Config),
  105:     lists:foreach(fun (A) -> application:stop(A) end, As),
  106:     catch erts_debug:set_internal_state(available_internal_state, false),
  107:     Config.
  108: 
  109: init_per_group(_GroupName, Config) ->
  110:     Config.
  111: 
  112: end_per_group(_GroupName, Config) ->
  113:     Config.
  114: 
  115: init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
  116:     Dog=?t:timetrap(?t:minutes(10)),
  117:     [{watchdog, Dog},{testcase, Func}|Config].
  118: 
  119: end_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
  120:     Dog=?config(watchdog, Config),
  121:     ?t:timetrap_cancel(Dog).
  122: 
  123: fun_spawn(Fun) ->
  124:     spawn_link(erlang, apply, [Fun, []]).
  125: 
  126: %% Tests that binaries as arguments to spawn/3 doesn't leak
  127: %% (unclear if this test case will actually prove anything on
  128: %% a modern computer with lots of memory).
  129: spawn_with_binaries(Config) when is_list(Config) ->
  130:     L = lists:duplicate(2048, 42),
  131:     TwoMeg = lists:duplicate(1024, L),
  132:     Fun = fun() -> spawn(?MODULE, binary_owner, [list_to_binary(TwoMeg)]),
  133: 			 receive after 1 -> ok end end,
  134:     Iter = case test_server:purify_is_running() of
  135: 		     true -> 10;
  136: 		     false -> 150
  137: 		 end,
  138:     test_server:do_times(Iter, Fun),
  139:     ok.
  140: 
  141: binary_owner(Bin) when is_binary(Bin) ->
  142:     ok.
  143: 
  144: %% Tests exit/1 with a big message.
  145: t_exit_1(Config) when is_list(Config) ->
  146:     start_spawner(),
  147:     Dog = test_server:timetrap(test_server:seconds(20)),
  148:     process_flag(trap_exit, true),
  149:     test_server:do_times(10, fun t_exit_1/0),
  150:     test_server:timetrap_cancel(Dog),
  151:     stop_spawner(),
  152:     ok.
  153: 
  154: t_exit_1() ->
  155:     Pid = fun_spawn(fun() -> exit(kb_128()) end),
  156:     Garbage = kb_128(),
  157:     receive
  158: 	      {'EXIT', Pid, Garbage} -> ok
  159: 	  end.
  160: 
  161: 
  162: %% Tests exit/2 with a lot of data in the exit message.
  163: t_exit_2_other(Config) when is_list(Config) ->
  164:     start_spawner(),
  165:     Dog = test_server:timetrap(test_server:seconds(20)),
  166:     process_flag(trap_exit, true),
  167:     test_server:do_times(10, fun t_exit_2_other/0),
  168:     test_server:timetrap_cancel(Dog),
  169:     stop_spawner(),
  170:     ok.
  171: 
  172: t_exit_2_other() ->
  173:     Pid = fun_spawn(fun() -> receive x -> ok end end),
  174:     Garbage = kb_128(),
  175:     exit(Pid, Garbage),
  176:     receive
  177: 	      {'EXIT', Pid, Garbage} -> ok
  178: 	  end.
  179: 
  180: %% Tests that exit(Pid, normal) does not kill another process.;
  181: t_exit_2_other_normal(Config) when is_list(Config) ->
  182:     Dog = test_server:timetrap(test_server:seconds(20)),
  183:     process_flag(trap_exit, true),
  184:     Pid = fun_spawn(fun() -> receive x -> ok end end),
  185:     exit(Pid, normal),
  186:     receive
  187: 	      {'EXIT', Pid, Reason} ->
  188: 		  test_server:fail({process_died, Reason})
  189: 	  after 1000 ->
  190: 		  ok
  191: 	  end,
  192:     case process_info(Pid) of
  193: 	      undefined ->
  194: 		  test_server:fail(process_died_on_normal);
  195: 	      List when is_list(List) ->
  196: 		  ok
  197: 	  end,
  198:     exit(Pid, kill),
  199:     test_server:timetrap_cancel(Dog),
  200:     ok.
  201: 
  202: %% Tests that we can trap an exit message sent with exit/2 from
  203: %% the same process.
  204: self_exit(Config) when is_list(Config) ->
  205:     start_spawner(),
  206:     Dog = test_server:timetrap(test_server:seconds(10)),
  207:     process_flag(trap_exit, true),
  208:     test_server:do_times(200, fun self_exit/0),
  209:     test_server:timetrap_cancel(Dog),
  210:     stop_spawner(),
  211:     ok.
  212: 
  213: self_exit() ->
  214:     Garbage = eight_kb(),
  215:     P = self(),
  216:     true = exit(P, Garbage),
  217:     receive
  218: 	      {'EXIT', P, Garbage} -> ok
  219: 	  end.
  220: 
  221: %% Tests exit(self(), normal) is equivalent to exit(normal) for a process
  222: %% that doesn't trap exits.
  223: normal_suicide_exit(Config) when is_list(Config) ->
  224:     process_flag(trap_exit, true),
  225:     Pid = fun_spawn(fun() -> exit(self(), normal) end),
  226:     receive
  227: 	      {'EXIT', Pid, normal} -> ok;
  228: 	      Other -> test_server:fail({bad_message, Other})
  229: 	  end.
  230: 
  231: %% Tests exit(self(), Term) is equivalent to exit(Term) for a process
  232: %% that doesn't trap exits.";
  233: abnormal_suicide_exit(Config) when is_list(Config) ->
  234:     Garbage = eight_kb(),
  235:     process_flag(trap_exit, true),
  236:     Pid = fun_spawn(fun() -> exit(self(), Garbage) end),
  237:     receive
  238: 	      {'EXIT', Pid, Garbage} -> ok;
  239: 	      Other -> test_server:fail({bad_message, Other})
  240: 	  end.
  241: 
  242: %% Tests that exit(self(), die) cannot be catched.
  243: t_exit_2_catch(Config) when is_list(Config) ->
  244:     process_flag(trap_exit, true),
  245:     Pid = fun_spawn(fun() -> catch exit(self(), die) end),
  246:     receive
  247: 	      {'EXIT', Pid, normal} ->
  248: 		  test_server:fail(catch_worked);
  249: 	      {'EXIT', Pid, die} ->
  250: 		  ok;
  251: 	      Other ->
  252: 		  test_server:fail({bad_message, Other})
  253: 	  end.
  254: 
  255: %% Tests trapping of an 'EXIT' message generated by a bad argument to
  256: %% the abs/1 bif.  The 'EXIT' message will intentionally be very big.
  257: trap_exit_badarg(Config) when is_list(Config) ->
  258:     start_spawner(),
  259:     Dog = test_server:timetrap(test_server:seconds(10)),
  260:     process_flag(trap_exit, true),
  261:     test_server:do_times(10, fun trap_exit_badarg/0),
  262:     test_server:timetrap_cancel(Dog),
  263:     stop_spawner(),
  264:     ok.
  265: 
  266: trap_exit_badarg() ->
  267:     Pid = fun_spawn(fun() -> bad_guy(kb_128()) end),
  268:     Garbage = kb_128(),
  269:     receive
  270: 	      {'EXIT',Pid,{badarg,[{erlang,abs,[Garbage],Loc1},
  271: 				   {?MODULE,bad_guy,1,Loc2}|_]}}
  272: 	      when is_list(Loc1), is_list(Loc2) ->
  273: 		  ok;
  274: 	      Other ->
  275: 		  ok = io:format("Bad EXIT message: ~P", [Other, 30]),
  276: 		  test_server:fail(bad_exit_message)
  277: 	  end.
  278: 
  279: bad_guy(Arg) ->
  280:     abs(Arg).
  281: 
  282: 
  283: kb_128() ->
  284:     Eight = eight_kb(),
  285:     {big_binary(),
  286:      Eight, Eight, Eight, Eight, Eight, Eight, Eight, Eight,
  287:      big_binary(),
  288:      Eight, Eight, Eight, Eight, Eight, Eight, Eight, Eight,
  289:      big_binary()}.
  290: 
  291: eight_kb() ->
  292:     B64 = lists:seq(1, 64),
  293:     B512 = {<<1>>,B64,<<2,3>>,B64,make_unaligned_sub_binary(<<4,5,6,7,8,9>>),
  294: 		  B64,make_sub_binary([1,2,3,4,5,6]),
  295: 		  B64,make_sub_binary(lists:seq(1, ?heap_binary_size+1)),
  296: 		  B64,B64,B64,B64,big_binary()},
  297:     lists:duplicate(8, {B512,B512}).
  298: 
  299: big_binary() ->
  300:     big_binary(10, [42]).
  301: big_binary(0, Acc) ->
  302:     list_to_binary(Acc);
  303: big_binary(N, Acc) ->
  304:     big_binary(N-1, [Acc|Acc]).
  305: 
  306: %% Test receiving an EXIT message when spawning a BIF with bad arguments.
  307: trap_exit_badarg_in_bif(Config) when is_list(Config) ->
  308:     Dog = test_server:timetrap(test_server:seconds(10)),
  309:     process_flag(trap_exit, true),
  310:     test_server:do_times(10, fun trap_exit_badarg_bif/0),
  311:     test_server:timetrap_cancel(Dog),
  312:     ok.
  313:     
  314: trap_exit_badarg_bif() ->
  315:     Pid = spawn_link(erlang, node, [1]),
  316:     receive
  317: 	      {'EXIT', Pid, {badarg, _}} ->
  318: 		  ok;
  319: 	      Other ->
  320: 		  test_server:fail({unexpected, Other})
  321: 	  end.
  322: 
  323: %% The following sequences of events have crasched Beam.
  324: %%
  325: %% 1) An exit is sent to a process which is currently not running.
  326: %%    The exit reason will (on purpose) overwrite the message queue
  327: %%    pointer.
  328: %% 2) Before the process is scheduled in, it receives a timeout (from
  329: %%    a 'receive after').
  330: %% 3) The process will crash the next time it executes 'receive'.
  331: 
  332: exit_and_timeout(Config) when is_list(Config) ->
  333:     Dog = test_server:timetrap(test_server:seconds(20)),
  334: 
  335:     process_flag(trap_exit, true),
  336:     Parent = self(),
  337:     Low = fun_spawn(fun() -> eat_low(Parent) end),
  338:     High = fun_spawn(fun() -> eat_high(Low) end),
  339:     eat_wait_for(Low, High),
  340: 
  341:     test_server:timetrap_cancel(Dog),
  342:     ok.
  343: 
  344: 
  345: eat_wait_for(Low, High) ->
  346:     receive
  347: 	{'EXIT', Low, {you, are, dead}} ->
  348: 	    ok;
  349: 	{'EXIT', High, normal} ->
  350: 	    eat_wait_for(Low, High);
  351: 	Other ->
  352: 	    test_server:fail({bad_message, Other})
  353:     end.
  354: 
  355: eat_low(_Parent) ->
  356:     receive
  357:     after 2500 ->
  358: 	    ok
  359:     end,
  360:     receive
  361: 	Any ->
  362: 	    io:format("Received: ~p\n", [Any])
  363:     after 1000 ->
  364: 	    ok
  365:     end.
  366:     
  367: eat_high(Low) ->
  368:     process_flag(priority, high),
  369:     receive after 1000 -> ok end,
  370:     exit(Low, {you, are, dead}),
  371:     {_, Sec, _} = now(),
  372:     loop(Sec, Sec).
  373: 
  374: %% Busy loop for 5 seconds.
  375: 
  376: loop(OrigSec, CurrentSec) when CurrentSec < OrigSec+5 ->
  377:     {_, NewSec, _} = now(),
  378:     loop(OrigSec, NewSec);
  379: loop(_, _) ->
  380:     ok.
  381: 
  382: 
  383: %% Tries to send two different exit messages to a process.
  384: %% (The second one should be ignored.)
  385: exit_twice(Config) when is_list(Config) ->
  386:     Dog = test_server:timetrap(test_server:seconds(20)),
  387: 
  388:     process_flag(trap_exit, true),
  389:     Low = fun_spawn(fun etwice_low/0),
  390:     High = fun_spawn(fun() -> etwice_high(Low) end),
  391:     etwice_wait_for(Low, High),
  392: 
  393:     test_server:timetrap_cancel(Dog),
  394:     ok.
  395: 
  396: etwice_wait_for(Low, High) ->
  397:     receive
  398: 	{'EXIT', Low, first} ->
  399: 	    ok;
  400: 	{'EXIT', Low, Other} ->
  401: 	    test_server:fail({wrong_exit_reason, Other});
  402: 	{'EXIT', High, normal} ->
  403: 	    etwice_wait_for(Low, High);
  404: 	Other ->
  405: 	    test_server:fail({bad_message, Other})
  406:     end.
  407: 
  408: etwice_low() ->
  409:     etwice_low().
  410: 
  411: etwice_high(Low) ->
  412:     process_flag(priority, high),
  413:     exit(Low, first),
  414:     exit(Low, second).
  415: 
  416: %% Tests the process_info/2 BIF.
  417: t_process_info(Config) when is_list(Config) ->
  418:     [] = process_info(self(), registered_name),
  419:     register(my_name, self()),
  420:     {registered_name, my_name} = process_info(self(), registered_name),
  421:     {status, running} = process_info(self(), status),
  422:     {min_heap_size, 233} = process_info(self(), min_heap_size),
  423:     {min_bin_vheap_size,46422} = process_info(self(), min_bin_vheap_size),
  424:     {current_function,{?MODULE,t_process_info,1}} =
  425: 	process_info(self(), current_function),
  426:     {current_function,{?MODULE,t_process_info,1}} =
  427: 	apply(erlang, process_info, [self(),current_function]),
  428: 
  429:     %% current_location and current_stacktrace
  430:     {Line1,Res1} = {?LINE,process_info(self(), current_location)},
  431:     verify_loc(Line1, Res1),
  432:     {Line2,Res2} = {?LINE,apply(erlang, process_info,
  433: 				[self(),current_location])},
  434:     verify_loc(Line2, Res2),
  435:     pi_stacktrace([{?MODULE,t_process_info,1,?LINE}]),
  436: 
  437:     Gleader = group_leader(),
  438:     {group_leader, Gleader} = process_info(self(), group_leader),
  439:     {'EXIT',{badarg,_Info}} = (catch process_info('not_a_pid')),
  440:     ok.
  441: 
  442: pi_stacktrace(Expected0) ->
  443:     {Line,Res} = {?LINE,erlang:process_info(self(), current_stacktrace)},
  444:     {current_stacktrace,Stack} = Res,
  445:     Expected = [{?MODULE,pi_stacktrace,1,Line}|Expected0],
  446:     pi_stacktrace_1(Stack, Expected).
  447: 
  448: pi_stacktrace_1([{M,F,A,Loc}|Stk], [{M,F,A,Line}|Exp]) ->
  449:     case Loc of
  450: 	[] ->
  451: 	    %% No location info for some reason (+L, native code).
  452: 	    io:format("Missing location information for ~w:~w/~w",
  453: 		      [M,F,A]),
  454: 	    ok;
  455: 	[_|_] ->
  456: 	    Line = proplists:get_value(line, Loc),
  457: 	    File = proplists:get_value(file, Loc),
  458: 	    File = ?MODULE_STRING ++ ".erl"
  459:     end,
  460:     pi_stacktrace_1(Stk, Exp);
  461: pi_stacktrace_1([_|_], []) -> ok.
  462: 
  463: verify_loc(Line, {current_location,{?MODULE,t_process_info=F,1=A,Loc}}) ->
  464:     case Loc of
  465: 	[] ->
  466: 	    %% No location info for some reason (+L, native code).
  467: 	    io:format("Missing location information for ~w:~w/~w",
  468: 		      [?MODULE,F,A]),
  469: 	    ok;
  470: 	[_|_] ->
  471: 	    Line = proplists:get_value(line, Loc),
  472: 	    File = proplists:get_value(file, Loc),
  473: 	    File = ?MODULE_STRING ++ ".erl"
  474:     end.
  475: 
  476: process_info_other(Config) when is_list(Config) ->
  477:     Self = self(),
  478:     Pid = spawn_link(fun() -> process_info_looper(Self) end),
  479:     receive after 1 -> ok end,
  480:     pio_current_location(10000, Pid, 0, 0),
  481:     pio_current_stacktrace().
  482: 
  483: pio_current_location(0, _, Pi, Looper) ->
  484:     io:format("~w call(s) to erlang:process_info/2", [Pi]),
  485:     io:format("~w call(s) to ~w:process_info_looper/1", [Looper,?MODULE]);
  486: pio_current_location(N, Pid, Pi, Looper) ->
  487:     erlang:yield(),
  488:     {current_location,Where} = process_info(Pid, current_location),
  489:     case Where of
  490: 	{erlang,process_info,2,[]} ->
  491: 	    pio_current_location(N-1, Pid, Pi+1, Looper);
  492: 	{?MODULE,process_info_looper,1,Loc} when is_list(Loc) ->
  493: 	    pio_current_location(N-1, Pid, Pi, Looper+1)
  494:     end.
  495: 
  496: pio_current_stacktrace() ->
  497:     L = [begin
  498: 	     {current_stacktrace,Stk} = process_info(P, current_stacktrace),
  499: 	     {P,Stk}
  500: 	 end || P <- processes()],
  501:     [erlang:garbage_collect(P) || {P,_} <- L],
  502:     erlang:garbage_collect(),
  503:     [verify_stacktrace(Stk) || {_,Stk} <- L],
  504:     ok.
  505: 
  506: verify_stacktrace([{M,F,A,Loc}|T])
  507:   when is_atom(M),
  508:        is_atom(F),
  509:        is_integer(A),
  510:        is_list(Loc) ->
  511:     verify_stacktrace(T);
  512: verify_stacktrace([]) -> ok.
  513: 
  514: process_info_looper(Parent) ->
  515:     process_info(Parent, current_location),
  516:     process_info_looper(Parent).
  517: 
  518: %% Tests the process_info/1 BIF on another process with messages.
  519: process_info_other_msg(Config) when is_list(Config) ->
  520:     Self = self(),
  521:     Pid = spawn_link(fun() -> other_process(Self) end),
  522:     receive
  523: 	{go_ahead,Pid} -> ok
  524:     end,
  525: 
  526:     Own = {my,own,message},
  527: 
  528:     {messages,[Own]} = process_info(Pid, messages),
  529:     
  530:     Garbage = kb_128(),
  531:     MsgA = {a,Garbage},
  532:     MsgB = {b,Garbage},
  533:     MsgC = {c,Garbage},
  534:     MsgD = {d,Garbage},
  535:     MsgE = {e,Garbage},
  536: 
  537:     Pid ! MsgA,
  538:     {messages,[Own,MsgA]} = process_info(Pid, messages),
  539:     Pid ! MsgB,
  540:     {messages,[Own,MsgA,MsgB]} = process_info(Pid, messages),
  541:     Pid ! MsgC,
  542:     {messages,[Own,MsgA,MsgB,MsgC]} = process_info(Pid, messages),
  543:     Pid ! MsgD,
  544:     {messages,[Own,MsgA,MsgB,MsgC,MsgD]} = process_info(Pid, messages),
  545:     Pid ! MsgE,
  546:     {messages,[Own,MsgA,MsgB,MsgC,MsgD,MsgE]=All} = process_info(Pid, messages),
  547:     {memory,BytesOther} = process_info(Pid, memory),
  548:     {memory,BytesSelf} = process_info(self(), memory),
  549: 
  550:     io:format("Memory ~p: ~p\n", [Pid,BytesOther]),
  551:     io:format("Memory ~p (self): ~p\n", [self(),BytesSelf]),
  552: 
  553:     [Own,MsgA,MsgB,MsgC,MsgD,MsgE] = All,
  554: 
  555:     Pid ! {self(),empty},
  556:     receive
  557: 	      empty -> ok
  558: 	  end,
  559:     {messages,[]} = process_info(Pid, messages),
  560: 
  561:     {min_heap_size, 233} = process_info(Pid, min_heap_size),
  562:     {min_bin_vheap_size, 46422} = process_info(Pid, min_bin_vheap_size),
  563: 
  564:     Pid ! stop,
  565:     ok.
  566: 
  567: process_info_other_dist_msg(Config) when is_list(Config) ->
  568:     %%
  569:     %% Check that process_info can handle messages that have not been
  570:     %% decoded yet.
  571:     %%
  572:     {ok, Node} = start_node(Config),
  573:     Self = self(),
  574:     Pid = spawn_link(fun() -> other_process(Self) end),
  575:     receive {go_ahead,Pid} -> ok end,
  576: 
  577:     Own = {my,own,message},
  578: 
  579:     {messages,[Own]} = process_info(Pid, messages),
  580:     Garbage = kb_128(),
  581:     MsgA = {a,self(),Garbage},
  582:     MsgB = {b,self(),Garbage},
  583:     MsgC = {c,self(),Garbage},
  584:     MsgD = {d,self(),Garbage},
  585:     MsgE = {e,self(),Garbage},
  586: 
  587:     %% We don't want the other process to decode messages itself
  588:     %% therefore we suspend it.
  589:     true =  erlang:suspend_process(Pid),
  590:     spawn_link(Node, fun () ->
  591: 		Pid  ! MsgA,
  592: 		Pid  ! MsgB,
  593: 		Pid  ! MsgC,
  594: 		Self ! check_abc
  595: 	end),
  596:     receive check_abc -> ok end,
  597:     [{status,suspended},
  598: 	{messages,[Own,MsgA,MsgB,MsgC]},
  599: 	{status,suspended}]= process_info(Pid, [status,messages,status]),
  600:     spawn_link(Node, fun () ->
  601: 		Pid  ! MsgD,
  602: 		Pid  ! MsgE,
  603: 		Self ! check_de
  604: 	end),
  605:     receive check_de -> ok end,
  606:     {messages,[Own,MsgA,MsgB,MsgC,MsgD,MsgE]=All} = process_info(Pid, messages),
  607:     true = erlang:resume_process(Pid),
  608:     Pid ! {self(), get_all_messages},
  609:     receive
  610: 	      {all_messages, AllMsgs} ->
  611: 		  All = AllMsgs
  612: 	  end,
  613:     {messages,[]} = process_info(Pid, messages),
  614:     Pid ! stop,
  615:     stop_node(Node),
  616:     ok.
  617:     
  618: 
  619: other_process(Parent) ->
  620:     self() ! {my,own,message},
  621:     Parent ! {go_ahead,self()},
  622:     other_process_1().
  623: 
  624: other_process_1() ->
  625:     receive
  626: 	{Parent,get_all_messages} ->
  627: 	    Parent ! {all_messages, get_all_messages()},
  628: 	    other_process_1();
  629: 	{Parent,empty} ->
  630: 	    receive_all(),
  631: 	    Parent ! empty,
  632: 	    other_process_1();
  633: 	stop -> ok
  634:     end.
  635: 
  636: get_all_messages() ->
  637:     get_all_messages([]).
  638: 
  639: get_all_messages(Msgs) ->
  640:     receive
  641: 	Msg ->
  642: 	    get_all_messages([Msg|Msgs])
  643:     after 0 ->
  644: 	    lists:reverse(Msgs)
  645:     end.
  646: 
  647: receive_all() ->
  648:     receive
  649: 	_ -> receive_all()
  650:     after 0 -> ok
  651:     end.
  652: 
  653: chk_pi_order([],[]) ->
  654:     ok;
  655: chk_pi_order([{Arg, _}| Values], [Arg|Args]) ->
  656:     chk_pi_order(Values, Args).
  657: 
  658: process_info_2_list(doc) ->
  659:     [];
  660: process_info_2_list(suite) ->
  661:     [];
  662: process_info_2_list(Config) when is_list(Config) ->
  663:     Proc = spawn(fun () -> receive after infinity -> ok end end),
  664:     register(process_SUITE_process_info_2_list1, self()),
  665:     register(process_SUITE_process_info_2_list2, Proc),
  666:     erts_debug:set_internal_state(available_internal_state,true),
  667:     AllArgs = erts_debug:get_internal_state(process_info_args),
  668:     A1 = lists:sort(AllArgs) ++ [status] ++ lists:reverse(AllArgs),
  669: 
  670:     %% Verify that argument is accepted as single atom
  671:     lists:foreach(fun (A) ->
  672: 		{A, _} = process_info(Proc, A),
  673: 		{A, _} = process_info(self(), A)
  674: 	end, A1),
  675: 
  676:     %% Verify that order is preserved
  677:     ok = chk_pi_order(process_info(self(), A1), A1),
  678:     ok = chk_pi_order(process_info(Proc, A1), A1),
  679: 
  680:     %% Small arg list
  681:     A2 = [status, stack_size, trap_exit, priority],
  682:     [{status, _}, {stack_size, _}, {trap_exit, _}, {priority, _}]
  683: 	= process_info(Proc, A2),
  684:     [{status, _}, {stack_size, _}, {trap_exit, _}, {priority, _}]
  685: 	= process_info(self(), A2),
  686: 
  687:     %% Huge arg list (note values are shared)
  688:     A3 = lists:duplicate(5000,backtrace),
  689:     V3 = process_info(Proc, A3),
  690:     5000 = length(V3),
  691:     lists:foreach(fun ({backtrace, _}) -> ok end, V3),
  692:     ok.
  693:     
  694: process_info_lock_reschedule(doc) ->
  695:     [];
  696: process_info_lock_reschedule(suite) ->
  697:     [];
  698: process_info_lock_reschedule(Config) when is_list(Config) ->
  699:     %% We need a process that is running and an item that requires
  700:     %% process_info to take the main process lock.
  701:     Target1 = spawn_link(fun tok_loop/0),
  702:     Name1 = process_info_lock_reschedule_running,
  703:     register(Name1, Target1),
  704:     Target2 = spawn_link(fun () -> receive after infinity -> ok end end),
  705:     Name2 = process_info_lock_reschedule_waiting,
  706:     register(Name2, Target2),
  707:     PI = fun(_) ->
  708: 	    erlang:yield(),
  709: 	    [{registered_name, Name1}] = process_info(Target1, [registered_name]),
  710: 	    [{registered_name, Name2}] = process_info(Target2, [registered_name]),
  711: 	    erlang:yield(),
  712: 	    {registered_name, Name1} = process_info(Target1, registered_name),
  713: 	    {registered_name, Name2} = process_info(Target2, registered_name),
  714: 	    erlang:yield(),
  715: 	    [{registered_name, Name1}| _] = process_info(Target1),
  716: 	    [{registered_name, Name2}| _] = process_info(Target2)
  717:     end,
  718:     lists:foreach(PI, lists:seq(1,1000)),
  719:     %% Make sure Target1 still is willing to "tok loop"
  720:     case process_info(Target1, status) of
  721: 	{status, OkStatus} when OkStatus == runnable;
  722: 				OkStatus == running;
  723: 				OkStatus == garbage_collecting ->
  724: 	    unlink(Target1),
  725: 	    unlink(Target2),
  726: 	    exit(Target1, bang),
  727: 	    exit(Target2, bang),
  728: 	    OkStatus;
  729: 	{status, BadStatus} ->
  730: 	    ?t:fail(BadStatus)
  731:     end.
  732: 
  733: pi_loop(_Name, _Pid, 0) ->
  734:     ok;
  735: pi_loop(Name, Pid, N) ->
  736:     {registered_name, Name} = process_info(Pid, registered_name),
  737:     pi_loop(Name, Pid, N-1).
  738: 
  739: process_info_lock_reschedule2(doc) ->
  740:     [];
  741: process_info_lock_reschedule2(suite) ->
  742:     [];
  743: process_info_lock_reschedule2(Config) when is_list(Config) ->
  744:     Parent = self(),
  745:     Fun = fun () ->
  746: 	    receive {go, Name, Pid} -> ok end,
  747: 	    pi_loop(Name, Pid, 10000),
  748: 	    Parent ! {done, self()},
  749: 	    receive after infinity -> ok end
  750:     end,
  751:     P1 = spawn_link(Fun),
  752:     N1 = process_info_lock_reschedule2_1,
  753:     true = register(N1, P1),
  754:     P2 = spawn_link(Fun),
  755:     N2 = process_info_lock_reschedule2_2,
  756:     true = register(N2, P2),
  757:     P3 = spawn_link(Fun),
  758:     N3 = process_info_lock_reschedule2_3,
  759:     true = register(N3, P3),
  760:     P4 = spawn_link(Fun),
  761:     N4 = process_info_lock_reschedule2_4,
  762:     true = register(N4, P4),
  763:     P5 = spawn_link(Fun),
  764:     N5 = process_info_lock_reschedule2_5,
  765:     true = register(N5, P5),
  766:     P6 = spawn_link(Fun),
  767:     N6 = process_info_lock_reschedule2_6,
  768:     true = register(N6, P6),
  769:     P1 ! {go, N2, P2},
  770:     P2 ! {go, N1, P1},
  771:     P3 ! {go, N1, P1},
  772:     P4 ! {go, N1, P1},
  773:     P5 ! {go, N6, P6},
  774:     P6 ! {go, N5, P5},
  775:     receive {done, P1} -> ok end,
  776:     receive {done, P2} -> ok end,
  777:     receive {done, P3} -> ok end,
  778:     receive {done, P4} -> ok end,
  779:     receive {done, P5} -> ok end,
  780:     receive {done, P6} -> ok end,
  781:     unlink(P1), exit(P1, bang),
  782:     unlink(P2), exit(P2, bang),
  783:     unlink(P3), exit(P3, bang),
  784:     unlink(P4), exit(P4, bang),
  785:     unlink(P5), exit(P5, bang),
  786:     unlink(P6), exit(P6, bang),
  787:     ok.
  788: 
  789: many_args(0,_B,_C,_D,_E,_F,_G,_H,_I,_J) ->
  790:     ok;
  791: many_args(A,B,C,D,E,F,G,H,I,J) ->
  792:     many_args(A-1,B,C,D,E,F,G,H,I,J).
  793: 
  794: do_pi_msg_len(PT, AT) ->
  795:     lists:map(fun (_) -> ok end, [a,b,c,d]),
  796:     {message_queue_len, _} = process_info(element(2,PT), element(2,AT)).
  797:     
  798: process_info_lock_reschedule3(doc) ->
  799:     [];
  800: process_info_lock_reschedule3(suite) ->
  801:     [];
  802: process_info_lock_reschedule3(Config) when is_list(Config) ->
  803:     %% We need a process that is running and an item that requires
  804:     %% process_info to take the main process lock.
  805:     Target1 = spawn_link(fun tok_loop/0),
  806:     Name1 = process_info_lock_reschedule_running,
  807:     register(Name1, Target1),
  808:     Target2 = spawn_link(fun () -> receive after infinity -> ok end end),
  809:     Name2 = process_info_lock_reschedule_waiting,
  810:     register(Name2, Target2),
  811:     PI = fun(N) ->
  812: 	    case N rem 10 of
  813: 		0 -> erlang:yield();
  814: 		_ -> ok
  815: 	    end,
  816: 	    do_pi_msg_len({proc, Target1},
  817: 		{arg, message_queue_len})
  818:     end,
  819:     many_args(100000,1,2,3,4,5,6,7,8,9),
  820:     lists:foreach(PI, lists:seq(1,1000000)),
  821:     %% Make sure Target1 still is willing to "tok loop"
  822:     case process_info(Target1, status) of
  823: 	      {status, OkStatus} when OkStatus == runnable;
  824: 				      OkStatus == running;
  825: 				      OkStatus == garbage_collecting ->
  826: 		  unlink(Target1),
  827: 		  unlink(Target2),
  828: 		  exit(Target1, bang),
  829: 		  exit(Target2, bang),
  830: 		  OkStatus;
  831: 	      {status, BadStatus} ->
  832: 		  ?t:fail(BadStatus)
  833: 	  end.
  834: 
  835: process_status_exiting(Config) when is_list(Config) ->
  836:     %% Make sure that erts_debug:get_internal_state({process_status,P})
  837:     %% returns exiting if it is in status P_EXITING.
  838:     erts_debug:set_internal_state(available_internal_state,true),
  839:     Prio = process_flag(priority, max),
  840:     P = spawn_opt(fun () -> receive after infinity -> ok end end,
  841: 			[{priority, normal}]),
  842:     erlang:yield(),
  843:     %% The tok_loop processes are here to make it hard for the exiting
  844:     %% process to be scheduled in for exit...
  845:     TokLoops = lists:map(fun (_) ->
  846: 		spawn_opt(fun tok_loop/0,
  847: 		    [link,{priority, high}])
  848: 	end, lists:seq(1, erlang:system_info(schedulers_online))),
  849:     exit(P, boom),
  850:     wait_until(fun() ->
  851: 		exiting =:= erts_debug:get_internal_state({process_status,P})
  852: 	end),
  853:     lists:foreach(fun (Tok) -> unlink(Tok), exit(Tok,bang) end, TokLoops),
  854:     process_flag(priority, Prio),
  855:     ok.
  856: 
  857: otp_4725(Config) when is_list(Config) ->
  858:     Tester = self(),
  859:     Ref1 = make_ref(),
  860:     Pid1 = spawn_opt(fun () ->
  861: 		Tester ! {Ref1, process_info(self())},
  862: 		receive
  863: 		    Ref1 -> bye
  864: 		end
  865: 	end, [link, {priority, max}, {fullsweep_after, 600}]),
  866:     receive
  867: 	{Ref1, ProcInfo1A} ->
  868: 	    ProcInfo1B = process_info(Pid1),
  869: 	    Pid1 ! Ref1,
  870: 	    check_proc_infos(ProcInfo1A, ProcInfo1B)
  871:     end,
  872:     Ref2 = make_ref(),
  873:     Pid2 = spawn_opt(fun () ->
  874: 		Tester ! {Ref2, process_info(self())},
  875: 		receive
  876: 		    Ref2 -> bye
  877: 		end
  878: 	end,
  879: 	[]),
  880:     receive
  881: 	{Ref2, ProcInfo2A} ->
  882: 	    ProcInfo2B = process_info(Pid2),
  883: 	    Pid2 ! Ref2,
  884: 	    check_proc_infos(ProcInfo2A, ProcInfo2B)
  885:     end,
  886:     ok.
  887: 
  888: check_proc_infos(A, B) ->
  889:     IC = lists:keysearch(initial_call, 1, A),
  890:     IC = lists:keysearch(initial_call, 1, B),
  891: 
  892:     L = lists:keysearch(links, 1, A),
  893:     L = lists:keysearch(links, 1, B),
  894: 
  895:     D = lists:keysearch(dictionary, 1, A),
  896:     D = lists:keysearch(dictionary, 1, B),
  897: 
  898:     TE = lists:keysearch(trap_exit, 1, A),
  899:     TE = lists:keysearch(trap_exit, 1, B),
  900: 
  901:     EH = lists:keysearch(error_handler, 1, A),
  902:     EH = lists:keysearch(error_handler, 1, B),
  903: 
  904:     P = lists:keysearch(priority, 1, A),
  905:     P = lists:keysearch(priority, 1, B),
  906: 
  907:     GL = lists:keysearch(group_leader, 1, A),
  908:     GL = lists:keysearch(group_leader, 1, B),
  909: 
  910:     GC = lists:keysearch(garbage_collection, 1, A),
  911:     GC = lists:keysearch(garbage_collection, 1, B),
  912: 
  913:     ok.
  914: 
  915: 
  916: %% Dummies.
  917: 
  918: start_spawner() ->
  919:     ok.
  920: 
  921: stop_spawner() ->
  922:     ok.
  923: 
  924: %% Tests erlang:bump_reductions/1.
  925: bump_reductions(Config) when is_list(Config) ->
  926:     erlang:garbage_collect(),
  927:     receive after 1 -> ok end,		% Clear reductions.
  928:     {reductions,R1} = process_info(self(), reductions),
  929:     true = erlang:bump_reductions(100),
  930:     {reductions,R2} = process_info(self(), reductions),
  931:     case R2-R1 of
  932: 	      Diff when Diff < 100 ->
  933: 		  ok = io:format("R1 = ~w, R2 = ~w", [R1, R2]),
  934: 		  test_server:fail({small_diff, Diff});
  935: 	      Diff when Diff > 110 ->
  936: 		  ok = io:format("R1 = ~w, R2 = ~w", [R1, R2]),
  937: 		  test_server:fail({big_diff, Diff});
  938: 	      Diff ->
  939: 		  io:format("~p\n", [Diff]),
  940: 		  ok
  941: 	  end,
  942: 
  943:     %% Make sure that a bignum reduction doesn't crash the emulator (32-bit CPU).
  944:     bump_big(R2, 16#08000000).
  945: 
  946: bump_big(Prev, Limit) ->
  947:     true = erlang:bump_reductions(100000), %Limited to CONTEXT_REDUCTIONS.
  948:     case process_info(self(), reductions) of
  949: 	      {reductions,Big} when is_integer(Big), Big > Limit ->
  950: 		  erlang:garbage_collect(),
  951: 		  io:format("~p\n", [Big]);
  952: 	      {reductions,R} when is_integer(R), R > Prev ->
  953: 		  bump_big(R, Limit)
  954: 	  end,
  955:     ok.
  956: 
  957: %% Priority 'low' should be mixed with 'normal' using a factor of
  958: %% about 8. (OTP-2644)
  959: low_prio(Config) when is_list(Config) ->
  960:     case erlang:system_info(schedulers_online) of
  961: 	1 ->
  962: 	    ok = low_prio_test(Config);
  963: 	_ -> 
  964: 	    erlang:system_flag(multi_scheduling, block),
  965: 	    ok = low_prio_test(Config),
  966: 	    erlang:system_flag(multi_scheduling, unblock),
  967: 	    {comment,
  968: 		   "Test not written for SMP runtime system. "
  969: 		   "Multi scheduling blocked during test."}
  970:     end.
  971: 
  972: low_prio_test(Config) when is_list(Config) ->
  973:     process_flag(trap_exit, true),
  974:     S = spawn_link(?MODULE, prio_server, [0, 0]),
  975:     PCs = spawn_prio_clients(S, erlang:system_info(schedulers_online)),
  976:     timer:sleep(2000),
  977:     lists:foreach(fun (P) -> exit(P, kill) end, PCs),
  978:     S ! exit,
  979:     receive {'EXIT', S, {A, B}} -> check_prio(A, B) end,
  980:     ok.
  981: 
  982: check_prio(A, B) ->
  983:     Prop = A/B,
  984:     ok = io:format("Low=~p, High=~p, Prop=~p\n", [A, B, Prop]),
  985: 
  986:     %% It isn't 1/8, it's more like 0.3, but let's check that
  987:     %% the low-prio processes get some little chance to run at all.
  988:     true = (Prop < 1.0),
  989:     true = (Prop > 1/32).
  990: 
  991: prio_server(A, B) ->
  992:     receive
  993: 	low ->
  994: 	    prio_server(A+1, B);
  995: 	normal ->
  996: 	    prio_server(A, B+1);
  997: 	exit ->
  998: 	    exit({A, B})
  999:     end.
 1000: 
 1001: spawn_prio_clients(_, 0) ->
 1002:     [];
 1003: spawn_prio_clients(S, N) ->
 1004:     [spawn_opt(?MODULE, prio_client, [S, normal], [link, {priority,normal}]),
 1005:      spawn_opt(?MODULE, prio_client, [S, low], [link, {priority,low}])
 1006:      | spawn_prio_clients(S, N-1)].
 1007: 
 1008: prio_client(S, Prio) ->
 1009:     S ! Prio,
 1010:     prio_client(S, Prio).
 1011: 
 1012: make_sub_binary(Bin) when is_binary(Bin) ->
 1013:     {_,B} = split_binary(list_to_binary([0,1,3,Bin]), 3),
 1014:     B;
 1015: make_sub_binary(List) ->
 1016:     make_sub_binary(list_to_binary(List)).
 1017: 
 1018: make_unaligned_sub_binary(Bin0) ->
 1019:     Bin1 = <<0:3,Bin0/binary,31:5>>,
 1020:     Sz = size(Bin0),
 1021:     <<0:3,Bin:Sz/binary,31:5>> = id(Bin1),
 1022:     Bin.
 1023: 
 1024: yield(doc) ->
 1025:     "Tests erlang:yield/1.";
 1026: yield(Config) when is_list(Config) ->
 1027:     case catch erlang:system_info(modified_timing_level) of
 1028: 	Level when is_integer(Level) ->
 1029: 	    {skipped,
 1030: 	     "Modified timing (level " ++ integer_to_list(Level)
 1031: 	     ++ ") is enabled. Testcase gets messed up by modfied "
 1032: 	     "timing."};
 1033: 	_ ->
 1034: 	    MS = erlang:system_flag(multi_scheduling, block),
 1035: 	    yield_test(),
 1036: 	    erlang:system_flag(multi_scheduling, unblock),
 1037: 	    case MS of
 1038: 		blocked ->
 1039: 		    {comment,
 1040: 		     "Multi-scheduling blocked during test. This test-case "
 1041: 		     "was not written to work with multiple schedulers (the "
 1042: 		     "yield2 test-case tests almost the same thing)."};
 1043: 		_ ->
 1044: 		    ok
 1045: 	    end
 1046:     end.
 1047: 
 1048: yield_test() ->
 1049:     erlang:garbage_collect(),
 1050:     receive after 1 -> ok end,		% Clear reductions.
 1051:     SC = schedcnt(start),
 1052:     {reductions, R1} = process_info(self(), reductions),
 1053:     {ok, true} = call_yield(middle),
 1054:     true = call_yield(final),
 1055:     true = call_yield(),
 1056:     true = apply(erlang, yield, []),
 1057:     {reductions, R2} = process_info(self(), reductions),
 1058:     Schedcnt = schedcnt(stop, SC),
 1059:     case {R2-R1, Schedcnt} of
 1060: 	{Diff, 4} when Diff < 30 ->
 1061: 	    ok = io:format("R1 = ~w, R2 = ~w, Schedcnt = ~w", 
 1062: 		[R1, R2, Schedcnt]);
 1063: 	{Diff, _} ->
 1064: 	    ok = io:format("R1 = ~w, R2 = ~w, Schedcnt = ~w", 
 1065: 		[R1, R2, Schedcnt]),
 1066: 	    test_server:fail({measurement_error, Diff, Schedcnt})
 1067:     end.
 1068: 
 1069: call_yield() ->
 1070:     erlang:yield().
 1071: 
 1072: call_yield(middle) ->
 1073:     {ok, erlang:yield()};
 1074: call_yield(final) ->
 1075:     case self() of
 1076: 	Self when is_pid(Self) ->
 1077: 	    ok
 1078:     end,
 1079:     erlang:yield().
 1080: 
 1081: schedcnt(start) ->
 1082:     Ref = make_ref(),
 1083:     Fun = 
 1084: 	fun (F, Cnt) ->
 1085: 		receive
 1086: 		    {Ref, Parent} ->
 1087: 			Parent ! {Ref, Cnt}
 1088: 		after 0 ->
 1089: 			erlang:yield(),
 1090: 			F(F, Cnt+1)
 1091: 		end
 1092: 	end,
 1093:     Pid = spawn_link(fun () -> Fun(Fun, 0) end),
 1094:     {Ref, Pid}.
 1095: 
 1096: schedcnt(stop, {Ref, Pid}) when is_reference(Ref), is_pid(Pid) ->
 1097:     Pid ! {Ref, self()},
 1098:     receive
 1099: 	{Ref, Cnt} ->
 1100: 	    Cnt
 1101:     end.
 1102: 
 1103: yield2(doc) -> [];
 1104: yield2(suite) -> [];
 1105: yield2(Config) when is_list(Config) ->
 1106:     Me = self(),
 1107:     Go = make_ref(),
 1108:     RedDiff = make_ref(),
 1109:     Done = make_ref(),
 1110:     P = spawn(fun () ->
 1111: 		receive Go -> ok end,
 1112: 		{reductions, R1} = process_info(self(), reductions),
 1113: 		{ok, true} = call_yield(middle),
 1114: 		true = call_yield(final),
 1115: 		true = call_yield(),
 1116: 		true = apply(erlang, yield, []),
 1117: 		{reductions, R2} = process_info(self(), reductions),
 1118: 		Me ! {RedDiff, R2 - R1},
 1119: 		exit(Done)
 1120: 	end),
 1121:     erlang:yield(),
 1122: 
 1123:     1 = erlang:trace(P, true, [running, procs, {tracer, self()}]),
 1124: 
 1125:     P ! Go,
 1126: 
 1127:     %% receive Go -> ok end,
 1128:     {trace, P, in, _} = next_tmsg(P),
 1129: 
 1130:     %% {ok, true} = call_yield(middle),
 1131:     {trace, P, out, _} = next_tmsg(P),
 1132:     {trace, P, in, _} = next_tmsg(P),
 1133: 
 1134:     %% true = call_yield(final),
 1135:     {trace, P, out, _} = next_tmsg(P),
 1136:     {trace, P, in, _} = next_tmsg(P),
 1137: 
 1138:     %% true = call_yield(),
 1139:     {trace, P, out, _} = next_tmsg(P),
 1140:     {trace, P, in, _} = next_tmsg(P),
 1141: 
 1142:     %% true = apply(erlang, yield, []),
 1143:     {trace, P, out, _} = next_tmsg(P),
 1144:     {trace, P, in, _} = next_tmsg(P),
 1145: 
 1146:     %% exit(Done)
 1147:     {trace, P, exit, Done} = next_tmsg(P),
 1148: 
 1149: 
 1150:     receive
 1151: 	      {RedDiff, Reductions} when Reductions < 30, Reductions > 0 ->
 1152: 		  io:format("Reductions = ~p~n", [Reductions]),
 1153: 		  ok;
 1154: 	      {RedDiff, Reductions} ->
 1155: 		  ?t:fail({unexpected_reduction_count, Reductions})
 1156: 	  end,
 1157: 
 1158:     none = next_tmsg(P),
 1159: 
 1160:     ok.
 1161: 
 1162: next_tmsg(Pid) ->
 1163:     receive
 1164: 	TMsg when is_tuple(TMsg),
 1165: 		  element(1, TMsg) == trace,
 1166: 		  element(2, TMsg) == Pid ->
 1167: 	    TMsg
 1168:     after 100 ->
 1169: 	    none
 1170:     end.
 1171: 
 1172: %% Test that bad arguments to register/2 cause an exception.
 1173: bad_register(Config) when is_list(Config) ->
 1174:     Name = a_long_and_unused_name,
 1175: 
 1176:     {'EXIT',{badarg,_}} = (catch register({bad,name}, self())),
 1177:     fail_register(undefined, self()),
 1178:     fail_register([bad,name], self()),
 1179: 
 1180:     {Dead,Mref} = spawn_monitor(fun() -> true end),
 1181:     receive
 1182: 	{'DOWN',Mref,process,Dead,_} -> ok
 1183:     end,
 1184:     fail_register(Name, Dead),
 1185:     fail_register(Name, make_ref()),
 1186:     fail_register(Name, []),
 1187:     fail_register(Name, {bad,process}),
 1188:     fail_register(Name, <<>>),
 1189:     ok.
 1190: 
 1191: fail_register(Name, Process) ->
 1192:     {'EXIT',{badarg,_}} = (catch register(Name, Process)),
 1193:     {'EXIT',{badarg,_}} = (catch Name ! anything_goes),
 1194:     ok.
 1195: 
 1196: garbage_collect(doc) -> [];
 1197: garbage_collect(suite) -> [];
 1198: garbage_collect(Config) when is_list(Config) ->
 1199:     Prio = process_flag(priority, high),
 1200:     true = erlang:garbage_collect(),
 1201:     
 1202:     TokLoopers = lists:map(fun (_) ->
 1203: 		spawn_opt(fun tok_loop/0, [{priority, low}, link])
 1204: 	end, lists:seq(1, 10)),
 1205: 
 1206:     lists:foreach(fun (Pid) ->
 1207: 		Mon = erlang:monitor(process, Pid),
 1208: 		DownBefore = receive
 1209: 		    {'DOWN', Mon, _, _, _} ->
 1210: 			true
 1211: 		after 0 ->
 1212: 			false
 1213: 		end,
 1214: 		GC = erlang:garbage_collect(Pid),
 1215: 		DownAfter = receive
 1216: 		    {'DOWN', Mon, _, _, _} ->
 1217: 			true
 1218: 		after 0 ->
 1219: 			false
 1220: 		end,
 1221: 		true = erlang:demonitor(Mon),
 1222: 		case {DownBefore, DownAfter} of
 1223: 		    {true, _} -> false = GC;
 1224: 		    {false, false} -> true = GC;
 1225: 		    _ -> GC
 1226: 		end
 1227: 	end, processes()),
 1228: 
 1229:     lists:foreach(fun (Pid) ->
 1230: 		unlink(Pid),
 1231: 		exit(Pid, bang)
 1232: 	end, TokLoopers),
 1233:     process_flag(priority, Prio),
 1234:     ok.
 1235: 
 1236: process_info_messages(doc) ->
 1237:     ["This used to cause the nofrag emulator to dump core"];
 1238: process_info_messages(suite) ->
 1239:     [];
 1240: process_info_messages(Config) when is_list(Config) ->
 1241:     process_info_messages_test(),
 1242:     ok.
 1243: 
 1244: process_info_messages_loop(0) -> ok;
 1245: process_info_messages_loop(N) -> process_info_messages_loop(N-1).
 1246: 
 1247: process_info_messages_send_my_msgs_to(Rcvr) ->
 1248:     receive
 1249: 	Msg ->
 1250: 	    Rcvr ! Msg,
 1251: 	    process_info_messages_send_my_msgs_to(Rcvr)
 1252:     after 0 ->
 1253: 	    ok
 1254:     end.
 1255: 
 1256: process_info_messages_test() ->
 1257:     Go = make_ref(),
 1258:     Done = make_ref(),
 1259:     Rcvr = self(),
 1260:     Rcvr2 = spawn_link(fun () ->
 1261: 		receive {Go, Rcvr} -> ok end,
 1262: 		garbage_collect(),
 1263: 		Rcvr ! {Done, self()}
 1264: 	end),
 1265:     Sndrs = lists:map(
 1266: 	fun (_) ->
 1267: 		spawn_link(fun () ->
 1268: 			    Rcvr ! {Go, self()},
 1269: 			    receive {Go, Rcvr} -> ok end,
 1270: 			    BigData = lists:seq(1, 1000),
 1271: 			    Rcvr ! BigData,
 1272: 			    Rcvr ! BigData,
 1273: 			    Rcvr ! BigData,
 1274: 			    Rcvr ! {Done, self()}
 1275: 		    end)
 1276: 	end, lists:seq(1, 10)),
 1277:     lists:foreach(fun (Sndr) -> receive {Go, Sndr} -> ok end end,
 1278: 			Sndrs),
 1279:     garbage_collect(),
 1280:     erlang:yield(),
 1281:     lists:foreach(fun (Sndr) -> Sndr ! {Go, self()} end, Sndrs),
 1282:     process_info_messages_loop(100000000),
 1283:     Msgs = process_info(self(), messages),
 1284:     lists:foreach(fun (Sndr) -> receive {Done, Sndr} -> ok end end,
 1285: 			Sndrs),
 1286:     garbage_collect(),
 1287:     Rcvr2 ! Msgs,
 1288:     process_info_messages_send_my_msgs_to(Rcvr2),
 1289:     Rcvr2 ! {Go, self()},
 1290:     garbage_collect(),
 1291:     receive {Done, Rcvr2} -> ok end,
 1292:     Msgs.
 1293: 
 1294: chk_badarg(Fun) ->
 1295:     try Fun(), exit(no_badarg) catch error:badarg -> ok end.
 1296: 
 1297: process_flag_badarg(doc) ->
 1298:     [];
 1299: process_flag_badarg(suite) ->
 1300:     [];
 1301: process_flag_badarg(Config) when is_list(Config) ->
 1302:     chk_badarg(fun () -> process_flag(gurka, banan) end),
 1303:     chk_badarg(fun () -> process_flag(trap_exit, gurka) end),
 1304:     chk_badarg(fun () -> process_flag(error_handler, 1) end),
 1305:     chk_badarg(fun () -> process_flag(min_heap_size, gurka) end),
 1306:     chk_badarg(fun () -> process_flag(min_bin_vheap_size, gurka) end),
 1307:     chk_badarg(fun () -> process_flag(min_bin_vheap_size, -1) end),
 1308:     chk_badarg(fun () -> process_flag(priority, 4711) end),
 1309:     chk_badarg(fun () -> process_flag(save_calls, hmmm) end),
 1310:     P= spawn_link(fun () -> receive die -> ok end end),
 1311:     chk_badarg(fun () -> process_flag(P, save_calls, hmmm) end),
 1312:     chk_badarg(fun () -> process_flag(gurka, save_calls, hmmm) end),
 1313:     P ! die,
 1314:     ok.
 1315: 
 1316: -include_lib("stdlib/include/ms_transform.hrl").
 1317: 
 1318: otp_6237(doc) -> [];
 1319: otp_6237(suite) -> [];
 1320: otp_6237(Config) when is_list(Config) ->
 1321:     Slctrs = lists:map(fun (_) ->
 1322: 		spawn_link(fun () ->
 1323: 			    otp_6237_select_loop()
 1324: 		    end)
 1325: 	end,
 1326: 	lists:seq(1,5)),
 1327:     lists:foreach(fun (_) -> otp_6237_test() end, lists:seq(1, 100)),
 1328:     lists:foreach(fun (S) -> unlink(S),exit(S, kill) end, Slctrs), 
 1329:     ok.
 1330: 				
 1331: otp_6237_test() ->
 1332:     Parent = self(),
 1333:     Inited = make_ref(),
 1334:     Die = make_ref(),
 1335:     Pid = spawn_link(fun () ->
 1336: 		register(otp_6237,self()),
 1337: 		otp_6237 = ets:new(otp_6237,
 1338: 		    [named_table,
 1339: 			ordered_set]),
 1340: 		ets:insert(otp_6237,
 1341: 		    [{I,I}
 1342: 			|| I <- lists:seq(1, 100)]),
 1343: 		%% Inserting a lot of bif timers
 1344: 		%% increase the possibility that
 1345: 		%% the test will fail when the
 1346: 		%% original cleanup order is used
 1347: 		lists:foreach( fun (_) ->
 1348: 			    erlang:send_after(1000000, self(), {a,b,c})
 1349: 		    end, lists:seq(1,1000)),
 1350: 		Parent ! Inited,
 1351: 		receive Die -> bye end
 1352: 	end),
 1353:     receive
 1354: 	Inited -> ok
 1355:     end,
 1356:     Pid ! Die,
 1357:     otp_6237_whereis_loop().
 1358: 
 1359: otp_6237_whereis_loop() ->
 1360:     case whereis(otp_6237) of
 1361: 	      undefined ->
 1362: 		  otp_6237 = ets:new(otp_6237,
 1363: 					   [named_table,ordered_set]),
 1364: 		  ets:delete(otp_6237),
 1365: 		  ok;
 1366: 	      _ ->
 1367: 		  otp_6237_whereis_loop()
 1368: 	  end.
 1369: 	     
 1370: otp_6237_select_loop() ->
 1371:     catch ets:select(otp_6237, ets:fun2ms(fun({K, does_not_exist}) -> K end)),
 1372:     otp_6237_select_loop().
 1373: 
 1374: 
 1375: -define(NoTestProcs, 10000).
 1376: -record(ptab_list_bif_info, {min_start_reds,
 1377: 			     tab_chunks,
 1378: 			     tab_chunks_size,
 1379: 			     tab_indices_per_red,
 1380: 			     free_term_proc_reds,
 1381: 			     term_procs_per_red,
 1382: 			     term_procs_max_reds,
 1383: 			     conses_per_red,
 1384: 			     debug_level}).
 1385: 
 1386: processes_large_tab(doc) ->
 1387:     [];
 1388: processes_large_tab(suite) ->
 1389:     [];
 1390: processes_large_tab(Config) when is_list(Config) ->
 1391:     sys_mem_cond_run(2048, fun () -> processes_large_tab_test(Config) end).
 1392: 
 1393: processes_large_tab_test(Config) ->
 1394:     enable_internal_state(),
 1395:     MaxDbgLvl = 20,
 1396:     MinProcTabSize = 2*(1 bsl 15),
 1397:     ProcTabSize0 = 1000000,
 1398:     ProcTabSize1 = case {erlang:system_info(schedulers_online),
 1399: 	    erlang:system_info(logical_processors)} of
 1400: 	{Schdlrs, Cpus} when is_integer(Cpus),
 1401: 	Schdlrs =< Cpus ->
 1402: 	    ProcTabSize0;
 1403: 	_ ->
 1404: 	    ProcTabSize0 div 4
 1405:     end,
 1406:     ProcTabSize2 = case erlang:system_info(debug_compiled) of
 1407: 	true -> ProcTabSize1 - 500000;
 1408: 	false -> ProcTabSize1
 1409:     end,
 1410:     %% With high debug levels this test takes so long time that
 1411:     %% the connection times out; therefore, shrink the test on
 1412:     %% high debug levels.
 1413:     DbgLvl = case erts_debug:get_internal_state(processes_bif_info) of
 1414: 		       #ptab_list_bif_info{debug_level = Lvl} when Lvl > MaxDbgLvl ->
 1415: 			   20;
 1416: 		       #ptab_list_bif_info{debug_level = Lvl} when Lvl < 0 ->
 1417: 			   ?t:fail({debug_level, Lvl});
 1418: 		       #ptab_list_bif_info{debug_level = Lvl} ->
 1419: 			   Lvl
 1420: 		   end,
 1421:     ProcTabSize3 = ProcTabSize2 - (1300000 * DbgLvl div MaxDbgLvl),
 1422:     ProcTabSize = case ProcTabSize3 < MinProcTabSize of
 1423: 			    true -> MinProcTabSize;
 1424: 			    false -> ProcTabSize3
 1425: 			end,
 1426:     {ok, LargeNode} = start_node(Config,
 1427: 				       "+P " ++ integer_to_list(ProcTabSize)),
 1428:     Res = rpc:call(LargeNode, ?MODULE, processes_bif_test, []),
 1429:     case rpc:call(LargeNode,
 1430: 			erts_debug,
 1431: 			get_internal_state,
 1432: 			[processes_bif_info]) of
 1433: 	      #ptab_list_bif_info{tab_chunks = Chunks} when is_integer(Chunks),
 1434: 							    Chunks > 1 -> ok;
 1435: 	      PBInfo -> ?t:fail(PBInfo)
 1436: 	  end,
 1437:     stop_node(LargeNode),
 1438:     chk_processes_bif_test_res(Res).
 1439: 
 1440: processes_default_tab(doc) ->
 1441:     [];
 1442: processes_default_tab(suite) ->
 1443:     [];
 1444: processes_default_tab(Config) when is_list(Config) ->
 1445:     sys_mem_cond_run(1024, fun () -> processes_default_tab_test(Config) end).
 1446: 
 1447: processes_default_tab_test(Config) ->
 1448:     {ok, DefaultNode} = start_node(Config, ""),
 1449:     Res = rpc:call(DefaultNode, ?MODULE, processes_bif_test, []),
 1450:     stop_node(DefaultNode),
 1451:     chk_processes_bif_test_res(Res).
 1452: 
 1453: processes_small_tab(doc) ->
 1454:     [];
 1455: processes_small_tab(suite) ->
 1456:     [];
 1457: processes_small_tab(Config) when is_list(Config) ->
 1458:     {ok, SmallNode} = start_node(Config, "+P 1024"),
 1459:     Res    = rpc:call(SmallNode, ?MODULE, processes_bif_test, []),
 1460:     PBInfo = rpc:call(SmallNode, erts_debug, get_internal_state, [processes_bif_info]),
 1461:     stop_node(SmallNode),
 1462:     true = PBInfo#ptab_list_bif_info.tab_chunks < 10,
 1463:     chk_processes_bif_test_res(Res).
 1464: 
 1465: processes_this_tab(doc) ->
 1466:     [];
 1467: processes_this_tab(suite) ->
 1468:     [];
 1469: processes_this_tab(Config) when is_list(Config) ->
 1470:     sys_mem_cond_run(1024, fun () -> chk_processes_bif_test_res(processes_bif_test()) end).
 1471: 
 1472: chk_processes_bif_test_res(ok) -> ok;
 1473: chk_processes_bif_test_res({comment, _} = Comment) -> Comment;
 1474: chk_processes_bif_test_res(Failure) -> ?t:fail(Failure).
 1475: 
 1476: print_processes_bif_info(#ptab_list_bif_info{min_start_reds = MinStartReds,
 1477: 					     tab_chunks = TabChunks,
 1478: 					     tab_chunks_size = TabChunksSize,
 1479: 					     tab_indices_per_red = TabIndPerRed,
 1480: 					     free_term_proc_reds = FreeTPReds,
 1481: 					     term_procs_per_red = TPPerRed,
 1482: 					     term_procs_max_reds = TPMaxReds,
 1483: 					     conses_per_red = ConsesPerRed,
 1484: 					     debug_level = DbgLvl}) ->
 1485:     ?t:format("processes/0 bif info on node ~p:~n"
 1486: 	      "Min start reductions = ~p~n"
 1487: 	      "Process table chunks = ~p~n"
 1488: 	      "Process table chunks size = ~p~n"
 1489: 	      "Process table indices per reduction = ~p~n"
 1490: 	      "Reduction cost for free() on terminated process struct = ~p~n"
 1491: 	      "Inspect terminated processes per reduction = ~p~n"
 1492: 	      "Max reductions during inspection of terminated processes = ~p~n"
 1493: 	      "Create cons-cells per reduction = ~p~n"
 1494: 	      "Debug level = ~p~n",
 1495: 	      [node(),
 1496: 	       MinStartReds,
 1497: 	       TabChunks,
 1498: 	       TabChunksSize,
 1499: 	       TabIndPerRed,
 1500: 	       FreeTPReds,
 1501: 	       TPPerRed,
 1502: 	       TPMaxReds,
 1503: 	       ConsesPerRed,
 1504: 	       DbgLvl]).
 1505: 
 1506: processes_bif_cleaner() ->
 1507:     receive {'EXIT', _, _} -> ok end,
 1508:     processes_bif_cleaner().
 1509: 
 1510: spawn_initial_hangarounds(Cleaner) ->
 1511:     TabSz = erlang:system_info(process_limit),
 1512:     erts_debug:set_internal_state(next_pid,TabSz),
 1513:     spawn_initial_hangarounds(Cleaner,
 1514: 			      TabSz,
 1515: 			      TabSz*2,
 1516: 			      0,
 1517: 			      []).
 1518: 
 1519: processes_unexpected_result(CorrectProcs, Procs) ->
 1520:     ProcInfo = [registered_name,
 1521: 		initial_call,
 1522: 		current_function,
 1523: 		status,
 1524: 		priority],
 1525:     MissingProcs = CorrectProcs -- Procs,
 1526:     ?t:format("Missing processes: ~p",
 1527: 	      [lists:map(fun (Pid) ->
 1528: 				 [{pid, Pid}
 1529: 				  | case process_info(Pid, ProcInfo) of
 1530: 					undefined -> [];
 1531: 					Res -> Res
 1532: 				    end]
 1533: 			 end,
 1534: 			 MissingProcs)]),
 1535:     SuperfluousProcs = Procs -- CorrectProcs,
 1536:     ?t:format("Superfluous processes: ~p",
 1537: 	      [lists:map(fun (Pid) ->
 1538: 				 [{pid, Pid}
 1539: 				  | case process_info(Pid, ProcInfo) of
 1540: 					undefined -> [];
 1541: 					Res -> Res
 1542: 				    end]
 1543: 			 end,
 1544: 			 SuperfluousProcs)]),
 1545:     ?t:fail(unexpected_result).
 1546: 
 1547: hangaround(Cleaner, Type) ->
 1548:     %% Type is only used to distinguish different processes from
 1549:     %% when doing process_info
 1550:     try link(Cleaner) catch error:Reason -> exit(Reason) end,
 1551:     receive after infinity -> ok end,
 1552:     exit(Type).
 1553: 
 1554: spawn_initial_hangarounds(_Cleaner, NP, Max, Len, HAs) when NP > Max ->
 1555:     {Len, HAs};
 1556: spawn_initial_hangarounds(Cleaner, NP, Max, Len, HAs) ->
 1557:     Skip = 30,
 1558:     HA1 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
 1559: 		    [{priority, low}]),
 1560:     HA2 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
 1561: 		    [{priority, normal}]),
 1562:     HA3 = spawn_opt(?MODULE, hangaround, [Cleaner, initial_hangaround],
 1563: 		    [{priority, high}]),
 1564:     spawn_drop(Skip),
 1565:     spawn_initial_hangarounds(Cleaner, NP+Skip, Max, Len+3, [HA1,HA2,HA3|HAs]).
 1566: 
 1567: spawn_drop(N) when N =< 0 ->
 1568:     ok;
 1569: spawn_drop(N) ->
 1570:     spawn(fun () -> ok end),
 1571:     spawn_drop(N-1).
 1572: 
 1573: do_processes(WantReds) ->
 1574:     erts_debug:set_internal_state(reds_left, WantReds),
 1575:     processes().
 1576: 
 1577: processes_bif_test() ->
 1578:     Tester = self(),
 1579:     enable_internal_state(),
 1580:     PBInfo = erts_debug:get_internal_state(processes_bif_info),
 1581:     print_processes_bif_info(PBInfo),
 1582:     WantReds = PBInfo#ptab_list_bif_info.min_start_reds + 10,
 1583:     WillTrap = case PBInfo of
 1584: 	#ptab_list_bif_info{tab_chunks = Chunks} when Chunks < 10 ->
 1585: 	    false; %% Skip for small tables
 1586: 	#ptab_list_bif_info{tab_chunks = Chunks,
 1587: 	    tab_chunks_size = ChunksSize,
 1588: 	    tab_indices_per_red = IndiciesPerRed
 1589: 	} ->
 1590: 	    Chunks*ChunksSize >= IndiciesPerRed*WantReds
 1591:     end,
 1592:     Processes = fun () ->
 1593: 	    erts_debug:set_internal_state(reds_left,WantReds),
 1594: 	    processes()
 1595:     end,
 1596: 
 1597:     ok = do_processes_bif_test(WantReds, WillTrap, Processes),
 1598: 
 1599:     case WillTrap of
 1600: 	false ->
 1601: 	    ok;
 1602: 	true ->
 1603: 	    %% Do it again with a process suspended while
 1604: 	    %% in the processes/0 bif.
 1605: 	    erlang:system_flag(multi_scheduling, block),
 1606: 	    Suspendee = spawn_link(fun () ->
 1607: 						 Tester ! {suspend_me, self()},
 1608: 						 Tester ! {self(),
 1609: 							   done,
 1610: 							   hd(Processes())},
 1611: 						 receive
 1612: 						 after infinity ->
 1613: 							 ok
 1614: 						 end
 1615: 					 end),
 1616: 	    receive {suspend_me, Suspendee} -> ok end,
 1617: 	    erlang:suspend_process(Suspendee),
 1618: 	    erlang:system_flag(multi_scheduling, unblock),
 1619: 	    
 1620: 	    [{status,suspended},{current_function,{erlang,ptab_list_continue,2}}] =
 1621: 		process_info(Suspendee, [status, current_function]),
 1622: 
 1623: 	    ok = do_processes_bif_test(WantReds, WillTrap, Processes),
 1624: 	    
 1625: 	    erlang:resume_process(Suspendee),
 1626: 	    receive {Suspendee, done, _} -> ok end,
 1627: 	    unlink(Suspendee),
 1628: 	    exit(Suspendee, bang)
 1629:     end,
 1630:     case get(processes_bif_testcase_comment) of
 1631: 	undefined -> ok;
 1632: 	Comment -> {comment, Comment}
 1633:     end.
 1634:     
 1635: do_processes_bif_test(WantReds, DieTest, Processes) ->
 1636:     Tester = self(),
 1637:     SpawnProcesses = fun (Prio) ->
 1638: 	    spawn_opt(?MODULE, do_processes, [WantReds], [link, {priority, Prio}])
 1639:     end,
 1640:     Cleaner = spawn_link(fun () ->
 1641: 		process_flag(trap_exit, true),
 1642: 		Tester ! {cleaner_alive, self()},
 1643: 		processes_bif_cleaner()
 1644: 	end),
 1645:     receive {cleaner_alive, Cleaner} -> ok end,
 1646:     try
 1647: 	DoIt = make_ref(),
 1648: 	GetGoing = make_ref(),
 1649: 	{NoTestProcs, TestProcs} = spawn_initial_hangarounds(Cleaner),
 1650: 	?t:format("Testing with ~p processes~n", [NoTestProcs]),
 1651: 	SpawnHangAround = fun () ->
 1652: 		spawn(?MODULE, hangaround, [Cleaner, new_hangaround])
 1653: 	end,
 1654: 	Killer = spawn_opt(fun () ->
 1655: 		    Splt = NoTestProcs div 10,
 1656: 		    {TP1, TP23} = lists:split(Splt, TestProcs),
 1657: 		    {TP2, TP3} = lists:split(Splt, TP23),
 1658: 		    erlang:system_flag(multi_scheduling, block),
 1659: 		    Tester ! DoIt,
 1660: 		    receive GetGoing -> ok end,
 1661: 		    erlang:system_flag(multi_scheduling, unblock),
 1662: 		    SpawnProcesses(high),
 1663: 		    lists:foreach( fun (P) ->
 1664: 				SpawnHangAround(),
 1665: 				exit(P, bang)
 1666: 			end, TP1),
 1667: 		    SpawnProcesses(high),
 1668: 		    erlang:yield(),
 1669: 		    lists:foreach( fun (P) ->
 1670: 				SpawnHangAround(),
 1671: 				exit(P, bang)
 1672: 			end, TP2),
 1673: 		    SpawnProcesses(high),
 1674: 		    lists:foreach(
 1675: 			fun (P) ->
 1676: 				SpawnHangAround(),
 1677: 				exit(P, bang)
 1678: 			end, TP3)
 1679: 	    end, [{priority, high}, link]),
 1680: 	receive DoIt -> ok end,
 1681: 	process_flag(priority, low),
 1682: 	SpawnProcesses(low),
 1683: 	erlang:yield(),
 1684: 	process_flag(priority, normal),
 1685: 	CorrectProcs0 = erts_debug:get_internal_state(processes),
 1686: 	Killer ! GetGoing,
 1687: 	erts_debug:set_internal_state(reds_left, WantReds),
 1688: 	Procs0 = processes(),
 1689: 	Procs = lists:sort(Procs0),
 1690: 	CorrectProcs = lists:sort(CorrectProcs0),
 1691: 	LengthCorrectProcs = length(CorrectProcs),
 1692: 	?t:format("~p = length(CorrectProcs)~n", [LengthCorrectProcs]),
 1693: 	true = LengthCorrectProcs > NoTestProcs,
 1694: 	case CorrectProcs =:= Procs of
 1695: 	    true ->
 1696: 		ok;
 1697: 	    false ->
 1698: 		processes_unexpected_result(CorrectProcs, Procs)
 1699: 	end,
 1700: 	unlink(Killer),
 1701: 	exit(Killer, bang)
 1702:     after
 1703: 	unlink(Cleaner),
 1704:         exit(Cleaner, kill),
 1705:         %% Wait for the system to recover to a normal state...
 1706: 	wait_until_system_recover()
 1707:     end,
 1708:     do_processes_bif_die_test(DieTest, Processes),
 1709:     ok.
 1710: 
 1711: 
 1712: do_processes_bif_die_test(false, _Processes) ->
 1713:     ?t:format("Skipping test killing process executing processes/0~n",[]),
 1714:     ok;
 1715: do_processes_bif_die_test(true, Processes) ->
 1716:     do_processes_bif_die_test(5, Processes);
 1717: do_processes_bif_die_test(N, Processes) ->
 1718:     ?t:format("Doing test killing process executing processes/0~n",[]),
 1719:     try
 1720: 	Tester = self(),
 1721: 	Oooh_Nooooooo = make_ref(),
 1722: 	{_, DieWhileDoingMon} = erlang:spawn_monitor( fun () ->
 1723: 		    Victim = self(),
 1724: 		    spawn_opt(
 1725: 			fun () ->
 1726: 				exit(Victim, got_him)
 1727: 			end,
 1728: 			[link, {priority, max}]),
 1729: 		    Tester ! {Oooh_Nooooooo,
 1730: 			hd(Processes())},
 1731: 		    exit(ohhhh_nooooo)
 1732: 	    end),
 1733: 	receive
 1734: 	    {'DOWN', DieWhileDoingMon, _, _, Reason} ->
 1735: 		case Reason of
 1736: 		    got_him -> ok;
 1737: 		    _ -> throw({kill_in_trap, Reason})
 1738: 		end
 1739: 	end,
 1740: 	receive
 1741: 	    {Oooh_Nooooooo, _} ->
 1742: 		throw({kill_in_trap, 'Oooh_Nooooooo'})
 1743: 	after 0 ->
 1744: 		ok
 1745: 	end,
 1746: 	PrcsCllrsSeqLen = 2*erlang:system_info(schedulers_online),
 1747: 	PrcsCllrsSeq = lists:seq(1, PrcsCllrsSeqLen),
 1748: 	ProcsCallers = lists:map( fun (_) ->
 1749: 		    spawn_link(
 1750: 			fun () ->
 1751: 				Tester ! hd(Processes())
 1752: 			end)
 1753: 	    end, PrcsCllrsSeq),
 1754: 	erlang:yield(),
 1755: 	{ProcsCallers1, ProcsCallers2} = lists:split(PrcsCllrsSeqLen div 2,
 1756: 						     ProcsCallers),
 1757: 	process_flag(priority, high),
 1758: 	lists:foreach(
 1759: 		fun (P) ->
 1760: 			unlink(P),
 1761: 			exit(P, bang)
 1762: 		end,
 1763: 		lists:reverse(ProcsCallers2) ++ ProcsCallers1),
 1764: 	process_flag(priority, normal),
 1765: 	ok
 1766:     catch
 1767: 	throw:{kill_in_trap, R} when N > 0 ->
 1768: 	    ?t:format("Failed to kill in trap: ~p~n", [R]),
 1769: 	    ?t:format("Trying again~n", []),
 1770: 	    do_processes_bif_die_test(N-1, Processes)
 1771:     end.
 1772: 	    
 1773: 
 1774: wait_until_system_recover() ->
 1775:     %% If system hasn't recovered after 10 seconds we give up
 1776:     Tmr = erlang:start_timer(10000, self(), no_more_wait),
 1777:     wait_until_system_recover(Tmr).
 1778: 
 1779: wait_until_system_recover(Tmr) ->
 1780:     try
 1781: 	lists:foreach(fun (P) when P == self() ->
 1782: 			      ok;
 1783: 			  (P) ->
 1784: 			      case process_info(P, initial_call) of
 1785: 				  {initial_call,{?MODULE, _, _}} ->
 1786: 				      throw(wait);
 1787: 				  {initial_call,{_, _, _}} ->
 1788: 				      ok;
 1789: 				  undefined ->
 1790: 				      ok
 1791: 			      end
 1792: 		      end,
 1793: 		      processes())
 1794:     catch
 1795: 	throw:wait ->
 1796: 	    receive
 1797: 		{timeout, Tmr, _} ->
 1798: 		    Comment = "WARNING: Test processes still hanging around!",
 1799: 		    ?t:format("~s~n", [Comment]),
 1800: 		    put(processes_bif_testcase_comment, Comment),
 1801: 		    lists:foreach(
 1802: 		      fun (P) when P == self() ->
 1803: 			      ok;
 1804: 			  (P) ->
 1805: 			      case process_info(P, initial_call) of
 1806: 				  {initial_call,{?MODULE, _, _} = MFA} ->
 1807: 				      ?t:format("~p ~p~n", [P, MFA]);
 1808: 				  {initial_call,{_, _, _}} ->
 1809: 				      ok;
 1810: 				  undefined ->
 1811: 				      ok
 1812: 			      end
 1813: 		      end,
 1814: 		      processes())
 1815: 	    after 100 ->
 1816: 		    wait_until_system_recover(Tmr)
 1817: 	    end
 1818:     end,
 1819:     erlang:cancel_timer(Tmr),
 1820:     receive {timeout, Tmr, _} -> ok after 0 -> ok end,
 1821:     ok.
 1822: 
 1823: processes_last_call_trap(doc) ->
 1824:     [];
 1825: processes_last_call_trap(suite) ->
 1826:     [];
 1827: processes_last_call_trap(Config) when is_list(Config) ->
 1828:     enable_internal_state(),
 1829:     Processes = fun () -> processes() end,
 1830:     PBInfo = erts_debug:get_internal_state(processes_bif_info),
 1831:     print_processes_bif_info(PBInfo),
 1832:     WantReds = case PBInfo#ptab_list_bif_info.min_start_reds of
 1833: 	R when R > 10 -> R - 1;
 1834: 	_R -> 9
 1835:     end,
 1836:     lists:foreach(fun (_) ->
 1837: 		erts_debug:set_internal_state(reds_left,
 1838: 		    WantReds),
 1839: 		Processes(),
 1840: 		erts_debug:set_internal_state(reds_left,
 1841: 		    WantReds),
 1842: 		my_processes()
 1843: 	end,
 1844: 	lists:seq(1,100)).
 1845:     
 1846: my_processes() ->
 1847:     processes().
 1848: 
 1849: processes_apply_trap(doc) ->
 1850:     [];
 1851: processes_apply_trap(suite) ->
 1852:     [];
 1853: processes_apply_trap(Config) when is_list(Config) ->
 1854:     enable_internal_state(),
 1855:     PBInfo = erts_debug:get_internal_state(processes_bif_info),
 1856:     print_processes_bif_info(PBInfo),
 1857:     WantReds = case PBInfo#ptab_list_bif_info.min_start_reds of
 1858: 	R when R > 10 -> R - 1;
 1859: 	_R -> 9
 1860:     end,
 1861:     lists:foreach(fun (_) ->
 1862: 		erts_debug:set_internal_state(reds_left,
 1863: 		    WantReds),
 1864: 		apply(erlang, processes, [])
 1865: 	end, lists:seq(1,100)).
 1866: 
 1867: processes_gc_trap(doc) ->
 1868:     [];
 1869: processes_gc_trap(suite) ->
 1870:     [];
 1871: processes_gc_trap(Config) when is_list(Config) ->
 1872:     Tester = self(),
 1873:     enable_internal_state(),
 1874:     PBInfo = erts_debug:get_internal_state(processes_bif_info),
 1875:     print_processes_bif_info(PBInfo),
 1876:     WantReds = PBInfo#ptab_list_bif_info.min_start_reds + 10,
 1877:     Processes = fun () ->
 1878: 	    erts_debug:set_internal_state(reds_left,WantReds),
 1879: 	    processes()
 1880:     end,
 1881: 
 1882:     erlang:system_flag(multi_scheduling, block),
 1883:     Suspendee = spawn_link(fun () ->
 1884: 					 Tester ! {suspend_me, self()},
 1885: 					 Tester ! {self(),
 1886: 						   done,
 1887: 						   hd(Processes())},
 1888: 					 receive after infinity -> ok end
 1889: 				 end),
 1890:     receive {suspend_me, Suspendee} -> ok end,
 1891:     erlang:suspend_process(Suspendee),
 1892:     erlang:system_flag(multi_scheduling, unblock),
 1893: 	    
 1894:     [{status,suspended}, {current_function,{erlang,ptab_list_continue,2}}]
 1895: 	= process_info(Suspendee, [status, current_function]),
 1896: 
 1897:     erlang:garbage_collect(Suspendee),
 1898:     erlang:garbage_collect(Suspendee),
 1899: 	    
 1900:     erlang:resume_process(Suspendee),
 1901:     receive {Suspendee, done, _} -> ok end,
 1902:     erlang:garbage_collect(Suspendee),
 1903:     erlang:garbage_collect(Suspendee),
 1904: 
 1905:     unlink(Suspendee),
 1906:     exit(Suspendee, bang),
 1907:     ok.
 1908: 
 1909: process_flag_heap_size(doc) ->
 1910:     [];
 1911: process_flag_heap_size(suite) ->
 1912:     [];
 1913: process_flag_heap_size(Config) when is_list(Config) ->
 1914:     HSize  = 2586,   % must be gc fib+ number
 1915:     VHSize = 318187, % must be gc fib+ number
 1916:     OldHmin = erlang:process_flag(min_heap_size, HSize),
 1917:     {min_heap_size, HSize} = erlang:process_info(self(), min_heap_size),
 1918:     OldVHmin = erlang:process_flag(min_bin_vheap_size, VHSize),
 1919:     {min_bin_vheap_size, VHSize} = erlang:process_info(self(), min_bin_vheap_size),
 1920:     HSize = erlang:process_flag(min_heap_size, OldHmin),
 1921:     VHSize = erlang:process_flag(min_bin_vheap_size, OldVHmin),
 1922:     ok.
 1923: 
 1924: spawn_opt_heap_size(doc) ->
 1925:     [];
 1926: spawn_opt_heap_size(suite) ->
 1927:     [];
 1928: spawn_opt_heap_size(Config) when is_list(Config) ->
 1929:     HSize  = 987,   % must be gc fib+ number
 1930:     VHSize = 46422, % must be gc fib+ number
 1931:     Pid  = spawn_opt(fun () -> receive stop -> ok end end,
 1932: 	[{min_heap_size, HSize},{ min_bin_vheap_size, VHSize}]),
 1933:     {min_heap_size, HSize} = process_info(Pid, min_heap_size),
 1934:     {min_bin_vheap_size, VHSize} = process_info(Pid, min_bin_vheap_size),
 1935:     Pid ! stop,
 1936:     ok.
 1937: 
 1938: processes_term_proc_list(doc) ->
 1939:     [];
 1940: processes_term_proc_list(suite) ->
 1941:     [];
 1942: processes_term_proc_list(Config) when is_list(Config) ->
 1943:     Tester = self(),
 1944:     as_expected = processes_term_proc_list_test(false),
 1945:     {ok, Node} = start_node(Config, "+Mis true"),
 1946:     RT = spawn_link(Node, fun () ->
 1947: 		receive after 1000 -> ok end,
 1948: 		processes_term_proc_list_test(false),
 1949: 		Tester ! {it_worked, self()}
 1950: 	end),
 1951:     receive {it_worked, RT} -> ok end,
 1952:     stop_node(Node),
 1953:     ok.
 1954:     
 1955: -define(CHK_TERM_PROC_LIST(MC, XB),
 1956: 	chk_term_proc_list(?LINE, MC, XB)).
 1957: 
 1958: chk_term_proc_list(Line, MustChk, ExpectBlks) ->
 1959:     case {MustChk, instrument:memory_status(types)} of
 1960: 	{false, false} ->
 1961: 	    not_enabled;
 1962: 	{_, MS} ->
 1963: 	    {value,
 1964: 	     {ptab_list_deleted_el,
 1965: 	      DL}} = lists:keysearch(ptab_list_deleted_el, 1, MS),
 1966: 	    case lists:keysearch(blocks, 1, DL) of
 1967: 		{value, {blocks, ExpectBlks, _, _}} ->
 1968: 		    ok;
 1969: 		{value, {blocks, Blks, _, _}} ->
 1970: 		    exit({line, Line,
 1971: 			  mismatch, expected, ExpectBlks, actual, Blks});
 1972: 		Unexpected ->
 1973: 		    exit(Unexpected)
 1974: 	    end
 1975:     end,
 1976:     ok.
 1977: 
 1978: processes_term_proc_list_test(MustChk) ->
 1979:     Tester = self(),
 1980:     enable_internal_state(),
 1981:     PBInfo = erts_debug:get_internal_state(processes_bif_info),
 1982:     print_processes_bif_info(PBInfo),
 1983:     WantReds = PBInfo#ptab_list_bif_info.min_start_reds + 10,
 1984:     #ptab_list_bif_info{tab_chunks = Chunks,
 1985: 	tab_chunks_size = ChunksSize,
 1986: 	tab_indices_per_red = IndiciesPerRed
 1987:     } = PBInfo,
 1988:     true = Chunks > 1,
 1989:     true = Chunks*ChunksSize >= IndiciesPerRed*WantReds,
 1990:     Processes = fun () ->
 1991: 	    erts_debug:set_internal_state(reds_left,
 1992: 		WantReds),
 1993: 	    processes()
 1994:     end,
 1995:     Exit = fun (P) ->
 1996: 	    unlink(P),
 1997: 	    exit(P, bang),
 1998: 	    wait_until(
 1999: 		fun () ->
 2000: 			not lists:member(
 2001: 			    P,
 2002: 			    erts_debug:get_internal_state(
 2003: 				processes))
 2004: 		end)
 2005:     end,
 2006:     SpawnSuspendProcessesProc = fun () ->
 2007: 		  erlang:system_flag(multi_scheduling, block),
 2008: 		  P = spawn_link(fun () ->
 2009: 					 Tester ! {suspend_me, self()},
 2010: 					 Tester ! {self(),
 2011: 						   done,
 2012: 						   hd(Processes())},
 2013: 					 receive after infinity -> ok end
 2014: 				 end),
 2015: 		  receive {suspend_me, P} -> ok end,
 2016: 		  erlang:suspend_process(P),
 2017: 		  erlang:system_flag(multi_scheduling, unblock),
 2018: 		  [{status,suspended},
 2019: 		   {current_function,{erlang,ptab_list_continue,2}}]
 2020: 		      = process_info(P, [status, current_function]),
 2021: 		  P
 2022: 	  end,
 2023:     ResumeProcessesProc = fun (P) ->
 2024: 					erlang:resume_process(P),
 2025: 					receive {P, done, _} -> ok end
 2026: 				end,
 2027:     ?CHK_TERM_PROC_LIST(MustChk, 0),
 2028:     HangAround = fun () -> receive after infinity -> ok end end,
 2029:     HA1 = spawn_link(HangAround),
 2030:     HA2 = spawn_link(HangAround),
 2031:     HA3 = spawn_link(HangAround),
 2032:     S1 = SpawnSuspendProcessesProc(),
 2033:     ?CHK_TERM_PROC_LIST(MustChk, 1),
 2034:     Exit(HA1),
 2035:     ?CHK_TERM_PROC_LIST(MustChk, 2),
 2036:     S2 = SpawnSuspendProcessesProc(),
 2037:     ?CHK_TERM_PROC_LIST(MustChk, 3),
 2038:     S3 = SpawnSuspendProcessesProc(),
 2039:     ?CHK_TERM_PROC_LIST(MustChk, 4),
 2040:     Exit(HA2),
 2041:     ?CHK_TERM_PROC_LIST(MustChk, 5),
 2042:     S4 = SpawnSuspendProcessesProc(),
 2043:     ?CHK_TERM_PROC_LIST(MustChk, 6),
 2044:     Exit(HA3),
 2045:     ?CHK_TERM_PROC_LIST(MustChk, 7),
 2046:     ResumeProcessesProc(S1),
 2047:     ?CHK_TERM_PROC_LIST(MustChk, 5),
 2048:     ResumeProcessesProc(S3),
 2049:     ?CHK_TERM_PROC_LIST(MustChk, 4),
 2050:     ResumeProcessesProc(S4),
 2051:     ?CHK_TERM_PROC_LIST(MustChk, 3),
 2052:     ResumeProcessesProc(S2),
 2053:     ?CHK_TERM_PROC_LIST(MustChk, 0),
 2054:     Exit(S1),
 2055:     Exit(S2),
 2056:     Exit(S3),
 2057:     Exit(S4),
 2058: 
 2059: 
 2060:     HA4 = spawn_link(HangAround),
 2061:     HA5 = spawn_link(HangAround),
 2062:     HA6 = spawn_link(HangAround),
 2063:     S5 = SpawnSuspendProcessesProc(),
 2064:     ?CHK_TERM_PROC_LIST(MustChk, 1),
 2065:     Exit(HA4),
 2066:     ?CHK_TERM_PROC_LIST(MustChk, 2),
 2067:     S6 = SpawnSuspendProcessesProc(),
 2068:     ?CHK_TERM_PROC_LIST(MustChk, 3),
 2069:     Exit(HA5),
 2070:     ?CHK_TERM_PROC_LIST(MustChk, 4),
 2071:     S7 = SpawnSuspendProcessesProc(),
 2072:     ?CHK_TERM_PROC_LIST(MustChk, 5),
 2073:     Exit(HA6),
 2074:     ?CHK_TERM_PROC_LIST(MustChk, 6),
 2075:     S8 = SpawnSuspendProcessesProc(),
 2076:     ?CHK_TERM_PROC_LIST(MustChk, 7),
 2077: 
 2078:     erlang:system_flag(multi_scheduling, block),
 2079:     Exit(S8),
 2080:     ?CHK_TERM_PROC_LIST(MustChk, 7),
 2081:     Exit(S5),
 2082:     ?CHK_TERM_PROC_LIST(MustChk, 6),
 2083:     Exit(S7),
 2084:     ?CHK_TERM_PROC_LIST(MustChk, 6),
 2085:     Exit(S6),
 2086:     ?CHK_TERM_PROC_LIST(MustChk, 0),
 2087:     erlang:system_flag(multi_scheduling, unblock),
 2088:     as_expected.
 2089: 
 2090: 
 2091: otp_7738_waiting(doc) ->
 2092:     [];
 2093: otp_7738_waiting(suite) ->
 2094:     [];
 2095: otp_7738_waiting(Config) when is_list(Config) ->
 2096:     otp_7738_test(waiting).
 2097: 
 2098: otp_7738_suspended(doc) ->
 2099:     [];
 2100: otp_7738_suspended(suite) ->
 2101:     [];
 2102: otp_7738_suspended(Config) when is_list(Config) ->
 2103:     otp_7738_test(suspended).
 2104: 
 2105: otp_7738_resume(doc) ->
 2106:     [];
 2107: otp_7738_resume(suite) ->
 2108:     [];
 2109: otp_7738_resume(Config) when is_list(Config) ->
 2110:     otp_7738_test(resume).
 2111: 
 2112: otp_7738_test(Type) ->
 2113:     sys_mem_cond_run(3072, fun () -> do_otp_7738_test(Type) end).
 2114: 
 2115: do_otp_7738_test(Type) ->
 2116:     T = self(),
 2117:     S = spawn_link(fun () ->
 2118: 		receive
 2119: 		    {suspend, Suspendee} ->
 2120: 			erlang:suspend_process(Suspendee),
 2121: 			T ! {suspended, Suspendee},
 2122: 			receive
 2123: 			after 10 ->
 2124: 				erlang:resume_process(Suspendee),
 2125: 				Suspendee ! wake_up
 2126: 			end;
 2127: 		    {send, To, Msg} ->
 2128: 			receive after 10 -> ok end,
 2129: 			To ! Msg
 2130: 		end
 2131: 	end),
 2132:     R = spawn_link(fun () ->
 2133: 		X = lists:seq(1, 20000000),
 2134: 		T ! {initialized, self()},
 2135: 		case Type of
 2136: 		    _ when Type == suspended;
 2137: 		Type == waiting ->
 2138: 		    receive _ -> ok end;
 2139: 		_ when Type == resume ->
 2140: 		    Receive = fun (F) ->
 2141: 			    receive
 2142: 				_ ->
 2143: 				    ok
 2144: 			    after 0 ->
 2145: 				    F(F)
 2146: 			    end
 2147: 		    end,
 2148: 		    Receive(Receive)
 2149: 	    end,
 2150: 	    T ! {woke_up, self()},
 2151: 	    id(X)
 2152:     end),
 2153:     receive {initialized, R} -> ok end,
 2154:     receive after 10 -> ok end,
 2155:     case Type of
 2156: 	      suspended ->
 2157: 		  erlang:suspend_process(R),
 2158: 		  S ! {send, R, wake_up};
 2159: 	      waiting ->
 2160: 		  S ! {send, R, wake_up};
 2161: 	      resume ->
 2162: 		  S ! {suspend, R},
 2163: 		  receive {suspended, R} -> ok end
 2164: 	  end,
 2165:     erlang:garbage_collect(R),
 2166:     case Type of
 2167: 	      suspended ->
 2168: 		  erlang:resume_process(R);
 2169: 	      _ ->
 2170: 		  ok
 2171: 	  end,
 2172:     receive
 2173: 	      {woke_up, R} ->
 2174: 		  ok
 2175: 	  after 2000 ->
 2176: 		  I = process_info(R, [status, message_queue_len]),
 2177: 		  ?t:format("~p~n", [I]),
 2178: 		  ?t:fail(no_progress)
 2179: 	  end,
 2180:     ok.
 2181: 
 2182: gor(Reds, Stop) ->
 2183:     receive
 2184: 	{From, reds} ->
 2185: 	    From ! {reds, Reds, self()},
 2186: 	    gor(Reds+1, Stop);
 2187: 	{From, Stop} ->
 2188: 	    From ! {stopped, Stop, Reds, self()}
 2189:     after 0 ->
 2190: 	    gor(Reds+1, Stop)
 2191:     end.
 2192: 
 2193: garb_other_running(Config) when is_list(Config) ->
 2194:     Stop = make_ref(),
 2195:     {Pid, Mon} = spawn_monitor(fun () -> gor(0, Stop) end),
 2196:     Reds = lists:foldl(fun (_, OldReds) ->
 2197: 				     erlang:garbage_collect(Pid),
 2198: 				     receive after 1 -> ok end,
 2199: 				     Pid ! {self(), reds},
 2200: 				     receive
 2201: 					       {reds, NewReds, Pid} ->
 2202: 						   true = (NewReds > OldReds),
 2203: 						   NewReds
 2204: 					   end
 2205: 			     end,
 2206: 			     0,
 2207: 			     lists:seq(1, 10000)),
 2208:     receive after 1 -> ok end,
 2209:     Pid ! {self(), Stop},
 2210:     receive
 2211: 	      {stopped, Stop, StopReds, Pid} ->
 2212: 		  true = (StopReds > Reds)
 2213: 	  end,
 2214:     receive {'DOWN', Mon, process, Pid, normal} -> ok end,
 2215:     ok.
 2216: 
 2217: %% Internal functions
 2218: 
 2219: wait_until(Fun) ->
 2220:     case Fun() of
 2221: 	true -> true;
 2222: 	false -> receive after 10 -> wait_until(Fun) end
 2223:     end.
 2224: 
 2225: tok_loop() ->
 2226:     tok_loop(hej).
 2227: 
 2228: tok_loop(hej) ->
 2229:     tok_loop(hopp);
 2230: tok_loop(hopp) ->
 2231:     tok_loop(hej).
 2232: 
 2233: id(I) -> I.
 2234:     
 2235: start_node(Config) ->
 2236:     start_node(Config, "").
 2237: 
 2238: start_node(Config, Args) when is_list(Config) ->
 2239:     Pa = filename:dirname(code:which(?MODULE)),
 2240:     {A, B, C} = now(),
 2241:     Name = list_to_atom(atom_to_list(?MODULE)
 2242: 			      ++ "-"
 2243: 			      ++ atom_to_list(?config(testcase, Config))
 2244: 			      ++ "-"
 2245: 			      ++ integer_to_list(A)
 2246: 			      ++ "-"
 2247: 			      ++ integer_to_list(B)
 2248: 			      ++ "-"
 2249: 			      ++ integer_to_list(C)),
 2250:     ?t:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]).
 2251: 
 2252: stop_node(Node) ->
 2253:     ?t:stop_node(Node).
 2254: 
 2255: enable_internal_state() ->
 2256:     case catch erts_debug:get_internal_state(available_internal_state) of
 2257: 	true -> true;
 2258: 	_ -> erts_debug:set_internal_state(available_internal_state, true)
 2259:     end.
 2260: 
 2261: sys_mem_cond_run(ReqSizeMB, TestFun) when is_integer(ReqSizeMB) ->
 2262:     case total_memory() of
 2263: 	TotMem when is_integer(TotMem), TotMem >= ReqSizeMB ->
 2264: 	    TestFun();
 2265: 	TotMem when is_integer(TotMem) ->
 2266: 	    {skipped, "Not enough memory ("++integer_to_list(TotMem)++" MB)"};
 2267: 	undefined ->
 2268: 	    {skipped, "Could not retrieve memory information"}
 2269:     end.
 2270: 
 2271: 
 2272: total_memory() ->
 2273:     %% Totat memory in MB.
 2274:     try
 2275: 	MemoryData = memsup:get_system_memory_data(),
 2276: 	case lists:keysearch(total_memory, 1, MemoryData) of
 2277: 	    {value, {total_memory, TM}} ->
 2278: 		TM div (1024*1024);
 2279: 	    false ->
 2280: 		{value, {system_total_memory, STM}} =
 2281: 		    lists:keysearch(system_total_memory, 1, MemoryData),
 2282: 		STM div (1024*1024)
 2283: 	end
 2284:     catch
 2285: 	_ : _ ->
 2286: 	    undefined
 2287:     end.