1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 1997-2018. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20 21-module(trace_SUITE). 22 23%%% 24%%% Tests the trace BIF. 25%%% 26 27-export([all/0, suite/0, init_per_testcase/2, end_per_testcase/2, 28 link_receive_call_correlation/0, 29 receive_trace/1, link_receive_call_correlation/1, self_send/1, 30 timeout_trace/1, send_trace/1, 31 procs_trace/1, dist_procs_trace/1, procs_new_trace/1, 32 suspend/1, suspend_exit/1, suspender_exit/1, 33 suspend_system_limit/1, suspend_opts/1, suspend_waiting/1, 34 new_clear/1, existing_clear/1, tracer_die/1, 35 set_on_spawn/1, set_on_first_spawn/1, cpu_timestamp/1, 36 set_on_link/1, set_on_first_link/1, 37 system_monitor_args/1, more_system_monitor_args/1, 38 system_monitor_long_gc_1/1, system_monitor_long_gc_2/1, 39 system_monitor_large_heap_1/1, system_monitor_large_heap_2/1, 40 system_monitor_long_schedule/1, 41 bad_flag/1, trace_delivered/1, trap_exit_self_receive/1, 42 trace_info_badarg/1, erl_704/1, ms_excessive_nesting/1]). 43 44-include_lib("common_test/include/ct.hrl"). 45 46%%% Internal exports 47-export([process/1]). 48 49suite() -> 50 [{ct_hooks,[ts_install_cth]}, 51 {timetrap, {minutes, 1}}]. 52 53all() -> 54 [cpu_timestamp, receive_trace, link_receive_call_correlation, 55 self_send, timeout_trace, 56 send_trace, procs_trace, dist_procs_trace, suspend, 57 suspend_exit, suspender_exit, 58 suspend_system_limit, suspend_opts, suspend_waiting, 59 new_clear, existing_clear, tracer_die, set_on_spawn, 60 set_on_first_spawn, set_on_link, set_on_first_link, 61 system_monitor_args, 62 more_system_monitor_args, system_monitor_long_gc_1, 63 system_monitor_long_gc_2, system_monitor_large_heap_1, 64 system_monitor_long_schedule, 65 system_monitor_large_heap_2, bad_flag, trace_delivered, 66 trap_exit_self_receive, trace_info_badarg, erl_704, 67 ms_excessive_nesting]. 68 69init_per_testcase(_Case, Config) -> 70 [{receiver,spawn(fun receiver/0)}|Config]. 71 72end_per_testcase(_Case, Config) -> 73 Receiver = proplists:get_value(receiver, Config), 74 unlink(Receiver), 75 exit(Receiver, die), 76 ok. 77 78%% No longer testing anything, just reporting whether cpu_timestamp 79%% is enabled or not. 80cpu_timestamp(Config) when is_list(Config) -> 81 %% Test whether cpu_timestamp is implemented on this platform. 82 Works = try erlang:trace(all, true, [cpu_timestamp]) of 83 _ -> 84 erlang:trace(all, false, [cpu_timestamp]), 85 true 86 catch 87 error:badarg -> false 88 end, 89 {comment,case Works of 90 false -> "cpu_timestamp is NOT implemented/does not work"; 91 true -> "cpu_timestamp works" 92 end}. 93 94 95%% Tests that trace(Pid, How, ['receive']) works. 96 97receive_trace(Config) when is_list(Config) -> 98 Receiver = proplists:get_value(receiver, Config), 99 100 %% Trace the process; make sure that we receive the trace messages. 101 1 = erlang:trace(Receiver, true, ['receive']), 102 Hello = {hello, world}, 103 Receiver ! Hello, 104 {trace, Receiver, 'receive', Hello} = receive_first_trace(), 105 Hello2 = {hello, again, world}, 106 Receiver ! Hello2, 107 {trace, Receiver, 'receive', Hello2} = receive_first_trace(), 108 receive_nothing(), 109 110 %% Test 'receive' with matchspec 111 F1 = fun ({Pat, IsMatching}) -> 112 set_trace_pattern('receive', Pat, []), 113 Receiver ! Hello, 114 case IsMatching of 115 true -> 116 {trace, Receiver, 'receive', Hello} = receive_first_trace(); 117 false -> 118 ok 119 end, 120 receive_nothing() 121 end, 122 From = self(), 123 Node = node(), 124 lists:foreach(F1, [{no, true}, 125 {[{[Node, undefined,"Unexpected"],[],[]}], false}, 126 {[{[Node, From,'_'],[],[]}], true}, 127 {[{[Node, '$1','_'],[{'=/=','$1',From}],[]}], false}, 128 {[{['$1', '_','_'],[{'=:=','$1',Node}],[]}], true}, 129 {false, false}, 130 {true, true}]), 131 132 %% Remote messages 133 OtherName = atom_to_list(?MODULE)++"_receive_trace", 134 {ok, OtherNode} = start_node(OtherName), 135 RemoteProc = spawn_link(OtherNode, ?MODULE, process, [self()]), 136 io:format("RemoteProc = ~p ~n", [RemoteProc]), 137 138 RemoteProc ! {send_please, Receiver, Hello}, 139 {trace, Receiver, 'receive', Hello} = receive_first_trace(), 140 RemoteProc ! {send_please, Receiver, 99}, 141 {trace, Receiver, 'receive', 99} = receive_first_trace(), 142 143 %% Remote with matchspec 144 F2 = fun (To, {Pat, IsMatching}) -> 145 set_trace_pattern('receive', Pat, []), 146 RemoteProc ! {send_please, To, Hello}, 147 case IsMatching of 148 true -> 149 {trace, Receiver, 'receive', Hello} = receive_first_trace(); 150 false -> 151 ok 152 end, 153 receive_nothing() 154 end, 155 F2(Receiver, {no, true}), 156 F2(Receiver, {[{[OtherNode, undefined,"Unexpected"],[],[]}], false}), 157 F2(Receiver, {[{[OtherNode, RemoteProc,'_'],[],[]}, 158 {[OtherNode, undefined,'_'],[],[]}], true}), 159 F2(Receiver, {[{[OtherNode, '$1','_'], 160 [{'orelse',{'=:=','$1',undefined},{'=/=',{node,'$1'},{node}}}], 161 []}], true}), 162 F2(Receiver, {[{['$1', '_','_'], [{'=:=','$1',OtherNode}], []}], true}), 163 F2(Receiver, {false, false}), 164 F2(Receiver, {true, true}), 165 166 %% Remote to named with matchspec 167 Name = trace_SUITE_receiver, 168 register(Name, Receiver), 169 NN = {Name, node()}, 170 F2(NN, {no, true}), 171 F2(NN, {[{[OtherNode, undefined,"Unexpected"],[],[]}], false}), 172 F2(NN, {[{[OtherNode, RemoteProc,'_'],[],[]}, 173 {[OtherNode, undefined,'_'],[],[]}], true}), 174 F2(NN, {[{[OtherNode, '$1','_'], 175 [{'orelse',{'=:=','$1',undefined},{'=/=',{node,'$1'},{node}}}], 176 []}], true}), 177 F2(NN, {[{['$1', '_','_'], [{'==','$1',OtherNode}], []}], true}), 178 F2(NN, {false, false}), 179 F2(NN, {true, true}), 180 181 unlink(RemoteProc), 182 true = stop_node(OtherNode), 183 184 %% Timeout 185 Receiver ! {set_timeout, 10}, 186 {trace, Receiver, 'receive', {set_timeout, 10}} = receive_first_trace(), 187 {trace, Receiver, 'receive', timeout} = receive_first_trace(), 188 erlang:trace_pattern('receive', [{[clock_service,undefined,timeout], [], []}], []), 189 Receiver ! {set_timeout, 7}, 190 {trace, Receiver, 'receive', timeout} = receive_first_trace(), 191 erlang:trace_pattern('receive', true, []), 192 193 %% Another process should not be able to trace Receiver. 194 process_flag(trap_exit, true), 195 Intruder = fun_spawn(fun() -> erlang:trace(Receiver, true, ['receive']) end), 196 {'EXIT', Intruder, {badarg, _}} = receive_first(), 197 198 %% Untrace the process; we should not receive anything. 199 1 = erlang:trace(Receiver, false, ['receive']), 200 Receiver ! {hello, there}, 201 Receiver ! any_garbage, 202 receive_nothing(), 203 204 %% Verify restrictions in matchspec for 'receive' 205 F3 = fun (Pat) -> {'EXIT', {badarg,_}} = (catch erlang:trace_pattern('receive', Pat, [])) end, 206 WC = ['_','_','_'], 207 F3([{WC,[],[{message, {process_dump}}]}]), 208 F3([{WC,[{is_seq_trace}],[]}]), 209 F3([{WC,[],[{set_seq_token,label,4711}]}]), 210 F3([{WC,[],[{get_seq_token}]}]), 211 F3([{WC,[],[{enable_trace,call}]}]), 212 F3([{WC,[],[{enable_trace,self(),call}]}]), 213 F3([{WC,[],[{disable_trace,call}]}]), 214 F3([{WC,[],[{disable_trace,self(),call}]}]), 215 F3([{WC,[],[{trace,[call],[]}]}]), 216 F3([{WC,[],[{trace,self(),[],[call]}]}]), 217 F3([{WC,[],[{caller}]}]), 218 F3([{WC,[],[{silent,true}]}]), 219 220 ok. 221 222%% Tests that receive of a message always happens before a call with 223%% that message and that links/unlinks are ordered together with the 224%% 'receive'. 225link_receive_call_correlation() -> 226 [{timetrap, {minutes, 5}}]. 227link_receive_call_correlation(Config) when is_list(Config) -> 228 Receiver = fun_spawn(fun F() -> 229 receive 230 stop -> ok; 231 M -> receive_msg(M), F() 232 end 233 end), 234 process_flag(trap_exit, true), 235 236 %% Trace the process; make sure that we receive the trace messages. 237 1 = erlang:trace(Receiver, true, ['receive', procs, call, timestamp, scheduler_id]), 238 1 = erlang:trace_pattern({?MODULE, receive_msg, '_'}, [], [local]), 239 240 Num = 100, 241 242 (fun F(0) -> []; 243 F(N) -> 244 if N rem 2 == 0 -> 245 link(Receiver); 246 true -> 247 unlink(Receiver) 248 end, 249 [Receiver ! N | F(N-1)] 250 end)(Num), 251 252 Receiver ! stop, 253 MonRef = erlang:monitor(process, Receiver), 254 receive {'DOWN', MonRef, _, _, _} -> ok end, 255 Ref = erlang:trace_delivered(Receiver), 256 receive {trace_delivered, _, Ref} -> ok end, 257 258 Msgs = (fun F() -> receive M -> [M | F()] after 1 -> [] end end)(), 259 260 case check_consistent(Receiver, Num, Num, Num, Msgs, false, undefined) of 261 ok -> 262 ok; 263 {error, Reason} -> 264 ct:log("~p", [Msgs]), 265 ct:fail({error, Reason}) 266 end. 267 268-define(schedid, , _). 269 270check_consistent(_Pid, Recv, Call, _LU, [Msg | _], _Received, _LinkedN) when Recv > Call -> 271 {error, Msg}; 272check_consistent(Pid, Recv, Call, LU, [Msg | Msgs], false, undefined) -> 273 274 case Msg of 275 {trace, Pid, 'receive', Recv ?schedid} -> 276 check_consistent(Pid,Recv - 1, Call, LU, Msgs, true, undefined); 277 {trace_ts, Pid, 'receive', Recv ?schedid, _} -> 278 check_consistent(Pid,Recv - 1, Call, LU, Msgs, true, undefined); 279 280 {trace, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid} -> 281 check_consistent(Pid,Recv, Call - 1, LU, Msgs, false, undefined); 282 {trace_ts, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid, _} -> 283 check_consistent(Pid,Recv, Call - 1, LU, Msgs, false, undefined); 284 285 {trace, Pid, _, _Self ?schedid} -> 286 check_consistent(Pid, Recv, Call, LU, Msgs, false, undefined); 287 {trace_ts, Pid, _, _Self ?schedid, _} -> 288 check_consistent(Pid, Recv, Call, LU, Msgs, false, undefined); 289 290 Msg -> 291 {error, Msg} 292 end; 293check_consistent(Pid, Recv, Call, LU, [Msg | Msgs], true, undefined) -> 294 295 case Msg of 296 {trace, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid} -> 297 check_consistent(Pid,Recv, Call - 1, LU, Msgs, true, undefined); 298 {trace_ts, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid, _} -> 299 check_consistent(Pid,Recv, Call - 1, LU, Msgs, true, undefined); 300 301 {trace, Pid, getting_linked, _Self ?schedid} -> 302 check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, Recv rem 2); 303 {trace_ts, Pid, getting_linked, _Self ?schedid, _} -> 304 check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, Recv rem 2); 305 306 {trace, Pid, getting_unlinked, _Self ?schedid} -> 307 check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, (Recv+1) rem 2); 308 {trace_ts, Pid, getting_unlinked, _Self ?schedid, _} -> 309 check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, (Recv+1) rem 2); 310 311 Msg -> 312 {error, Msg} 313 end; 314check_consistent(Pid, Recv, Call, LU, [Msg | Msgs], true, LinkedN) -> 315 UnlinkedN = (LinkedN + 1) rem 2, 316 317 case Msg of 318 {trace, Pid, 'receive', Recv ?schedid} when Recv == LU -> 319 check_consistent(Pid,Recv - 1, Call, LU, Msgs, true, LinkedN); 320 {trace_ts, Pid, 'receive', Recv ?schedid, _} when Recv == LU -> 321 check_consistent(Pid,Recv - 1, Call, LU, Msgs, true, LinkedN); 322 323 {trace, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid} -> 324 check_consistent(Pid,Recv, Call - 1, LU, Msgs, true, LinkedN); 325 {trace_ts, Pid, call, {?MODULE, receive_msg, [Call]} ?schedid, _} -> 326 check_consistent(Pid,Recv, Call - 1, LU, Msgs, true, LinkedN); 327 328 %% We check that for each receive we have gotten a 329 %% getting_linked or getting_unlinked message. Also 330 %% if we receive a getting_linked, then the next 331 %% message we expect to receive is an even number 332 %% and odd number for getting_unlinked. 333 {trace, Pid, getting_linked, _Self ?schedid} 334 when Recv rem 2 == LinkedN -> 335 check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, LinkedN); 336 {trace_ts, Pid, getting_linked, _Self ?schedid, _} 337 when Recv rem 2 == LinkedN -> 338 check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, LinkedN); 339 340 {trace, Pid, getting_unlinked, _Self ?schedid} 341 when Recv rem 2 == UnlinkedN -> 342 check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, LinkedN); 343 {trace_ts, Pid, getting_unlinked, _Self ?schedid, _} 344 when Recv rem 2 == UnlinkedN -> 345 check_consistent(Pid, Recv, Call, LU - 1, Msgs, true, LinkedN); 346 347 {trace,Pid,'receive',Ignore ?schedid} 348 when Ignore == stop; Ignore == timeout -> 349 check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN); 350 {trace_ts,Pid,'receive',Ignore ?schedid,_} 351 when Ignore == stop; Ignore == timeout -> 352 check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN); 353 354 {trace, Pid, exit, normal ?schedid} -> 355 check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN); 356 {trace_ts, Pid, exit, normal ?schedid, _} -> 357 check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN); 358 {'EXIT', Pid, normal} -> 359 check_consistent(Pid, Recv, Call, LU, Msgs, true, LinkedN); 360 Msg -> 361 {error, Msg} 362 end; 363check_consistent(_, 0, 0, 1, [], true, _) -> 364 ok; 365check_consistent(_, Recv, Call, LU, [], _, _) -> 366 {error,{Recv, Call, LU}}. 367 368receive_msg(M) -> 369 M. 370 371%% Test that traces are generated for messages sent 372%% and received to/from self(). 373self_send(Config) when is_list(Config) -> 374 Fun = 375 fun(Self, Parent) -> receive 376 go_ahead -> 377 self() ! from_myself, 378 Self(Self, Parent); 379 from_myself -> 380 Parent ! done 381 end 382 end, 383 Self = self(), 384 SelfSender = fun_spawn(Fun, [Fun, Self]), 385 erlang:trace(SelfSender, true, ['receive', 'send']), 386 SelfSender ! go_ahead, 387 receive {trace, SelfSender, 'receive', go_ahead} -> ok end, 388 receive {trace, SelfSender, 'receive', from_myself} -> ok end, 389 receive 390 {trace,SelfSender,send,from_myself,SelfSender} -> ok 391 end, 392 receive {trace,SelfSender,send,done,Self} -> ok end, 393 receive done -> ok end, 394 ok. 395 396%% Test that we can receive timeout traces. 397timeout_trace(Config) when is_list(Config) -> 398 Process = fun_spawn(fun process/0), 399 1 = erlang:trace(Process, true, ['receive']), 400 Process ! timeout_please, 401 {trace, Process, 'receive', timeout_please} = receive_first_trace(), 402 {trace, Process, 'receive', timeout} = receive_first_trace(), 403 receive_nothing(), 404 ok. 405 406%% Tests that trace(Pid, How, [send]) works. 407 408send_trace(Config) when is_list(Config) -> 409 process_flag(trap_exit, true), 410 Sender = fun_spawn(fun sender/0), 411 Receiver = proplists:get_value(receiver, Config), 412 413 %% Check that a message sent to another process is traced. 414 1 = erlang:trace(Sender, true, [send]), 415 F1 = fun (Pat) -> 416 set_trace_pattern(send, Pat, []), 417 Sender ! {send_please, Receiver, to_receiver}, 418 {trace, Sender, send, to_receiver, Receiver} = receive_first_trace(), 419 receive_nothing() 420 end, 421 lists:foreach(F1, [no, 422 [{[Receiver,to_receiver],[],[]}], 423 [{['_','_'],[],[]}], 424 [{['$1','_'],[{is_pid,'$1'}],[]}], 425 [{['_','$1'],[{is_atom,'$1'}],[]}], 426 true]), 427 428 %% Test {message, Msg} 429 F1m = fun ({Pat, Msg}) -> 430 set_trace_pattern(send, Pat, []), 431 Sender ! {send_please, Receiver, to_receiver}, 432 {trace, Sender, send, to_receiver, Receiver, Msg} = receive_first_trace(), 433 receive_nothing() 434 end, 435 lists:foreach(F1m, [{[{['_','_'],[],[{message, 4711}]}], 4711}, 436 {[{['_','_'],[],[{message, "4711"}]}], "4711"} 437 ]), 438 439 %% Test {message, {process_dump}} 440 set_trace_pattern(send, [{['_','_'],[],[{message, {process_dump}}]}], []), 441 Sender ! {send_please, Receiver, to_receiver}, 442 {trace, Sender, send, to_receiver, Receiver, ProcDump} = receive_first_trace(), 443 true = is_binary(ProcDump), 444 receive_nothing(), 445 446 %% Same test with false match spec 447 F2 = fun (Pat) -> 448 set_trace_pattern(send, Pat, []), 449 Sender ! {send_please, Receiver, to_receiver}, 450 receive_nothing() 451 end, 452 lists:foreach(F2, [[{[Sender,to_receiver],[],[]}], 453 [{[Receiver,nomatch],[],[]}], 454 [{['$1','_'],[{is_atom,'$1'}],[]}], 455 [{['_','$1'],[{is_pid,'$1'}],[]}], 456 false, 457 [{['_','_'],[],[{message,false}]}], 458 [{['_','_'],[],[{silent,true}]}]]), 459 erlang:trace_pattern(send, true, []), 460 erlang:trace(Sender, false, [silent]), 461 462 %% Check that a message sent to another registered process is traced. 463 register(?MODULE,Receiver), 464 F3 = fun (Pat) -> 465 set_trace_pattern(send, Pat, []), 466 Sender ! {send_please, ?MODULE, to_receiver}, 467 {trace, Sender, send, to_receiver, ?MODULE} = receive_first_trace(), 468 receive_nothing() 469 end, 470 lists:foreach(F3, [no, 471 [{[?MODULE,to_receiver],[],[]}], 472 [{['_','_'],[],[]}], 473 [{['$1','_'],[{is_atom,'$1'}],[]}], 474 [{['_','$1'],[{is_atom,'$1'}],[]}], 475 true]), 476 %% Again with false match spec 477 F4 = fun (Pat) -> 478 set_trace_pattern(send, Pat, []), 479 Sender ! {send_please, ?MODULE, to_receiver}, 480 receive_nothing() 481 end, 482 lists:foreach(F4, [[{[nomatch,to_receiver],[],[]}], 483 [{[?MODULE,nomatch],[],[]}], 484 [{['$1','_'],[{is_pid,'$1'}],[]}], 485 [{['_','$1'],[{is_pid,'$1'}],[]}], 486 [{['_','_'],[],[{message,false}]}], 487 [{['_','_'],[],[{silent,true}]}] 488 ]), 489 unregister(?MODULE), 490 erlang:trace_pattern(send, true, []), 491 erlang:trace(Sender, false, [silent]), 492 493 %% Check that a message sent to this process is traced. 494 F5 = fun (Pat) -> 495 set_trace_pattern(send, Pat, []), 496 Sender ! {send_please, self(), to_myself}, 497 receive to_myself -> ok end, 498 Self = self(), 499 {trace, Sender, send, to_myself, Self} = receive_first_trace(), 500 receive_nothing() 501 end, 502 lists:foreach(F5, [no, 503 [{[self(),to_myself],[],[]}], 504 [{['_','_'],[],[]}], 505 true]), 506 507 %% Check that a message sent to dead process is traced. 508 {Pid,Ref} = spawn_monitor(fun() -> ok end), 509 receive {'DOWN',Ref,_,_,_} -> ok end, 510 F6 = fun (Pat) -> 511 set_trace_pattern(send, Pat, []), 512 Sender ! {send_please, Pid, to_dead}, 513 {trace, Sender, send_to_non_existing_process, to_dead, Pid} = receive_first_trace(), 514 receive_nothing() 515 end, 516 lists:foreach(F6, [no, 517 [{[Pid,to_dead],[],[]}], 518 [{['_','_'],[],[]}], 519 true]), 520 521 %% Check that a message sent to unknown registrated process is traced. 522 BadargSender = fun_spawn(fun sender/0), 523 1 = erlang:trace(BadargSender, true, [send]), 524 unlink(BadargSender), 525 BadargSender ! {send_please, not_registered, to_unknown}, 526 {trace, BadargSender, send, to_unknown, not_registered} = receive_first_trace(), 527 receive_nothing(), 528 529 %% Another process should not be able to trace Sender. 530 Intruder = fun_spawn(fun() -> erlang:trace(Sender, true, [send]) end), 531 {'EXIT', Intruder, {badarg, _}} = receive_first(), 532 533 %% Untrace the sender process and make sure that we receive no more 534 %% trace messages. 535 1 = erlang:trace(Sender, false, [send]), 536 Sender ! {send_please, Receiver, to_receiver}, 537 Sender ! {send_please, self(), to_myself_again}, 538 receive to_myself_again -> ok end, 539 receive_nothing(), 540 541 {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [global])), 542 {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [local])), 543 {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [meta])), 544 {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [{meta,self()}])), 545 {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [call_count])), 546 {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, true, [call_time])), 547 {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, restart, [])), 548 {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, pause, [])), 549 {'EXIT',{badarg,_}} = (catch erlang:trace_pattern(send, [{['_','_'],[],[{caller}]}], [])), 550 551 %% Done. 552 ok. 553 554set_trace_pattern(_, no, _) -> 0; 555set_trace_pattern(MFA, Pat, Flg) -> 556 R = erlang:trace_pattern(MFA, Pat, Flg), 557 {match_spec, Pat} = erlang:trace_info(MFA, match_spec), 558 R. 559 560%% Test trace(Pid, How, [procs]). 561procs_trace(Config) when is_list(Config) -> 562 Name = list_to_atom(atom_to_list(?MODULE)++"_procs_trace"), 563 Self = self(), 564 process_flag(trap_exit, true), 565 %% 566 Proc1 = spawn_link(?MODULE, process, [Self]), 567 io:format("Proc1 = ~p ~n", [Proc1]), 568 Proc2 = spawn(?MODULE, process, [Self]), 569 io:format("Proc2 = ~p ~n", [Proc2]), 570 %% 571 1 = erlang:trace(Proc1, true, [procs, set_on_first_spawn]), 572 MFA = {?MODULE, process, [Self]}, 573 %% 574 %% spawn, link 575 Proc1 ! {spawn_link_please, Self, MFA}, 576 Proc3 = receive {spawned, Proc1, P3} -> P3 end, 577 receive {trace, Proc3, spawned, Proc1, MFA} -> ok end, 578 receive {trace, Proc3, getting_linked, Proc1} -> ok end, 579 {trace, Proc1, spawn, Proc3, MFA} = receive_first_trace(), 580 io:format("Proc3 = ~p ~n", [Proc3]), 581 {trace, Proc1, link, Proc3} = receive_first_trace(), 582 receive_nothing(), 583 %% 584 %% getting_unlinked by exit() 585 Proc1 ! {trap_exit_please, true}, 586 Reason3 = make_ref(), 587 Proc1 ! {send_please, Proc3, {exit_please, Reason3}}, 588 receive {Proc1, {'EXIT', Proc3, Reason3}} -> ok end, 589 receive {trace, Proc3, exit, Reason3} -> ok end, 590 {trace, Proc1, getting_unlinked, Proc3} = receive_first_trace(), 591 Proc1 ! {trap_exit_please, false}, 592 receive_nothing(), 593 %% 594 %% link 595 Proc1 ! {link_please, Proc2}, 596 {trace, Proc1, link, Proc2} = receive_first_trace(), 597 receive_nothing(), 598 %% 599 %% unlink 600 Proc1 ! {unlink_please, Proc2}, 601 {trace, Proc1, unlink, Proc2} = receive_first_trace(), 602 receive_nothing(), 603 %% 604 %% getting_linked 605 Proc2 ! {link_please, Proc1}, 606 {trace, Proc1, getting_linked, Proc2} = receive_first_trace(), 607 receive_nothing(), 608 %% 609 %% getting_unlinked 610 Proc2 ! {unlink_please, Proc1}, 611 {trace, Proc1, getting_unlinked, Proc2} = receive_first_trace(), 612 receive_nothing(), 613 %% 614 %% register 615 true = register(Name, Proc1), 616 {trace, Proc1, register, Name} = receive_first_trace(), 617 receive_nothing(), 618 %% 619 %% unregister 620 true = unregister(Name), 621 {trace, Proc1, unregister, Name} = receive_first_trace(), 622 receive_nothing(), 623 %% 624 %% exit (with registered name, due to link) 625 Reason4 = make_ref(), 626 Proc1 ! {spawn_link_please, Self, MFA}, 627 Proc4 = receive {spawned, Proc1, P4} -> P4 end, 628 {trace, Proc1, spawn, Proc4, MFA} = receive_first_trace(), 629 io:format("Proc4 = ~p ~n", [Proc4]), 630 {trace, Proc1, link, Proc4} = receive_first_trace(), 631 Proc1 ! {register_please, Name, Proc1}, 632 {trace, Proc1, register, Name} = receive_first_trace(), 633 Proc4 ! {exit_please, Reason4}, 634 receive {'EXIT', Proc1, Reason4} -> ok end, 635 {trace, Proc1, exit, Reason4} = receive_first_trace(), 636 {trace, Proc1, unregister, Name} = receive_first_trace(), 637 receive_nothing(), 638 %% 639 %% exit (not linked to tracing process) 640 1 = erlang:trace(Proc2, true, [procs]), 641 Reason2 = make_ref(), 642 Proc2 ! {exit_please, Reason2}, 643 {trace, Proc2, exit, Reason2} = receive_first_trace(), 644 receive_nothing(), 645 ok. 646 647 648dist_procs_trace(Config) when is_list(Config) -> 649 ct:timetrap({seconds, 15}), 650 OtherName = atom_to_list(?MODULE)++"_dist_procs_trace", 651 {ok, OtherNode} = start_node(OtherName), 652 Self = self(), 653 process_flag(trap_exit, true), 654 %% 655 Proc1 = spawn_link(?MODULE, process, [Self]), 656 io:format("Proc1 = ~p ~n", [Proc1]), 657 Proc2 = spawn(OtherNode, ?MODULE, process, [Self]), 658 io:format("Proc2 = ~p ~n", [Proc2]), 659 %% 660 1 = erlang:trace(Proc1, true, [procs]), 661 MFA = {?MODULE, process, [Self]}, 662 %% 663 %% getting_unlinked by exit() 664 Proc1 ! {spawn_link_please, Self, OtherNode, MFA}, 665 Proc1 ! {trap_exit_please, true}, 666 Proc3 = receive {spawned, Proc1, P3} -> P3 end, 667 io:format("Proc3 = ~p ~n", [Proc3]), 668 {trace, Proc1, link, Proc3} = receive_first_trace(), 669 Reason3 = make_ref(), 670 Proc1 ! {send_please, Proc3, {exit_please, Reason3}}, 671 receive {Proc1, {'EXIT', Proc3, Reason3}} -> ok end, 672 {trace, Proc1, getting_unlinked, Proc3} = receive_first_trace(), 673 Proc1 ! {trap_exit_please, false}, 674 receive_nothing(), 675 %% 676 %% link 677 Proc1 ! {link_please, Proc2}, 678 {trace, Proc1, link, Proc2} = receive_first_trace(), 679 receive_nothing(), 680 %% 681 %% unlink 682 Proc1 ! {unlink_please, Proc2}, 683 {trace, Proc1, unlink, Proc2} = receive_first_trace(), 684 receive_nothing(), 685 %% 686 %% getting_linked 687 Proc2 ! {link_please, Proc1}, 688 {trace, Proc1, getting_linked, Proc2} = receive_first_trace(), 689 receive_nothing(), 690 %% 691 %% getting_unlinked 692 Proc2 ! {unlink_please, Proc1}, 693 {trace, Proc1, getting_unlinked, Proc2} = receive_first_trace(), 694 receive_nothing(), 695 696 %% 697 %% exit (with registered name, due to link) 698 Name = list_to_atom(OtherName), 699 Reason2 = make_ref(), 700 Proc1 ! {link_please, Proc2}, 701 {trace, Proc1, link, Proc2} = receive_first_trace(), 702 Proc1 ! {register_please, Name, Proc1}, 703 {trace, Proc1, register, Name} = receive_first_trace(), 704 Proc2 ! {exit_please, Reason2}, 705 receive {'EXIT', Proc1, Reason2} -> ok end, 706 {trace, Proc1, exit, Reason2} = receive_first_trace(), 707 {trace, Proc1, unregister, Name} = receive_first_trace(), 708 receive_nothing(), 709 %% 710 %% Done. 711 true = stop_node(OtherNode), 712 ok. 713 714%% Test trace(new, How, [procs]). 715procs_new_trace(Config) when is_list(Config) -> 716 Self = self(), 717 process_flag(trap_exit, true), 718 %% 719 Proc1 = spawn_link(?MODULE, process, [Self]), 720 io:format("Proc1 = ~p ~n", [Proc1]), 721 %% 722 0 = erlang:trace(new, true, [procs]), 723 724 MFA = {?MODULE, process, [Self]}, 725 %% 726 %% spawn, link 727 Proc1 ! {spawn_link_please, Self, MFA}, 728 Proc3 = receive {spawned, Proc1, P3} -> P3 end, 729 receive {trace, Proc3, spawned, Proc1, MFA} -> ok end, 730 receive {trace, Proc3, getting_linked, Proc1} -> ok end, 731 io:format("Proc3 = ~p ~n", [Proc3]), 732 receive_nothing(), 733 %% 734 %% 735 %% exit (not linked to tracing process) 736 Reason1 = make_ref(), 737 Proc1 ! {exit_please, Reason1}, 738 receive {'EXIT', Proc1, Reason1} -> ok end, 739 {trace, Proc3, exit, Reason1} = receive_first_trace(), 740 receive_nothing(), 741 ok. 742 743 744 745%% Tests trace(Pid, How, [set_on_spawn]). 746 747set_on_spawn(Config) when is_list(Config) -> 748 Listener = fun_spawn(fun process/0), 749 750 %% Create and trace a process with the set_on_spawn flag. 751 %% Make sure it is traced. 752 Father_SOS = fun_spawn(fun process/0), 753 1 = erlang:trace(Father_SOS, true, [send, set_on_spawn]), 754 true = is_send_traced(Father_SOS, Listener, sos_father), 755 756 %% Have the process spawn of two children and test that they 757 %% are traced. 758 [Child1, Child2] = spawn_children(Father_SOS, 2), 759 true = is_send_traced(Child1, Listener, child1), 760 true = is_send_traced(Child2, Listener, child2), 761 762 %% Second generation. 763 [Child11, Child12] = spawn_children(Child1, 2), 764 true = is_send_traced(Child11, Listener, child11), 765 true = is_send_traced(Child12, Listener, child12), 766 ok. 767 768%% Tests trace(Pid, How, [set_on_first_spawn]). 769 770set_on_first_spawn(Config) when is_list(Config) -> 771 ct:timetrap({seconds, 10}), 772 Listener = fun_spawn(fun process/0), 773 774 %% Create and trace a process with the set_on_first_spawn flag. 775 %% Make sure it is traced. 776 Parent = fun_spawn(fun process/0), 777 1 = erlang:trace(Parent, true, [send, set_on_first_spawn]), 778 is_send_traced(Parent, Listener, sos_father), 779 780 %% Have the process spawn off three children and test that the 781 %% first is traced. 782 [Child1, Child2, Child3] = spawn_children(Parent, 3), 783 true = is_send_traced(Child1, Listener, child1), 784 false = is_send_traced(Child2, Listener, child2), 785 false = is_send_traced(Child3, Listener, child3), 786 receive_nothing(), 787 ok. 788 789%% Tests trace(Pid, How, [set_on_link]). 790 791set_on_link(_Config) -> 792 Listener = fun_spawn(fun process/0), 793 794 %% Create and trace a process with the set_on_link flag. 795 %% Make sure it is traced. 796 Father_SOL = fun_spawn(fun process/0), 797 1 = erlang:trace(Father_SOL, true, [send, set_on_link]), 798 true = is_send_traced(Father_SOL, Listener, sol_father), 799 800 %% Have the process spawn of two children and test that they 801 %% are traced. 802 [Child1, Child2] = spawn_children(Father_SOL, 2), 803 true = is_send_traced(Child1, Listener, child1), 804 true = is_send_traced(Child2, Listener, child2), 805 806 %% Second generation. 807 [Child11, Child12] = spawn_children(Child1, 2), 808 true = is_send_traced(Child11, Listener, child11), 809 true = is_send_traced(Child12, Listener, child12), 810 ok. 811 812%% Tests trace(Pid, How, [set_on_first_spawn]). 813 814set_on_first_link(_Config) -> 815 ct:timetrap({seconds, 10}), 816 Listener = fun_spawn(fun process/0), 817 818 %% Create and trace a process with the set_on_first_spawn flag. 819 %% Make sure it is traced. 820 Parent = fun_spawn(fun process/0), 821 1 = erlang:trace(Parent, true, [send, set_on_first_link]), 822 is_send_traced(Parent, Listener, sol_father), 823 824 %% Have the process spawn off three children and test that the 825 %% first is traced. 826 [Child1, Child2, Child3] = spawn_children(Parent, 3), 827 true = is_send_traced(Child1, Listener, child1), 828 false = is_send_traced(Child2, Listener, child2), 829 false = is_send_traced(Child3, Listener, child3), 830 receive_nothing(), 831 ok. 832 833 834 835%% Tests arguments to erlang:system_monitor/0,1,2 836system_monitor_args(Config) when is_list(Config) -> 837 Self = self(), 838 %% 839 OldMonitor = erlang:system_monitor(undefined), 840 undefined = erlang:system_monitor(Self, [{long_gc,0}]), 841 MinT = case erlang:system_monitor() of 842 {Self,[{long_gc,T}]} when is_integer(T), T > 0 -> T; 843 Other1 -> test_server:fault(Other1) 844 end, 845 {Self,[{long_gc,MinT}]} = erlang:system_monitor(), 846 {Self,[{long_gc,MinT}]} = 847 erlang:system_monitor({Self,[{large_heap,0}]}), 848 MinN = case erlang:system_monitor() of 849 {Self,[{large_heap,N}]} when is_integer(N), N > 0 -> N; 850 Other2 -> test_server:fault(Other2) 851 end, 852 {Self,[{large_heap,MinN}]} = erlang:system_monitor(), 853 {Self,[{large_heap,MinN}]} = 854 erlang:system_monitor(Self, [busy_port]), 855 {Self,[busy_port]} = erlang:system_monitor(), 856 {Self,[busy_port]} = 857 erlang:system_monitor({Self,[busy_dist_port]}), 858 {Self,[busy_dist_port]} = erlang:system_monitor(), 859 All = lists:sort([busy_port,busy_dist_port, 860 {long_gc,1},{large_heap,65535}]), 861 {Self,[busy_dist_port]} = erlang:system_monitor(Self, All), 862 {Self,A1} = erlang:system_monitor(), 863 All = lists:sort(A1), 864 {Self,A1} = erlang:system_monitor(Self, []), 865 Pid = spawn(fun () -> receive {Self,die} -> exit(die) end end), 866 Mref = erlang:monitor(process, Pid), 867 undefined = erlang:system_monitor(Pid, All), 868 {Pid,A2} = erlang:system_monitor(), 869 All = lists:sort(A2), 870 Pid ! {Self,die}, 871 receive {'DOWN',Mref,_,_,_} -> ok end, 872 undefined = erlang:system_monitor(OldMonitor), 873 erlang:yield(), 874 OldMonitor = erlang:system_monitor(), 875 %% 876 {'EXIT',{badarg,_}} = (catch erlang:system_monitor(atom)), 877 {'EXIT',{badarg,_}} = (catch erlang:system_monitor({})), 878 {'EXIT',{badarg,_}} = (catch erlang:system_monitor({1})), 879 {'EXIT',{badarg,_}} = (catch erlang:system_monitor({1,2,3})), 880 {'EXIT',{badarg,_}} = 881 (catch erlang:system_monitor({Self,atom})), 882 {'EXIT',{badarg,_}} = 883 (catch erlang:system_monitor(atom, atom)), 884 {'EXIT',{badarg,_}} = 885 (catch erlang:system_monitor({Self,[busy_port|busy_dist_port]})), 886 {'EXIT',{badarg,_}} = 887 (catch erlang:system_monitor(Self, [{long_gc,-1}])), 888 {'EXIT',{badarg,_}} = 889 (catch erlang:system_monitor({Self,[{long_gc,atom}]})), 890 {'EXIT',{badarg,_}} = 891 (catch erlang:system_monitor(Self,[{large_heap,-1}])), 892 {'EXIT',{badarg,_}} = 893 (catch erlang:system_monitor({Self,[{large_heap,atom}]})), 894 ok. 895 896 897%% Tests arguments to erlang:system_monitor/0,1,2 898more_system_monitor_args(Config) when is_list(Config) -> 899 try_l(64000), 900 try_l(16#7ffffff), 901 try_l(16#3fffffff), 902 try_l(16#7fffffff), 903 try_l(16#ffffffff), 904 ok. 905 906try_l(Val) -> 907 Self = self(), 908 Arbitrary1 = 77777, 909 Arbitrary2 = 88888, 910 911 erlang:system_monitor(undefined), 912 913 undefined = erlang:system_monitor(Self, [{long_gc,Val},{large_heap,Arbitrary1}]), 914 915 {Self,Comb0} = erlang:system_monitor(Self, [{long_gc,Arbitrary2},{large_heap,Val}]), 916 [{large_heap,Arbitrary1},{long_gc,Val}] = lists:sort(Comb0), 917 918 {Self,Comb1} = erlang:system_monitor(undefined), 919 [{large_heap,Val},{long_gc,Arbitrary2}] = lists:sort(Comb1). 920 921monitor_sys(Parent) -> 922 receive 923 {monitor,Pid,long_schedule,Data} when is_pid(Pid) -> 924 io:format("Long schedule of ~w: ~w~n",[Pid,Data]), 925 Parent ! {Pid,Data}, 926 monitor_sys(Parent); 927 {monitor,Port,long_schedule,Data} when is_port(Port) -> 928 {name,Name} = erlang:port_info(Port,name), 929 io:format("Long schedule of ~w (~p): ~w~n",[Port,Name,Data]), 930 Parent ! {Port,Data}, 931 monitor_sys(Parent); 932 Other -> 933 erlang:display(Other) 934 end. 935 936start_monitor() -> 937 Parent = self(), 938 Mpid = spawn_link(fun() -> monitor_sys(Parent) end), 939 erlang:system_monitor(Mpid,[{long_schedule,100}]), 940 erlang:yield(), % Need to be rescheduled for the trace to take 941 ok. 942 943%% Tests erlang:system_monitor(Pid, [{long_schedule,Time}]) 944system_monitor_long_schedule(Config) when is_list(Config) -> 945 Path = proplists:get_value(data_dir, Config), 946 erl_ddll:start(), 947 case (catch load_driver(Path, slow_drv)) of 948 ok -> 949 do_system_monitor_long_schedule(); 950 _Error -> 951 {skip, "Unable to load slow_drv (windows or no usleep()?)"} 952 end. 953do_system_monitor_long_schedule() -> 954 start_monitor(), 955 Port = open_port({spawn_driver,slow_drv}, []), 956 "ok" = erlang:port_control(Port,0,[]), 957 Self = self(), 958 receive 959 {Self,L} when is_list(L) -> 960 ok 961 after 1000 -> 962 ct:fail(no_trace_of_pid) 963 end, 964 "ok" = erlang:port_control(Port,1,[]), 965 receive 966 {Port,LL} when is_list(LL) -> 967 ok 968 after 1000 -> 969 ct:fail(no_trace_of_port) 970 end, 971 port_close(Port), 972 erlang:system_monitor(undefined), 973 ok. 974 975 976-define(LONG_GC_SLEEP, 670). 977 978%% Tests erlang:system_monitor(Pid, [{long_gc,Time}]) 979system_monitor_long_gc_1(Config) when is_list(Config) -> 980 erts_debug:set_internal_state(available_internal_state, true), 981 try 982 case erts_debug:get_internal_state(force_heap_frags) of 983 true -> 984 {skip,"emulator with FORCE_HEAP_FRAGS defined"}; 985 false -> 986 %% Add ?LONG_GC_SLEEP ms to all gc 987 erts_debug:set_internal_state(test_long_gc_sleep, 988 ?LONG_GC_SLEEP), 989 LoadFun = fun () -> 990 garbage_collect(), 991 self() 992 end, 993 long_gc(LoadFun, false) 994 end 995 after 996 erts_debug:set_internal_state(test_long_gc_sleep, 0), 997 erts_debug:set_internal_state(available_internal_state, false) 998 end. 999 1000%% Tests erlang:system_monitor(Pid, [{long_gc,Time}]) 1001system_monitor_long_gc_2(Config) when is_list(Config) -> 1002 erts_debug:set_internal_state(available_internal_state, true), 1003 try 1004 case erts_debug:get_internal_state(force_heap_frags) of 1005 true -> 1006 {skip,"emulator with FORCE_HEAP_FRAGS defined"}; 1007 false -> 1008 %% Add ?LONG_GC_SLEEP ms to all gc 1009 erts_debug:set_internal_state(test_long_gc_sleep, 1010 ?LONG_GC_SLEEP), 1011 Parent = self(), 1012 LoadFun = 1013 fun () -> 1014 Ref = make_ref(), 1015 Pid = 1016 spawn_link( 1017 fun () -> 1018 garbage_collect(), 1019 Parent ! {Ref, self()} 1020 end), 1021 receive {Ref, Pid} -> Pid end 1022 end, 1023 long_gc(LoadFun, true), 1024 long_gc(LoadFun, true), 1025 long_gc(LoadFun, true) 1026 end 1027 after 1028 erts_debug:set_internal_state(test_long_gc_sleep, 0), 1029 erts_debug:set_internal_state(available_internal_state, false) 1030 end. 1031 1032long_gc(LoadFun, ExpectMonMsg) -> 1033 Self = self(), 1034 Time = 1, 1035 OldMonitor = erlang:system_monitor(Self, [{long_gc,Time}]), 1036 Pid = LoadFun(), 1037 Ref = erlang:trace_delivered(Pid), 1038 receive {trace_delivered, Pid, Ref} -> ok end, 1039 {Self,[{long_gc,Time}]} = erlang:system_monitor(OldMonitor), 1040 case {long_gc_check(Pid, Time, undefined), ExpectMonMsg} of 1041 {ok, true} when Pid =/= Self -> 1042 ok; 1043 {ok, false} -> 1044 ct:fail(unexpected_system_monitor_message_received); 1045 {undefined, false} -> 1046 ok; 1047 {undefined, true} -> 1048 ct:fail(no_system_monitor_message_received) 1049 end. 1050 1051long_gc_check(Pid, Time, Result) -> 1052 receive 1053 {monitor,Pid,long_gc,L} = Monitor -> 1054 case lists:foldl( 1055 fun (_, error) -> 1056 error; 1057 ({timeout,T}, N) when is_integer(T), 1058 Time =< T, T =< 10*?LONG_GC_SLEEP -> 1059 %% OTP-7622. The time T must be within reasonable limits 1060 %% for the test to pass. 1061 N-1; 1062 ({heap_size,_}, N) -> 1063 N-1; 1064 ({old_heap_size,_}, N) -> 1065 N-1; 1066 ({stack_size,_}, N) -> 1067 N-1; 1068 ({mbuf_size,_}, N) -> 1069 N-1; 1070 ({heap_block_size,_}, N) -> 1071 N-1; 1072 ({old_heap_block_size,_}, N) -> 1073 N-1; 1074 (_, _) -> 1075 error 1076 end, 7, L) of 1077 0 -> 1078 long_gc_check(Pid, Time, ok); 1079 error -> 1080 {error,Monitor} 1081 end; 1082 {monitor,_,long_gc,_} -> 1083 long_gc_check(Pid, Time, Result); 1084 Other -> 1085 {error,Other} 1086 after 0 -> 1087 Result 1088 end. 1089 1090%% Tests erlang:system_monitor(Pid, [{large_heap,Size}]) 1091system_monitor_large_heap_1(Config) when is_list(Config) -> 1092 LoadFun = 1093 fun (Size) -> 1094 List = seq(1,2*Size), 1095 garbage_collect(), 1096 true = lists:prefix([1], List), 1097 self() 1098 end, 1099 large_heap(LoadFun, false). 1100 1101%% Tests erlang:system_monitor(Pid, [{large_heap,Size}]) 1102system_monitor_large_heap_2(Config) when is_list(Config) -> 1103 Parent = self(), 1104 LoadFun = 1105 fun (Size) -> 1106 Ref = make_ref(), 1107 Pid = 1108 spawn_opt(fun () -> 1109 garbage_collect(), 1110 Parent ! {Ref, self()} 1111 end, 1112 [link, {min_heap_size, 2*Size}]), 1113 receive {Ref, Pid} -> Pid end 1114 end, 1115 large_heap(LoadFun, true). 1116 1117large_heap(LoadFun, ExpectMonMsg) -> 1118 ct:timetrap({seconds, 20}), 1119 %% 1120 Size = 65535, 1121 Self = self(), 1122 NewMonitor = {Self,[{large_heap,Size}]}, 1123 OldMonitor = erlang:system_monitor(NewMonitor), 1124 Pid = LoadFun(Size), 1125 Ref = erlang:trace_delivered(Pid), 1126 receive {trace_delivered, Pid, Ref} -> ok end, 1127 {Self,[{large_heap,Size}]} = erlang:system_monitor(OldMonitor), 1128 case {large_heap_check(Pid, Size, undefined), ExpectMonMsg} of 1129 {ok, true} when Pid =/= Self -> 1130 ok; 1131 {ok, false} -> 1132 ct:fail(unexpected_system_monitor_message_received); 1133 {undefined, false} -> 1134 ok; 1135 {undefined, true} -> 1136 ct:fail(no_system_monitor_message_received) 1137 end, 1138 ok. 1139 1140large_heap_check(Pid, Size, Result) -> 1141 receive 1142 {monitor,Pid,large_heap,L} = Monitor -> 1143 case lists:foldl( 1144 fun (_, error) -> 1145 error; 1146 ({heap_size,_}, N) -> 1147 N-1; 1148 ({old_heap_size,_}, N) -> 1149 N-1; 1150 ({stack_size,_}, N) -> 1151 N-1; 1152 ({mbuf_size,_}, N) -> 1153 N-1; 1154 ({heap_block_size,_}, N) -> 1155 N-1; 1156 ({old_heap_block_size,_}, N) -> 1157 N-1; 1158 (_, _) -> 1159 error 1160 end, 6, L) of 1161 0 -> 1162 large_heap_check(Pid, Size, ok); 1163 error -> 1164 {error,Monitor} 1165 end; 1166 {monitor,_,large_heap,_} -> 1167 large_heap_check(Pid, Size, Result); 1168 Other -> 1169 {error,Other} 1170 after 0 -> 1171 Result 1172 end. 1173 1174seq(N, M) -> 1175 seq(N, M, []). 1176 1177seq(M, M, R) -> 1178 lists:reverse(R); 1179seq(N, M, R) -> 1180 seq(N+1, M, [N|R]). 1181 1182 1183is_send_traced(Pid, Listener, Msg) -> 1184 Pid ! {send_please, Listener, Msg}, 1185 receive 1186 Any -> 1187 {trace, Pid, send, Msg, Listener} = Any, 1188 true 1189 after 1000 -> 1190 false 1191 end. 1192 1193%% This procedure assumes that the Parent process is send traced. 1194 1195spawn_children(Parent, Number) -> 1196 spawn_children(Parent, Number, []). 1197 1198spawn_children(_Parent, 0, Result) -> 1199 lists:reverse(Result); 1200spawn_children(Parent, Number, Result) -> 1201 Self = self(), 1202 Parent ! {spawn_please, Self, fun process/0}, 1203 Child = 1204 receive 1205 {trace, Parent, send, {spawned, Pid}, Self} -> Pid 1206 end, 1207 receive 1208 {spawned, Child} -> 1209 spawn_children(Parent, Number-1, [Child|Result]) 1210 end. 1211 1212%% Test erlang:suspend/1 and erlang:resume/1. 1213suspend(Config) when is_list(Config) -> 1214 ct:timetrap({minutes,2}), 1215 Worker = fun_spawn(fun worker/0), 1216 %% Suspend a process and test that it is suspended. 1217 ok = do_suspend(Worker, 10000), 1218 ok. 1219 1220do_suspend(_Pid, 0) -> 1221 ok; 1222do_suspend(Pid, N) -> 1223 %% Suspend a process and test that it is suspended. 1224 true = erlang:suspend_process(Pid), 1225 {status, suspended} = process_info(Pid, status), 1226 1227 %% Unsuspend the process and make sure it starts working. 1228 true = erlang:resume_process(Pid), 1229 case process_info(Pid, status) of 1230 {status, runnable} -> ok; 1231 {status, running} -> ok; 1232 {status, garbage_collecting} -> ok; 1233 ST -> ct:fail(ST) 1234 end, 1235 erlang:yield(), 1236 do_suspend(Pid, N-1). 1237 1238suspend_exit(Config) when is_list(Config) -> 1239 ct:timetrap({minutes, 2}), 1240 rand:seed(exsplus, {4711,17,4711}), 1241 do_suspend_exit(5000), 1242 ok. 1243 1244do_suspend_exit(0) -> 1245 ok; 1246do_suspend_exit(N) -> 1247 Work = rand:uniform(50), 1248 Parent = self(), 1249 {Suspendee, Mon2} 1250 = spawn_monitor(fun () -> 1251 suspend_exit_work(Work), 1252 exit(normal) 1253 end), 1254 {Suspender, Mon1} 1255 = spawn_monitor( 1256 fun () -> 1257 suspend_exit_work(Work div 2), 1258 Parent ! {doing_suspend, self()}, 1259 case catch erlang:suspend_process(Suspendee) of 1260 {'EXIT', _} -> 1261 ok; 1262 true -> 1263 erlang:resume_process(Suspendee) 1264 end 1265 end), 1266 receive 1267 {doing_suspend, Suspender} -> 1268 case N rem 2 of 1269 0 -> exit(Suspender, bang); 1270 1 -> ok 1271 end 1272 end, 1273 receive {'DOWN', Mon1, process, Suspender, _} -> ok end, 1274 receive {'DOWN', Mon2, process, Suspendee, _} -> ok end, 1275 do_suspend_exit(N-1). 1276 1277 1278 1279 1280suspend_exit_work(0) -> 1281 ok; 1282suspend_exit_work(N) -> 1283 process_info(self()), 1284 suspend_exit_work(N-1). 1285 1286-define(CHK_SUSPENDED(P,B), chk_suspended(P, B, ?LINE)). 1287 1288chk_suspended(P, Bool, Line) -> 1289 {Bool, Line} = {({status, suspended} == process_info(P, status)), Line}. 1290 1291suspender_exit(Config) when is_list(Config) -> 1292 ct:timetrap({minutes, 3}), 1293 P1 = spawn_link(fun () -> receive after infinity -> ok end end), 1294 {'EXIT', _} = (catch erlang:resume_process(P1)), 1295 {P2, M2} = spawn_monitor( 1296 fun () -> 1297 ?CHK_SUSPENDED(P1, false), 1298 erlang:suspend_process(P1), 1299 ?CHK_SUSPENDED(P1, true), 1300 erlang:suspend_process(P1), 1301 erlang:suspend_process(P1), 1302 erlang:suspend_process(P1), 1303 ?CHK_SUSPENDED(P1, true), 1304 erlang:resume_process(P1), 1305 erlang:resume_process(P1), 1306 erlang:resume_process(P1), 1307 ?CHK_SUSPENDED(P1, true), 1308 erlang:resume_process(P1), 1309 ?CHK_SUSPENDED(P1, false), 1310 erlang:suspend_process(P1), 1311 erlang:suspend_process(P1), 1312 erlang:suspend_process(P1), 1313 ?CHK_SUSPENDED(P1, true), 1314 exit(bang) 1315 end), 1316 receive 1317 {'DOWN', M2,process,P2,R2} -> 1318 bang = R2, 1319 ?CHK_SUSPENDED(P1, false) 1320 end, 1321 Parent = self(), 1322 {P3, M3} = spawn_monitor( 1323 fun () -> 1324 erlang:suspend_process(P1), 1325 ?CHK_SUSPENDED(P1, true), 1326 Parent ! self(), 1327 receive after infinity -> ok end 1328 end), 1329 {P4, M4} = spawn_monitor( 1330 fun () -> 1331 erlang:suspend_process(P1), 1332 ?CHK_SUSPENDED(P1, true), 1333 Parent ! self(), 1334 receive after infinity -> ok end 1335 end), 1336 {P5, M5} = spawn_monitor( 1337 fun () -> 1338 erlang:suspend_process(P1), 1339 ?CHK_SUSPENDED(P1, true), 1340 Parent ! self(), 1341 receive after infinity -> ok end 1342 end), 1343 {P6, M6} = spawn_monitor( 1344 fun () -> 1345 erlang:suspend_process(P1), 1346 ?CHK_SUSPENDED(P1, true), 1347 Parent ! self(), 1348 receive after infinity -> ok end 1349 end), 1350 {P7, M7} = spawn_monitor( 1351 fun () -> 1352 erlang:suspend_process(P1), 1353 ?CHK_SUSPENDED(P1, true), 1354 Parent ! self(), 1355 receive after infinity -> ok end 1356 end), 1357 receive P3 -> ok end, 1358 receive P4 -> ok end, 1359 receive P5 -> ok end, 1360 receive P6 -> ok end, 1361 receive P7 -> ok end, 1362 ?CHK_SUSPENDED(P1, true), 1363 exit(P3, bang), 1364 receive 1365 {'DOWN',M3,process,P3,R3} -> 1366 bang = R3, 1367 ?CHK_SUSPENDED(P1, true) 1368 end, 1369 exit(P4, bang), 1370 receive 1371 {'DOWN',M4,process,P4,R4} -> 1372 bang = R4, 1373 ?CHK_SUSPENDED(P1, true) 1374 end, 1375 exit(P5, bang), 1376 receive 1377 {'DOWN',M5,process,P5,R5} -> 1378 bang = R5, 1379 ?CHK_SUSPENDED(P1, true) 1380 end, 1381 exit(P6, bang), 1382 receive 1383 {'DOWN',M6,process,P6,R6} -> 1384 bang = R6, 1385 ?CHK_SUSPENDED(P1, true) 1386 end, 1387 exit(P7, bang), 1388 receive 1389 {'DOWN',M7,process,P7,R7} -> 1390 bang = R7, 1391 ?CHK_SUSPENDED(P1, false) 1392 end, 1393 unlink(P1), 1394 exit(P1, bong), 1395 ok. 1396 1397suspend_system_limit(Config) when is_list(Config) -> 1398 case os:getenv("ERL_EXTREME_TESTING") of 1399 "true" -> 1400 ct:timetrap({minutes, 3*60}), 1401 P = spawn_link(fun () -> receive after infinity -> ok end end), 1402 suspend_until_system_limit(P), 1403 unlink(P), 1404 exit(P, bye), 1405 ok; 1406 _ -> 1407 {skip, "Takes too long time for normal testing"} 1408 end. 1409 1410suspend_until_system_limit(P) -> 1411 suspend_until_system_limit(P, 0, 0). 1412 1413suspend_until_system_limit(P, N, M) -> 1414 NewM = case M of 1415 1 -> 1416 ?CHK_SUSPENDED(P, true), 2; 1417 1000000 -> 1418 erlang:display(N), 1; 1419 _ -> 1420 M+1 1421 end, 1422 case catch erlang:suspend_process(P) of 1423 true -> 1424 suspend_until_system_limit(P, N+1, NewM); 1425 {'EXIT', R} when R == system_limit; 1426 element(1, R) == system_limit -> 1427 io:format("system limit at ~p~n", [N]), 1428 resume_from_system_limit(P, N, 0); 1429 Error -> 1430 ct:fail(Error) 1431 end. 1432 1433resume_from_system_limit(P, 0, _) -> 1434 ?CHK_SUSPENDED(P, false), 1435 {'EXIT', _} = (catch erlang:resume_process(P)), 1436 ok; 1437resume_from_system_limit(P, N, M) -> 1438 NewM = case M of 1439 1 -> 1440 ?CHK_SUSPENDED(P, true), 2; 1441 1000000 -> 1442 erlang:display(N), 1; 1443 _ -> 1444 M+1 1445 end, 1446 erlang:resume_process(P), 1447 resume_from_system_limit(P, N-1, NewM). 1448 1449-record(susp_info, {async = 0, 1450 dbl_async = 0, 1451 synced = 0, 1452 async_once = 0}). 1453 1454suspend_opts(Config) when is_list(Config) -> 1455 ct:timetrap({minutes, 3}), 1456 Self = self(), 1457 wait_for_empty_runq(10), 1458 Tok = spawn_link(fun () -> 1459 Self ! self(), 1460 tok_trace_loop(Self, 0, 1000000000) 1461 end), 1462 TC = 1000, 1463 receive Tok -> ok end, 1464 SF = fun (N, #susp_info {async = A, 1465 dbl_async = AA, 1466 synced = S, 1467 async_once = AO} = Acc) -> 1468 Tag = {make_ref(), self()}, 1469 erlang:suspend_process(Tok, [{asynchronous, Tag}]), 1470 Res = case {suspend_count(Tok), N rem 4} of 1471 {0, 2} -> 1472 erlang:suspend_process(Tok, 1473 [asynchronous]), 1474 case suspend_count(Tok) of 1475 2 -> 1476 erlang:resume_process(Tok), 1477 Acc#susp_info{async = A+1}; 1478 0 -> 1479 erlang:resume_process(Tok), 1480 Acc#susp_info{async = A+1, 1481 dbl_async = AA+1} 1482 end; 1483 {0, 1} -> 1484 erlang:suspend_process(Tok, 1485 [asynchronous, 1486 unless_suspending]), 1487 case suspend_count(Tok) of 1488 1 -> 1489 Acc#susp_info{async = A+1}; 1490 0 -> 1491 Acc#susp_info{async = A+1, 1492 async_once = AO+1} 1493 end; 1494 {0, 0} -> 1495 erlang:suspend_process(Tok, 1496 [unless_suspending]), 1497 1 = suspend_count(Tok), 1498 Acc#susp_info{async = A+1, 1499 synced = S+1}; 1500 {0, _} -> 1501 Acc#susp_info{async = A+1}; 1502 _ -> 1503 Acc 1504 end, 1505 receive 1506 {Tag, Result} -> 1507 suspended = Result, 1508 erlang:resume_process(Tok) 1509 end, 1510 erlang:yield(), 1511 Res 1512 end, 1513 SI = repeat_acc(SF, TC, #susp_info{}), 1514 erlang:suspend_process(Tok, [asynchronous]), 1515 %% Verify that it eventually suspends 1516 WaitTime0 = 10, 1517 WaitTime1 = case {erlang:system_info(debug_compiled), 1518 erlang:system_info(lock_checking)} of 1519 {false, false} -> 1520 WaitTime0; 1521 {false, true} -> 1522 WaitTime0*5; 1523 _ -> 1524 WaitTime0*10 1525 end, 1526 WaitTime = case {erlang:system_info(schedulers_online), 1527 erlang:system_info(logical_processors)} of 1528 {Schdlrs, CPUs} when is_integer(CPUs), 1529 Schdlrs =< CPUs -> 1530 WaitTime1; 1531 _ -> 1532 WaitTime1*10 1533 end, 1534 receive after WaitTime -> ok end, 1535 1 = suspend_count(Tok), 1536 erlang:suspend_process(Tok, [asynchronous]), 1537 2 = suspend_count(Tok), 1538 erlang:suspend_process(Tok, [asynchronous]), 1539 3 = suspend_count(Tok), 1540 erlang:suspend_process(Tok), 1541 4 = suspend_count(Tok), 1542 erlang:suspend_process(Tok), 1543 5 = suspend_count(Tok), 1544 erlang:suspend_process(Tok, [unless_suspending]), 1545 5 = suspend_count(Tok), 1546 erlang:suspend_process(Tok, [unless_suspending, 1547 asynchronous]), 1548 5 = suspend_count(Tok), 1549 erlang:resume_process(Tok), 1550 erlang:resume_process(Tok), 1551 erlang:resume_process(Tok), 1552 erlang:resume_process(Tok), 1553 1 = suspend_count(Tok), 1554 io:format("Main suspends: ~p~n" 1555 "Main async: ~p~n" 1556 "Double async: ~p~n" 1557 "Async once: ~p~n" 1558 "Synced: ~p~n", 1559 [TC, 1560 SI#susp_info.async, 1561 SI#susp_info.dbl_async, 1562 SI#susp_info.async_once, 1563 SI#susp_info.synced]), 1564 case erlang:system_info(schedulers_online) of 1565 1 -> 1566 ok; 1567 _ -> 1568 true = SI#susp_info.async =/= 0 1569 end, 1570 unlink(Tok), 1571 exit(Tok, bang), 1572 ok. 1573 1574suspend_count(Suspendee) -> 1575 suspend_count(self(), Suspendee). 1576 1577suspend_count(Suspender, Suspendee) -> 1578 {suspending, SList} = process_info(Suspender, suspending), 1579 1580 case lists:keysearch(Suspendee, 1, SList) of 1581 {value, {_Suspendee, 0, 0}} -> 1582 ct:fail({bad_suspendee_list, SList}); 1583 {value, {Suspendee, Count, 0}} when is_integer(Count), Count > 0 -> 1584 {status, suspended} = process_info(Suspendee, status), 1585 Count; 1586 {value, {Suspendee, 0, Outstanding}} when is_integer(Outstanding), 1587 Outstanding > 0 -> 1588 0; 1589 false -> 1590 0; 1591 Error -> 1592 ct:fail({bad_suspendee_list, Error, SList}) 1593 end. 1594 1595repeat_acc(Fun, N, Acc) -> 1596 repeat_acc(Fun, 0, N, Acc). 1597 1598repeat_acc(_Fun, N, N, Acc) -> 1599 Acc; 1600repeat_acc(Fun, N, M, Acc) -> 1601 repeat_acc(Fun, N+1, M, Fun(N, Acc)). 1602 1603%% Tests that waiting process can be suspended 1604%% (bug in R2D and earlier; see OTP-1488). 1605 1606%% Test that a waiting process can be suspended. 1607suspend_waiting(Config) when is_list(Config) -> 1608 Process = fun_spawn(fun process/0), 1609 receive after 1 -> ok end, 1610 true = erlang:suspend_process(Process), 1611 {status, suspended} = process_info(Process, status), 1612 ok. 1613 1614 1615%% Test that erlang:trace(new, true, ...) is cleared when tracer dies. 1616new_clear(Config) when is_list(Config) -> 1617 Tracer = proplists:get_value(receiver, Config), 1618 1619 0 = erlang:trace(new, true, [send, {tracer, Tracer}]), 1620 {flags, [send]} = erlang:trace_info(new, flags), 1621 {tracer, Tracer} = erlang:trace_info(new, tracer), 1622 Mref = erlang:monitor(process, Tracer), 1623 true = exit(Tracer, done), 1624 receive 1625 {'DOWN',Mref,_,_,_} -> ok 1626 end, 1627 {flags, []} = erlang:trace_info(new, flags), 1628 {tracer, []} = erlang:trace_info(new, tracer), 1629 ok. 1630 1631 1632 1633%% Test that erlang:trace(all, false, ...) works without tracer. 1634existing_clear(Config) when is_list(Config) -> 1635 Self = self(), 1636 1637 Tracer = proplists:get_value(receiver, Config), 1638 N = erlang:trace(existing, true, [send, {tracer, Tracer}]), 1639 {flags, [send]} = erlang:trace_info(Self, flags), 1640 {tracer, Tracer} = erlang:trace_info(Self, tracer), 1641 M = erlang:trace(all, false, [all]), 1642 io:format("Started trace on ~p processes and stopped on ~p~n", 1643 [N, M]), 1644 {flags, []} = erlang:trace_info(Self, flags), 1645 {tracer, []} = erlang:trace_info(Self, tracer), 1646 M = N, % Used to be N + 1, but from 19.0 the tracer is also traced 1647 1648 ok. 1649 1650%% Test that erlang:trace/3 can be called on processes where the 1651%% tracer has died. OTP-13928 1652tracer_die(Config) when is_list(Config) -> 1653 Proc = spawn_link(fun receiver/0), 1654 1655 Tracer = spawn_link(fun receiver/0), 1656 timer:sleep(1), 1657 N = erlang:trace(existing, true, [send, {tracer, Tracer}]), 1658 {flags, [send]} = erlang:trace_info(Proc, flags), 1659 {tracer, Tracer} = erlang:trace_info(Proc, tracer), 1660 unlink(Tracer), 1661 exit(Tracer, die), 1662 1663 Tracer2 = spawn_link(fun receiver/0), 1664 timer:sleep(1), 1665 N = erlang:trace(existing, true, [send, {tracer, Tracer2}]), 1666 {flags, [send]} = erlang:trace_info(Proc, flags), 1667 {tracer, Tracer2} = erlang:trace_info(Proc, tracer), 1668 unlink(Tracer2), 1669 exit(Tracer2, die), 1670 1671 Tracer3 = spawn_link(fun receiver/0), 1672 timer:sleep(1), 1673 1 = erlang:trace(Proc, true, [send, {tracer, Tracer3}]), 1674 {flags, [send]} = erlang:trace_info(Proc, flags), 1675 {tracer, Tracer3} = erlang:trace_info(Proc, tracer), 1676 unlink(Tracer3), 1677 exit(Tracer3, die), 1678 1679 ok. 1680 1681%% Test that an invalid flag cause badarg 1682bad_flag(Config) when is_list(Config) -> 1683 %% A bad flag could deadlock the SMP emulator in erts-5.5 1684 {'EXIT', {badarg, _}} = (catch erlang:trace(new, 1685 true, 1686 [not_a_valid_flag])), 1687 1688 %% Leaks of {tracer,_} in OTP 23.2 1689 Pid = spawn(fun() -> receive die -> ok end end), 1690 1 = erlang:trace(Pid, true, [{tracer, self()}, 1691 {tracer, self()}]), 1692 Pid ! die, 1693 {'EXIT', {badarg, _}} = 1694 (catch erlang:trace(new, true, [{tracer, self()} 1695 | improper])), 1696 {'EXIT', {badarg, _}} = 1697 (catch erlang:trace(new, true, [{tracer, self()}, 1698 not_a_valid_flag])), 1699 ok. 1700 1701%% Test erlang:trace_delivered/1 1702trace_delivered(Config) when is_list(Config) -> 1703 ct:timetrap({minutes, 1}), 1704 TokLoops = 10000, 1705 Go = make_ref(), 1706 Parent = self(), 1707 Tok = spawn(fun () -> 1708 receive Go -> gone end, 1709 tok_trace_loop(Parent, 0, TokLoops) 1710 end), 1711 1 = erlang:trace(Tok, true, [procs]), 1712 Mon = erlang:monitor(process, Tok), 1713 NoOfTraceMessages = 4*TokLoops + 1, 1714 io:format("Expect a total of ~p trace messages~n", 1715 [NoOfTraceMessages]), 1716 Tok ! Go, 1717 NoOfTraceMessages = drop_trace_until_down(Tok, Mon), 1718 receive 1719 Msg -> 1720 ct:fail({unexpected_message, Msg}) 1721 after 1000 -> 1722 ok 1723 end. 1724 1725%% This testcase checks that receive trace works on exit signal messages 1726%% when the sender of the exit signal is the process itself. 1727trap_exit_self_receive(Config) -> 1728 Parent = self(), 1729 Proc = spawn_link(fun() -> process(Parent) end), 1730 1731 1 = erlang:trace(Proc, true, ['receive']), 1732 Proc ! {trap_exit_please, true}, 1733 {trace, Proc, 'receive', {trap_exit_please, true}} = receive_first_trace(), 1734 1735 %% Make the process call exit(self(), signal) 1736 Reason1 = make_ref(), 1737 Proc ! {exit_signal_please, Reason1}, 1738 {trace, Proc, 'receive', {exit_signal_please, Reason1}} = receive_first_trace(), 1739 {trace, Proc, 'receive', {'EXIT', Proc, Reason1}} = receive_first_trace(), 1740 receive {Proc, {'EXIT', Proc, Reason1}} -> ok end, 1741 receive_nothing(), 1742 1743 unlink(Proc), 1744 Reason2 = make_ref(), 1745 Proc ! {exit_please, Reason2}, 1746 {trace, Proc, 'receive', {exit_please, Reason2}} = receive_first_trace(), 1747 receive_nothing(), 1748 ok. 1749 1750trace_info_badarg(Config) when is_list(Config) -> 1751 catch erlang:trace_info({a,b,c},d), 1752 ok. 1753 1754%% An incoming suspend monitor down wasn't handled 1755%% correct when the local monitor half had been 1756%% removed with an emulator crash as result. 1757erl_704(Config) -> 1758 erl_704_test(100). 1759 1760erl_704_test(0) -> 1761 ok; 1762erl_704_test(N) -> 1763 P = spawn(fun () -> receive infinity -> ok end end), 1764 erlang:suspend_process(P), 1765 exit(P, kill), 1766 (catch erlang:resume_process(P)), 1767 erl_704_test(N-1). 1768 1769ms_excessive_nesting(Config) when is_list(Config) -> 1770 MkMSCond = fun (_Fun, N) when N < 0 -> true; 1771 (Fun, N) -> {'or', {'=:=', N, '$1'}, Fun(Fun, N-1)} 1772 end, 1773 %% Ensure it compiles with substantial but reasonable 1774 %% (hmm...) nesting 1775 MS = [{['$1'], [MkMSCond(MkMSCond, 100)], []}], 1776 io:format("~p~n", [erlang:match_spec_test([1], MS, trace)]), 1777 _ = erlang:trace_pattern({?MODULE, '_', '_'}, MS, []), 1778 %% Now test a match spec using excessive nesting. This 1779 %% used to seg-fault the emulator due to recursion 1780 %% beyond the end of the C-stack. 1781 %% 1782 %% We expect to get a system_limit error, but don't 1783 %% fail if it compiles (someone must have rewritten 1784 %% compilation of match specs to use an explicit 1785 %% stack instead of using recursion). 1786 ENMS = [{['$1'], [MkMSCond(MkMSCond, 1000000)], []}], 1787 io:format("~p~n", [erlang:match_spec_test([1], ENMS, trace)]), 1788 try 1789 _ = erlang:trace_pattern({?MODULE, '_', '_'}, ENMS, []), 1790 {comment, "compiled"} 1791 catch 1792 error:system_limit -> 1793 {comment, "got system_limit"} 1794 end. 1795 1796drop_trace_until_down(Proc, Mon) -> 1797 drop_trace_until_down(Proc, Mon, false, 0, 0). 1798 1799drop_trace_until_down(Proc, Mon, TDRef, N, D) -> 1800 case receive Msg -> Msg end of 1801 {trace_delivered, Proc, TDRef} -> 1802 io:format("~p trace messages on 'DOWN'~n", [D]), 1803 io:format("Got a total of ~p trace messages~n", [N]), 1804 N; 1805 {'DOWN', Mon, process, Proc, _} -> 1806 Ref = erlang:trace_delivered(Proc), 1807 drop_trace_until_down(Proc, Mon, Ref, N, N); 1808 Trace when is_tuple(Trace), 1809 element(1, Trace) == trace, 1810 element(2, Trace) == Proc -> 1811 drop_trace_until_down(Proc, Mon, TDRef, N+1, D) 1812 end. 1813 1814tok_trace_loop(_, N, N) -> 1815 ok; 1816tok_trace_loop(Parent, N, M) -> 1817 Name = 'A really stupid name which I will unregister at once', 1818 link(Parent), 1819 register(Name, self()), 1820 unregister(Name), 1821 unlink(Parent), 1822 tok_trace_loop(Parent, N+1, M). 1823 1824%% Waits for and returns the first message in the message queue. 1825 1826receive_first() -> 1827 receive 1828 Any -> Any 1829 end. 1830 1831%% Waits for and returns the first message in the message queue. 1832 1833receive_first_trace() -> 1834 receive 1835 Any when element(1,Any) =:= trace; element(1,Any) =:= trace_ts -> Any 1836 end. 1837 1838%% Ensures that there is no message in the message queue. 1839 1840receive_nothing() -> 1841 receive 1842 Any -> 1843 ct:fail({unexpected_message, Any}) 1844 after 100 -> 1845 ok 1846 end. 1847 1848 1849%%% Models for various kinds of processes. 1850 1851process(Dest) -> 1852 receive 1853 {send_please, To, What} -> 1854 To ! What, 1855 process(Dest); 1856 {spawn_link_please, ReplyTo, {M, F, A}} -> 1857 Pid = spawn_link(M, F, A), 1858 ReplyTo ! {spawned, self(), Pid}, 1859 process(Dest); 1860 {spawn_link_please, ReplyTo, Node, {M, F, A}} -> 1861 Pid = spawn_link(Node, M, F, A), 1862 ReplyTo ! {spawned, self(), Pid}, 1863 process(Dest); 1864 {link_please, Pid} -> 1865 link(Pid), 1866 process(Dest); 1867 {unlink_please, Pid} -> 1868 unlink(Pid), 1869 process(Dest); 1870 {register_please, Name, Pid} -> 1871 register(Name, Pid), 1872 process(Dest); 1873 {unregister_please, Name} -> 1874 unregister(Name), 1875 process(Dest); 1876 {exit_please, Reason} -> 1877 exit(Reason); 1878 {exit_signal_please, Reason} -> 1879 exit(self(), Reason), 1880 process(Dest); 1881 {trap_exit_please, State} -> 1882 process_flag(trap_exit, State), 1883 process(Dest); 1884 Other -> 1885 Dest ! {self(), Other}, 1886 process(Dest) 1887 after 3000 -> 1888 exit(timeout) 1889 end. 1890 1891 1892%% A smart process template. 1893 1894process() -> 1895 receive 1896 {spawn_please, ReplyTo, Fun} -> 1897 Pid = fun_spawn(Fun), 1898 ReplyTo ! {spawned, Pid}, 1899 process(); 1900 {send_please, To, What} -> 1901 To ! What, 1902 process(); 1903 timeout_please -> 1904 receive after 1 -> process() end; 1905 _Other -> 1906 process() 1907 end. 1908 1909 1910%% Sends messages when ordered to. 1911 1912sender() -> 1913 receive 1914 {send_please, To, What} -> 1915 To ! What, 1916 sender() 1917 end. 1918 1919 1920%% Just consumes messages from its message queue. 1921 1922receiver() -> 1923 receiver(infinity). 1924 1925receiver(Timeout) -> 1926 receiver(receive 1927 {set_timeout, NewTimeout} -> NewTimeout; 1928 _Any -> Timeout 1929 after Timeout -> infinity %% reset 1930 end). 1931 1932%% Works as long as it receives CPU time. Will always be RUNNABLE. 1933 1934worker() -> 1935 worker(0). 1936 1937worker(Number) -> 1938 worker(Number+1). 1939 1940fun_spawn(Fun) -> 1941 spawn_link(erlang, apply, [Fun, []]). 1942 1943fun_spawn(Fun, Args) -> 1944 spawn_link(erlang, apply, [Fun, Args]). 1945 1946 1947start_node(Name) -> 1948 Pa = filename:dirname(code:which(?MODULE)), 1949 Cookie = atom_to_list(erlang:get_cookie()), 1950 test_server:start_node(Name, slave, 1951 [{args, "-setcookie " ++ Cookie ++" -pa " ++ Pa}]). 1952 1953stop_node(Node) -> 1954 test_server:stop_node(Node). 1955 1956 1957wait_for_empty_runq(DeadLine) -> 1958 case statistics(run_queue) of 1959 0 -> true; 1960 RQLen -> 1961 erlang:display("Waiting for empty run queue"), 1962 MSDL = DeadLine*1000, 1963 wait_for_empty_runq(MSDL, MSDL, RQLen) 1964 end. 1965 1966wait_for_empty_runq(DeadLine, Left, RQLen) when Left =< 0 -> 1967 issue_non_empty_runq_warning(DeadLine, RQLen), 1968 false; 1969wait_for_empty_runq(DeadLine, Left, _RQLen) -> 1970 Wait = 10, 1971 UntilDeadLine = Left - Wait, 1972 receive after Wait -> ok end, 1973 case statistics(run_queue) of 1974 0 -> 1975 erlang:display("Waited for " 1976 ++ integer_to_list(DeadLine 1977 - UntilDeadLine) 1978 ++ " ms for empty run queue."), 1979 true; 1980 NewRQLen -> 1981 wait_for_empty_runq(DeadLine, 1982 UntilDeadLine, 1983 NewRQLen) 1984 end. 1985 1986issue_non_empty_runq_warning(DeadLine, RQLen) -> 1987 PIs = lists:foldl( 1988 fun (P, Acc) -> 1989 case process_info(P, 1990 [status, 1991 initial_call, 1992 current_function, 1993 registered_name, 1994 reductions, 1995 message_queue_len]) of 1996 [{status, Runnable} | _] = PI when Runnable /= waiting, 1997 Runnable /= suspended -> 1998 [[{pid, P} | PI] | Acc]; 1999 _ -> 2000 Acc 2001 end 2002 end, 2003 [], 2004 processes()), 2005 io:format("WARNING: Unexpected runnable processes in system (waited ~p sec).~n" 2006 " Run queue length: ~p~n" 2007 " Self: ~p~n" 2008 " Processes info: ~p~n", 2009 [DeadLine div 1000, RQLen, self(), PIs]), 2010 receive after 1000 -> ok end. 2011 2012load_driver(Dir, Driver) -> 2013 case erl_ddll:load_driver(Dir, Driver) of 2014 ok -> ok; 2015 {error, Error} = Res -> 2016 io:format("~s\n", [erl_ddll:format_error(Error)]), 2017 Res 2018 end. 2019