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.