1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 2006-2011. 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: %%%------------------------------------------------------------------- 21: %%% File : signal_SUITE.erl 22: %%% Author : Rickard Green <rickard.s.green@ericsson.com> 23: %%% Description : Test signals 24: %%% 25: %%% Created : 10 Jul 2006 by Rickard Green <rickard.s.green@ericsson.com> 26: %%%------------------------------------------------------------------- 27: -module(signal_SUITE). 28: -author('rickard.s.green@ericsson.com'). 29: 30: -define(DEFAULT_TIMEOUT_SECONDS, 120). 31: 32: %-define(line_trace, 1). 33: -include_lib("test_server/include/test_server.hrl"). 34: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 35: init_per_group/2,end_per_group/2]). 36: 37: % Test cases 38: -export([xm_sig_order/1, 39: pending_exit_unlink_process/1, 40: pending_exit_unlink_dist_process/1, 41: pending_exit_unlink_port/1, 42: pending_exit_trap_exit/1, 43: pending_exit_receive/1, 44: pending_exit_exit/1, 45: pending_exit_gc/1, 46: pending_exit_is_process_alive/1, 47: pending_exit_process_display/1, 48: pending_exit_process_info_1/1, 49: pending_exit_process_info_2/1, 50: pending_exit_group_leader/1, 51: exit_before_pending_exit/1]). 52: 53: -export([init_per_testcase/2, end_per_testcase/2]). 54: 55: init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> 56: ?line Dog = ?t:timetrap(?t:seconds(?DEFAULT_TIMEOUT_SECONDS)), 57: available_internal_state(true), 58: ?line [{testcase, Func},{watchdog, Dog}|Config]. 59: 60: end_per_testcase(_Func, Config) -> 61: ?line Dog = ?config(watchdog, Config), 62: ?line ?t:timetrap_cancel(Dog). 63: 64: init_per_suite(Config) -> 65: Config. 66: 67: end_per_suite(_Config) -> 68: available_internal_state(true), 69: catch erts_debug:set_internal_state(not_running_optimization, true), 70: available_internal_state(false). 71: 72: suite() -> [{ct_hooks,[ts_install_cth]}]. 73: 74: all() -> 75: [xm_sig_order, pending_exit_unlink_process, 76: pending_exit_unlink_dist_process, 77: pending_exit_unlink_port, pending_exit_trap_exit, 78: pending_exit_receive, pending_exit_trap_exit, 79: pending_exit_gc, pending_exit_is_process_alive, 80: pending_exit_process_display, 81: pending_exit_process_info_1, 82: pending_exit_process_info_2, pending_exit_group_leader, 83: exit_before_pending_exit]. 84: 85: groups() -> 86: []. 87: 88: init_per_group(_GroupName, Config) -> 89: Config. 90: 91: end_per_group(_GroupName, Config) -> 92: Config. 93: 94: 95: xm_sig_order(doc) -> ["Test that exit signals and messages are received " 96: "in correct order"]; 97: xm_sig_order(suite) -> []; 98: xm_sig_order(Config) when is_list(Config) -> 99: ?line LNode = node(), 100: ?line repeat(fun () -> xm_sig_order_test(LNode) end, 1000), 101: ?line {ok, RNode} = start_node(Config), 102: ?line repeat(fun () -> xm_sig_order_test(RNode) end, 1000), 103: ?line stop_node(RNode), 104: ?line ok. 105: 106: 107: xm_sig_order_test(Node) -> 108: ?line P = spawn(Node, fun () -> xm_sig_order_proc() end), 109: ?line M = erlang:monitor(process, P), 110: ?line P ! may_reach, 111: ?line P ! may_reach, 112: ?line P ! may_reach, 113: ?line exit(P, good_signal_order), 114: ?line P ! may_not_reach, 115: ?line P ! may_not_reach, 116: ?line P ! may_not_reach, 117: ?line receive 118: {'DOWN', M, process, P, R} -> 119: ?line good_signal_order = R 120: end. 121: 122: xm_sig_order_proc() -> 123: receive 124: may_not_reach -> exit(bad_signal_order); 125: may_reach -> ok 126: after 0 -> ok 127: end, 128: xm_sig_order_proc(). 129: 130: pending_exit_unlink_process(doc) -> []; 131: pending_exit_unlink_process(suite) -> []; 132: pending_exit_unlink_process(Config) when is_list(Config) -> 133: ?line pending_exit_test(self(), unlink). 134: 135: pending_exit_unlink_dist_process(doc) -> []; 136: pending_exit_unlink_dist_process(suite) -> []; 137: pending_exit_unlink_dist_process(Config) when is_list(Config) -> 138: ?line {ok, Node} = start_node(Config), 139: ?line From = spawn(Node, fun () -> receive after infinity -> ok end end), 140: ?line Res = pending_exit_test(From, unlink), 141: ?line stop_node(Node), 142: ?line Res. 143: 144: pending_exit_unlink_port(doc) -> []; 145: pending_exit_unlink_port(suite) -> []; 146: pending_exit_unlink_port(Config) when is_list(Config) -> 147: ?line pending_exit_test(hd(erlang:ports()), unlink). 148: 149: pending_exit_trap_exit(doc) -> []; 150: pending_exit_trap_exit(suite) -> []; 151: pending_exit_trap_exit(Config) when is_list(Config) -> 152: ?line pending_exit_test(self(), trap_exit). 153: 154: pending_exit_receive(doc) -> []; 155: pending_exit_receive(suite) -> []; 156: pending_exit_receive(Config) when is_list(Config) -> 157: ?line pending_exit_test(self(), 'receive'). 158: 159: pending_exit_exit(doc) -> []; 160: pending_exit_exit(suite) -> []; 161: pending_exit_exit(Config) when is_list(Config) -> 162: ?line pending_exit_test(self(), exit). 163: 164: pending_exit_gc(doc) -> []; 165: pending_exit_gc(suite) -> []; 166: pending_exit_gc(Config) when is_list(Config) -> 167: ?line pending_exit_test(self(), gc). 168: 169: pending_exit_test(From, Type) -> 170: ?line case catch erlang:system_info(smp_support) of 171: true -> 172: ?line OTE = process_flag(trap_exit, true), 173: ?line Ref = make_ref(), 174: ?line Master = self(), 175: ?line ExitBySignal = case Type of 176: gc -> 177: lists:duplicate(10000, 178: exit_by_signal); 179: _ -> 180: exit_by_signal 181: end, 182: ?line Pid = spawn_link( 183: fun () -> 184: receive go -> ok end, 185: false = have_pending_exit(), 186: exit = fake_exit(From, 187: self(), 188: ExitBySignal), 189: true = have_pending_exit(), 190: Master ! {self(), Ref, Type}, 191: case Type of 192: gc -> 193: force_gc(), 194: erlang:yield(); 195: unlink -> 196: unlink(From); 197: trap_exit -> 198: process_flag(trap_exit, true); 199: 'receive' -> 200: receive _ -> ok 201: after 0 -> ok 202: end; 203: exit -> 204: ok 205: end, 206: exit(exit_by_myself) 207: end), 208: ?line Mon = erlang:monitor(process, Pid), 209: ?line Pid ! go, 210: ?line Reason = receive 211: {'DOWN', Mon, process, Pid, R} -> 212: ?line receive 213: {Pid, Ref, Type} -> 214: ?line ok 215: after 0 -> 216: ?line ?t:fail(premature_exit) 217: end, 218: ?line case Type of 219: exit -> 220: ?line exit_by_myself = R; 221: _ -> 222: ?line ExitBySignal = R 223: end 224: end, 225: ?line receive 226: {'EXIT', Pid, R2} -> 227: ?line Reason = R2 228: end, 229: ?line process_flag(trap_exit, OTE), 230: ?line ok, 231: {comment, 232: "Test only valid with current SMP emulator."}; 233: _ -> 234: {skipped, 235: "SMP support not enabled. " 236: "Test only valid with current SMP emulator."} 237: end. 238: 239: 240: 241: exit_before_pending_exit(doc) -> []; 242: exit_before_pending_exit(suite) -> []; 243: exit_before_pending_exit(Config) when is_list(Config) -> 244: %% This is a testcase testcase very specific to the smp 245: %% implementation as it is of the time of writing. 246: %% 247: %% The testcase tries to check that a process can 248: %% exit by itself even though it has a pending exit. 249: ?line OTE = process_flag(trap_exit, true), 250: ?line Master = self(), 251: ?line Tester = spawn_link( 252: fun () -> 253: Opts = case {erlang:system_info(run_queues), 254: erlang:system_info(schedulers_online)} of 255: {RQ, SO} when RQ =:= 1; SO =:= 1 -> []; 256: _ -> 257: process_flag(scheduler, 1), 258: [{scheduler, 2}] 259: end, 260: P = self(), 261: Exiter = spawn_opt(fun () -> 262: receive 263: {exit_me, P, R} -> 264: exit(P, R) 265: end 266: end, Opts), 267: erlang:yield(), 268: Exiter ! {exit_me, self(), exited_by_exiter}, 269: %% We want to get a pending exit 270: %% before we exit ourselves. We 271: %% don't want to be scheduled out 272: %% since we will then see the 273: %% pending exit. 274: %% 275: %% Do something that takes 276: %% relatively long time but 277: %% consumes few reductions... 278: repeat(fun() -> erlang:system_info(procs) end,10), 279: %% ... then exit. 280: Master ! {self(), 281: pending_exit, 282: have_pending_exit()}, 283: exit(exited_by_myself) 284: end), 285: ?line PendingExit = receive {Tester, pending_exit, PE} -> PE end, 286: ?line receive 287: {'EXIT', Tester, exited_by_myself} -> 288: ?line process_flag(trap_exit, OTE), 289: ?line ok; 290: Msg -> 291: ?line ?t:fail({unexpected_message, Msg}) 292: end, 293: NoScheds = integer_to_list(erlang:system_info(schedulers_online)), 294: {comment, 295: "Was " 296: ++ case PendingExit of 297: true -> ""; 298: false ->"*not*" 299: end ++ " able to trigger a pending exit. " 300: ++ "Running on " ++ NoScheds ++ " scheduler(s). " 301: ++ "This test is only interesting with at least two schedulers."}. 302: 303: -define(PE_INFO_REPEAT, 100). 304: 305: pending_exit_is_process_alive(Config) when is_list(Config) -> 306: ?line S = exit_op_test_init(), 307: ?line TestFun = fun (P) -> false = is_process_alive(P) end, 308: ?line repeated_exit_op_test(TestFun, ?PE_INFO_REPEAT), 309: ?line verify_pending_exit_success(S), 310: ?line comment(). 311: 312: pending_exit_process_info_1(Config) when is_list(Config) -> 313: ?line S = exit_op_test_init(), 314: ?line TestFun = fun (P) -> 315: undefined = process_info(P) 316: end, 317: ?line repeated_exit_op_test(TestFun, ?PE_INFO_REPEAT), 318: ?line verify_pending_exit_success(S), 319: ?line comment(). 320: 321: pending_exit_process_info_2(Config) when is_list(Config) -> 322: ?line S0 = exit_op_test_init(), 323: ?line repeated_exit_op_test(fun (P) -> 324: undefined = process_info(P, messages) 325: end, ?PE_INFO_REPEAT), 326: ?line S1 = verify_pending_exit_success(S0), 327: ?line repeated_exit_op_test(fun (P) -> 328: undefined = process_info(P, status) 329: end, ?PE_INFO_REPEAT), 330: ?line S2 = verify_pending_exit_success(S1), 331: ?line repeated_exit_op_test(fun (P) -> 332: undefined = process_info(P, links) 333: end, ?PE_INFO_REPEAT), 334: ?line S3 = verify_pending_exit_success(S2), 335: ?line repeated_exit_op_test(fun (P) -> 336: undefined = process_info(P, [messages]) 337: end, ?PE_INFO_REPEAT), 338: ?line S4 = verify_pending_exit_success(S3), 339: ?line repeated_exit_op_test(fun (P) -> 340: undefined = process_info(P, [status]) 341: end, ?PE_INFO_REPEAT), 342: ?line S5 = verify_pending_exit_success(S4), 343: ?line repeated_exit_op_test(fun (P) -> 344: undefined = process_info(P, [links]) 345: end, ?PE_INFO_REPEAT), 346: ?line S6 = verify_pending_exit_success(S5), 347: ?line repeated_exit_op_test(fun (P) -> 348: undefined = process_info(P, [status, 349: links]) 350: end, ?PE_INFO_REPEAT), 351: ?line S7 = verify_pending_exit_success(S6), 352: ?line repeated_exit_op_test(fun (P) -> 353: undefined = process_info(P, [messages, 354: status]) 355: end, ?PE_INFO_REPEAT), 356: ?line S8 = verify_pending_exit_success(S7), 357: ?line repeated_exit_op_test(fun (P) -> 358: undefined = process_info(P, [messages, 359: links]) 360: end, ?PE_INFO_REPEAT), 361: ?line S9 = verify_pending_exit_success(S8), 362: ?line repeated_exit_op_test( 363: fun (P) -> 364: undefined = process_info(P, [message_queue_len, 365: status]) 366: end, ?PE_INFO_REPEAT), 367: ?line S10 = verify_pending_exit_success(S9), 368: ?line repeated_exit_op_test(fun (P) -> 369: undefined = process_info(P, [messages, 370: links, 371: status]) 372: end, ?PE_INFO_REPEAT), 373: ?line verify_pending_exit_success(S10), 374: ?line comment(). 375: 376: pending_exit_process_display(Config) when is_list(Config) -> 377: ?line S = exit_op_test_init(), 378: ?line TestFun = fun (P) -> 379: badarg = try 380: erlang:process_display(P, backtrace) 381: catch 382: error:badarg -> badarg 383: end 384: end, 385: ?line repeated_exit_op_test(TestFun, ?PE_INFO_REPEAT), 386: ?line verify_pending_exit_success(S), 387: ?line comment(). 388: 389: pending_exit_group_leader(Config) when is_list(Config) -> 390: ?line S = exit_op_test_init(), 391: ?line TestFun = fun (P) -> 392: badarg = try 393: group_leader(self(), P) 394: catch 395: error:badarg -> badarg 396: end 397: end, 398: ?line repeated_exit_op_test(TestFun, ?PE_INFO_REPEAT), 399: ?line verify_pending_exit_success(S), 400: ?line comment(). 401: 402: %% 403: %% -- Internal utils -------------------------------------------------------- 404: %% 405: exit_op_test_init() -> 406: put(no_pending_exit_success, 0), 407: put(no_pending_exit_tries, 0), 408: {case {erlang:system_info(run_queues), 409: erlang:system_info(schedulers_online)} of 410: {RQ, SO} when RQ =:= 1; SO =:= 1 -> false; 411: _ -> true 412: end, 0, 0}. 413: 414: verify_pending_exit_success({false, _, _} = S) -> 415: S; 416: verify_pending_exit_success({true, S, T}) -> 417: NewS = get(no_pending_exit_success), 418: NewT = get(no_pending_exit_tries), 419: case NewT =:= T of 420: true -> ok; 421: _ -> case NewS > S of 422: true -> ok; 423: _ -> exit(no_pending_exits) 424: end 425: end, 426: {true, NewS, NewT}. 427: 428: comment() -> 429: {comment, 430: "Pending exit trigger ratio " 431: ++ integer_to_list(get(no_pending_exit_success)) 432: ++ "/" 433: ++ integer_to_list(get(no_pending_exit_tries)) 434: ++ "." 435: ++ case get(not_running_opt_test) of 436: true -> " No 'not running optimization' to disable."; 437: _ -> "" 438: end}. 439: 440: repeated_exit_op_test(TestFun, N) -> 441: WorkFun0 = fun () -> 442: lists:sort(lists:reverse(lists:seq(1, 1000))) 443: end, 444: repeat(fun () -> exit_op_test(TestFun, WorkFun0) end, N), 445: try erts_debug:set_internal_state(not_running_optimization, false) of 446: Bool when Bool == true; Bool == false -> 447: WorkFun1 = fun () -> 448: erts_debug:set_internal_state(sleep, 0), 449: lists:sort(lists:reverse(lists:seq(1, 1000))) 450: end, 451: repeat(fun () -> 452: exit_op_test(TestFun, WorkFun1) 453: end, N) 454: catch 455: error:notsup -> put(not_running_opt_test, true) 456: after 457: catch erts_debug:set_internal_state(not_running_optimization, true) 458: end. 459: 460: exit_op_test(TestFun, WorkFun) -> 461: Opts = case {erlang:system_info(run_queues), 462: erlang:system_info(schedulers_online)} of 463: {RQ, SO} when RQ =:= 1; SO =:= 1 -> []; 464: _ -> 465: process_flag(scheduler, 1), 466: [{scheduler, 2}] 467: end, 468: Master = self(), 469: Going = make_ref(), 470: P = spawn_opt(fun () -> 471: loop(10, WorkFun), 472: Master ! Going, 473: loop(infinity, WorkFun) 474: end, Opts), 475: receive Going -> ok end, 476: loop(10, WorkFun), 477: erlang:yield(), 478: exit(P, bang), 479: PE0 = have_pending_exit(P), 480: TestFun(P), 481: PE = case PE0 of 482: true -> true; 483: _ -> false 484: end, 485: case {PE, get(no_pending_exit_success), get(no_pending_exit_tries)} of 486: {true, undefined, undefined} -> 487: put(no_pending_exit_success, 1), 488: put(no_pending_exit_tries, 1); 489: {false, undefined, undefined} -> 490: put(no_pending_exit_success, 0), 491: put(no_pending_exit_tries, 1); 492: {true, S, T} -> 493: put(no_pending_exit_success, S+1), 494: put(no_pending_exit_tries, T+1); 495: {false, _S, T} -> 496: put(no_pending_exit_tries, T+1) 497: end, 498: ok. 499: 500: loop(infinity, WorkFun) -> 501: do_loop(infinity, WorkFun); 502: loop(0, _WorkFun) -> 503: ok; 504: loop(N, WorkFun) when is_integer(N) -> 505: do_loop(N-1, WorkFun). 506: 507: do_loop(N, WorkFun) -> 508: WorkFun(), 509: loop(N, WorkFun). 510: 511: repeat(_Fun, N) when is_integer(N), N =< 0 -> 512: ok; 513: repeat(Fun, N) when is_integer(N) -> 514: Fun(), 515: repeat(Fun, N-1). 516: 517: start_node(Config) -> 518: {A, B, C} = now(), 519: Name = list_to_atom(atom_to_list(?MODULE) 520: ++ "-" ++ atom_to_list(?config(testcase, Config)) 521: ++ "-" ++ integer_to_list(A) 522: ++ "-" ++ integer_to_list(B) 523: ++ "-" ++ integer_to_list(C)), 524: Pa = filename:dirname(code:which(?MODULE)), 525: ?t:start_node(Name, slave, [{args, "-pa " ++ Pa}]). 526: 527: stop_node(Node) -> 528: ?t:stop_node(Node). 529: 530: have_pending_exit() -> 531: have_pending_exit(self()). 532: 533: have_pending_exit(Pid) -> 534: erts_debug:get_internal_state({have_pending_exit, Pid}). 535: 536: force_gc() -> 537: erts_debug:set_internal_state(force_gc, self()). 538: 539: fake_exit(From, To, Reason) -> 540: erts_debug:set_internal_state(send_fake_exit_signal, {From, To, Reason}). 541: 542: available_internal_state(Bool) when Bool == true; Bool == false -> 543: case {Bool, 544: (catch erts_debug:get_internal_state(available_internal_state))} of 545: {true, true} -> 546: true; 547: {false, true} -> 548: erts_debug:set_internal_state(available_internal_state, false), 549: true; 550: {true, _} -> 551: erts_debug:set_internal_state(available_internal_state, true), 552: false; 553: {false, _} -> 554: false 555: end.