1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 1999-2012. 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: -module(trace_port_SUITE). 22: 23: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 24: init_per_group/2,end_per_group/2, 25: init_per_testcase/2,end_per_testcase/2, 26: call_trace/1, 27: return_trace/1, 28: send/1, 29: receive_trace/1, 30: process_events/1, 31: schedule/1, 32: fake_schedule/1, 33: fake_schedule_after_register/1, 34: fake_schedule_after_getting_linked/1, 35: fake_schedule_after_getting_unlinked/1, 36: gc/1, 37: default_tracer/1]). 38: 39: -include_lib("test_server/include/test_server.hrl"). 40: 41: test_cases() -> 42: [call_trace, return_trace, send, receive_trace, 43: process_events, schedule, fake_schedule, 44: fake_schedule_after_register, 45: fake_schedule_after_getting_linked, 46: fake_schedule_after_getting_unlinked, gc, 47: default_tracer]. 48: 49: suite() -> [{ct_hooks,[ts_install_cth]}]. 50: 51: all() -> 52: test_cases(). 53: 54: groups() -> 55: []. 56: 57: init_per_suite(Config) -> 58: Config. 59: 60: end_per_suite(_Config) -> 61: ok. 62: 63: init_per_group(_GroupName, Config) -> 64: Config. 65: 66: end_per_group(_GroupName, Config) -> 67: Config. 68: 69: 70: init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> 71: Dog = ?t:timetrap(?t:seconds(30)), 72: [{watchdog, Dog}|Config]. 73: 74: end_per_testcase(_Func, Config) -> 75: Dog = ?config(watchdog, Config), 76: ?t:timetrap_cancel(Dog). 77: 78: call_trace(doc) -> "Test sending call trace messages to a port."; 79: call_trace(Config) when is_list(Config) -> 80: case test_server:is_native(?MODULE) orelse 81: test_server:is_native(lists) of 82: true -> 83: {skip,"Native code"}; 84: false -> 85: ?line start_tracer(Config), 86: Self = self(), 87: ?line trace_func({lists,reverse,1}, []), 88: ?line trace_pid(Self, true, [call]), 89: ?line trace_info(Self, flags), 90: ?line trace_info(Self, tracer), 91: ?line [b,a] = lists:reverse([a,b]), 92: ?line expect({trace,Self,call,{lists,reverse,[[a,b]]}}), 93: 94: ?line trace_pid(Self, true, [timestamp]), 95: ?line trace_info(Self, flags), 96: ?line Huge = huge_data(), 97: ?line lists:reverse(Huge), 98: ?line expect({trace_ts,Self,call,{lists,reverse,[Huge]},ts}), 99: 100: ?line trace_pid(Self, true, [arity]), 101: ?line trace_info(Self, flags), 102: ?line [y,x] = lists:reverse([x,y]), 103: ?line expect({trace_ts,Self,call,{lists,reverse,1},ts}), 104: 105: ?line trace_pid(Self, false, [timestamp]), 106: ?line trace_info(Self, flags), 107: ?line [z,y,x] = lists:reverse([x,y,z]), 108: ?line expect({trace,Self,call,{lists,reverse,1}}), 109: 110: %% OTP-7399. Delayed sub-binary creation optimization. 111: ?line trace_pid(Self, false, [arity]), 112: ?line trace_info(Self, flags), 113: ?line trace_func({?MODULE,bs_sum_c,2}, [], [local]), 114: ?line 26 = bs_sum_c(<<3:4,5:4,7:4,11:4>>, 0), 115: ?line trace_func({?MODULE,bs_sum_c,2}, false, [local]), 116: ?line expect({trace,Self,call,{?MODULE,bs_sum_c,[<<3:4,5:4,7:4,11:4>>,0]}}), 117: ?line expect({trace,Self,call,{?MODULE,bs_sum_c,[<<5:4,7:4,11:4>>,3]}}), 118: ?line expect({trace,Self,call,{?MODULE,bs_sum_c,[<<7:4,11:4>>,8]}}), 119: ?line expect({trace,Self,call,{?MODULE,bs_sum_c,[<<11:4>>,15]}}), 120: ?line expect({trace,Self,call,{?MODULE,bs_sum_c,[<<>>,26]}}), 121: 122: ?line trace_func({lists,reverse,1}, false), 123: ok 124: end. 125: 126: bs_sum_c(<<H:4,T/bits>>, Acc) -> bs_sum_c(T, H+Acc); 127: bs_sum_c(<<>>, Acc) -> Acc. 128: 129: 130: return_trace(doc) -> "Test the new return trace."; 131: return_trace(Config) when is_list(Config) -> 132: case test_server:is_native(?MODULE) orelse 133: test_server:is_native(lists) of 134: true -> 135: {skip,"Native code"}; 136: false -> 137: ?line start_tracer(Config), 138: Self = self(), 139: MFA = {lists,reverse,1}, 140: 141: %% Plain (no timestamp, small data). 142: 143: ?line trace_func(MFA, [{['$1'],[],[{return_trace}, 144: {message,false}]}]), 145: ?line trace_pid(Self, true, [call]), 146: ?line trace_info(Self, flags), 147: ?line trace_info(Self, tracer), 148: ?line trace_info(MFA, match_spec), 149: ?line {traced,global} = trace_info(MFA, traced), 150: ?line [b,a] = lists:reverse([a,b]), 151: ?line expect({trace,Self,return_from,MFA,[b,a]}), 152: 153: %% Timestamp, huge data. 154: ?line trace_pid(Self, true, [timestamp]), 155: ?line Result = lists:reverse(huge_data()), 156: ?line expect({trace_ts,Self,return_from,MFA,Result,ts}), 157: 158: %% Turn off trace. 159: ?line trace_func(MFA, false), 160: ?line trace_info(MFA, match_spec), 161: ?line {traced,false} = trace_info(MFA, traced), 162: ok 163: end. 164: 165: send(doc) -> "Test sending send trace messages to a port."; 166: send(Config) when is_list(Config) -> 167: ?line Tracer = start_tracer(Config), 168: Self = self(), 169: ?line Sender = fun_spawn(fun sender/0), 170: ?line trac(Sender, true, [send]), 171: 172: %% Simple message, no timestamp. 173: 174: ?line Bin = list_to_binary(lists:seq(1, 10)), 175: ?line Msg = {some_data,Bin}, 176: Sender ! {send_please,self(),Msg}, 177: receive Msg -> ok end, 178: ?line expect({trace,Sender,send,Msg,Self}), 179: 180: %% Timestamp. 181: 182: BiggerMsg = {even_bigger,Msg}, 183: ?line trac(Sender, true, [send,timestamp]), 184: Sender ! {send_please,self(),BiggerMsg}, 185: receive BiggerMsg -> ok end, 186: ?line expect({trace_ts,Sender,send,BiggerMsg,Self,ts}), 187: 188: %% Huge message. 189: 190: ?line HugeMsg = huge_data(), 191: Sender ! {send_please,self(),HugeMsg}, 192: receive HugeMsg -> ok end, 193: ?line expect({trace_ts,Sender,send,HugeMsg,Self,ts}), 194: 195: %% Kill trace port and force a trace. The emulator should not crasch. 196: 197: ?line unlink(Tracer), 198: ?line exit(Tracer, kill), 199: erlang:yield(), % Make sure that port gets killed. 200: Sender ! {send_please,Self,good_bye}, 201: receive good_bye -> ok end, 202: ok. 203: 204: receive_trace(doc) -> "Test sending receive traces to a port."; 205: receive_trace(Config) when is_list(Config) -> 206: ?line start_tracer(Config), 207: ?line Receiver = fun_spawn(fun receiver/0), 208: ?line trac(Receiver, true, ['receive']), 209: 210: Receiver ! {hello,world}, 211: ?line expect({trace,Receiver,'receive',{hello,world}}), 212: 213: ?line trac(Receiver, true, ['receive',timestamp]), 214: Huge = {hello,huge_data()}, 215: Receiver ! {hello,huge_data()}, 216: ?line expect({trace_ts,Receiver,'receive',Huge,ts}), 217: ok. 218: 219: process_events(doc) -> "Tests a few process events (like getting linked)."; 220: process_events(Config) when is_list(Config) -> 221: ?line start_tracer(Config), 222: Self = self(), 223: ?line Receiver = fun_spawn(fun receiver/0), 224: ?line trac(Receiver, true, [procs]), 225: 226: unlink(Receiver), %It is already linked. 227: ?line expect({trace,Receiver,getting_unlinked,Self}), 228: link(Receiver), 229: ?line expect({trace,Receiver,getting_linked,Self}), 230: ?line trac(Receiver, true, [procs,timestamp]), 231: unlink(Receiver), 232: ?line expect({trace_ts,Receiver,getting_unlinked,Self,ts}), 233: link(Receiver), 234: ?line expect({trace_ts,Receiver,getting_linked,Self,ts}), 235: 236: unlink(Receiver), 237: ?line expect({trace_ts,Receiver,getting_unlinked,Self,ts}), 238: Huge = huge_data(), 239: exit(Receiver, Huge), 240: ?line expect({trace_ts,Receiver,exit,Huge,ts}), 241: 242: ok. 243: 244: schedule(doc) -> "Test sending scheduling events to a port."; 245: schedule(Config) when is_list(Config) -> 246: ?line start_tracer(Config), 247: ?line Receiver = fun_spawn(fun receiver/0), 248: ?line trac(Receiver, true, [running]), 249: 250: Receiver ! hi, 251: expect({trace,Receiver,in,{?MODULE,receiver,0}}), 252: expect({trace,Receiver,out,{?MODULE,receiver,0}}), 253: 254: ?line trac(Receiver, true, [running,timestamp]), 255: 256: Receiver ! hi_again, 257: expect({trace_ts,Receiver,in,{?MODULE,receiver,0},ts}), 258: expect({trace_ts,Receiver,out,{?MODULE,receiver,0},ts}), 259: 260: ok. 261: 262: run_fake_sched_test(Fun, Config) when is_function(Fun), is_list(Config) -> 263: ?line case catch erlang:system_info(smp_support) of 264: true -> 265: ?line {skipped, 266: "No need for faked schedule out/in trace messages " 267: "when smp support is enabled"}; 268: _ -> 269: ?line Fun(Config) 270: end. 271: 272: fake_schedule(doc) -> "Tests time compensating fake out/in scheduling."; 273: fake_schedule(Config) when is_list(Config) -> 274: ?line run_fake_sched_test(fun fake_schedule_test/1, Config). 275: 276: fake_schedule_test(Config) when is_list(Config) -> 277: ?line Tracer = start_tracer(Config), 278: ?line Port = get(tracer_port), 279: ?line General = fun_spawn(fun general/0), 280: %% 281: ?line trac(General, true, [send, running]), 282: %% 283: %% Test that fake out/in scheduling is not generated unless 284: %% both 'running' and 'timestamp' is active. 285: ?line [] = erlang:port_control(Port, $h, []), 286: ?line General ! nop, 287: ?line expect({trace, General, in, {?MODULE, general, 0}}), 288: ?line expect({trace, General, out, {?MODULE, general, 0}}), 289: ?line expect(), 290: %% 291: ?line trac(General, false, [running]), 292: ?line trac(General, true, [timestamp]), 293: %% 294: ?line Ref1 = make_ref(), 295: ?line Msg1 = {Port, {data, term_to_binary(Ref1)}}, 296: ?line [] = erlang:port_control(Port, $h, []), 297: ?line General ! {send, Tracer, Msg1}, 298: ?line expect({trace_ts, General, send, Msg1, Tracer, ts}), 299: ?line expect(Ref1), 300: ?line expect(), 301: %% 302: ?line trac(General, true, [running]), 303: %% 304: %% Test that fake out/in scheduling can be generated by the driver 305: ?line Ref2 = make_ref(), 306: ?line Msg2 = {Port, {data, term_to_binary(Ref2)}}, 307: ?line [] = erlang:port_control(Port, $h, []), 308: ?line General ! {send, Tracer, Msg2}, 309: ?line {_,_,_,_,Ts} = 310: expect({trace_ts, General, in, {?MODULE, general, 0}, ts}), 311: ?line expect({trace_ts, General, out, 0, Ts}), 312: ?line expect({trace_ts, General, in, 0, ts}), 313: ?line expect({trace_ts, General, send, Msg2, Tracer, ts}), 314: ?line expect(Ref2), 315: ?line expect({trace_ts, General, out, {?MODULE, general, 0}, ts}), 316: ?line expect(), 317: %% 318: %% Test that fake out/in scheduling is not generated after an 319: %% 'out' scheduling event 320: ?line Ref3 = make_ref(), 321: ?line Msg3 = {Port, {data, term_to_binary(Ref3)}}, 322: ?line General ! {apply, {erlang, port_control, [Port, $h, []]}}, 323: ?line expect({trace_ts, General, in, {?MODULE, general, 0}, ts}), 324: ?line expect({trace_ts, General, out, {?MODULE, general, 0}, ts}), 325: ?line General ! {send, Tracer, Msg3}, 326: ?line expect({trace_ts, General, in, {?MODULE, general, 0}, ts}), 327: ?line expect({trace_ts, General, send, Msg3, Tracer, ts}), 328: ?line expect(Ref3), 329: ?line expect({trace_ts, General, out, {?MODULE, general, 0}, ts}), 330: ?line expect(), 331: %% 332: ok. 333: 334: fake_schedule_after_register(doc) -> 335: "Tests fake out/in scheduling contents."; 336: fake_schedule_after_register(Config) when is_list(Config) -> 337: ?line run_fake_sched_test(fun fake_schedule_after_register_test/1, Config). 338: 339: fake_schedule_after_register_test(Config) when is_list(Config) -> 340: ?line start_tracer(Config), 341: ?line Port = get(tracer_port), 342: ?line G1 = fun_spawn(fun general/0), 343: ?line G2 = fun_spawn(fun general/0), 344: %% 345: ?line trac(G1, true, [running, timestamp, procs]), 346: ?line trac(G2, true, [running, timestamp]), 347: %% 348: %% Test fake out/in scheduling after certain messages 349: ?line erlang:yield(), 350: ?line G2 ! {apply, {erlang, port_control, [Port, $h, []]}}, 351: ?line G2 ! {apply, {erlang, register, [fake_schedule_after_register, G1]}}, 352: ?line expect({trace_ts, G2, in, {?MODULE, general, 0}, ts}), 353: ?line {_,_,_,_,Ts} = 354: expect({trace_ts, G1, register, fake_schedule_after_register, ts}), 355: ?line expect({trace_ts, G2, out, 0, Ts}), 356: ?line expect({trace_ts, G2, in, 0, ts}), 357: ?line expect({trace_ts, G2, out, {?MODULE, general, 0}, ts}), 358: ?line expect(), 359: %% 360: ok. 361: 362: fake_schedule_after_getting_linked(doc) -> 363: "Tests fake out/in scheduling contents."; 364: fake_schedule_after_getting_linked(Config) when is_list(Config) -> 365: ?line run_fake_sched_test(fun fake_schedule_after_getting_linked_test/1, 366: Config). 367: 368: fake_schedule_after_getting_linked_test(Config) when is_list(Config) -> 369: ?line start_tracer(Config), 370: ?line Port = get(tracer_port), 371: ?line G1 = fun_spawn(fun general/0), 372: ?line G2 = fun_spawn(fun general/0), 373: %% 374: ?line trac(G1, true, [running, timestamp, procs]), 375: ?line trac(G2, true, [running, timestamp]), 376: %% 377: %% Test fake out/in scheduling after certain messages 378: ?line erlang:yield(), 379: ?line G2 ! {apply, {erlang, port_control, [Port, $h, []]}}, 380: ?line G2 ! {apply, {erlang, link, [G1]}}, 381: ?line expect({trace_ts, G2, in, {?MODULE, general, 0}, ts}), 382: ?line {_,_,_,_,Ts} = 383: expect({trace_ts, G1, getting_linked, G2, ts}), 384: ?line expect({trace_ts, G2, out, 0, Ts}), 385: ?line expect({trace_ts, G2, in, 0, ts}), 386: ?line expect({trace_ts, G2, out, {?MODULE, general, 0}, ts}), 387: ?line expect(), 388: %% 389: ok. 390: 391: fake_schedule_after_getting_unlinked(doc) -> 392: "Tests fake out/in scheduling contents."; 393: fake_schedule_after_getting_unlinked(Config) when is_list(Config) -> 394: ?line run_fake_sched_test(fun fake_schedule_after_getting_unlinked_test/1, 395: Config). 396: 397: fake_schedule_after_getting_unlinked_test(Config) when is_list(Config) -> 398: ?line start_tracer(Config), 399: ?line Port = get(tracer_port), 400: ?line G1 = fun_spawn(fun general/0), 401: ?line G2 = fun_spawn(fun general/0), 402: %% 403: ?line trac(G1, true, [running, procs]), 404: ?line trac(G2, true, [running, timestamp]), 405: %% 406: %% Test fake out/in scheduling after certain messages 407: ?line erlang:yield(), 408: ?line G2 ! {apply, {erlang, link, [G1]}}, 409: ?line G2 ! {apply, {erlang, port_control, [Port, $h, []]}}, 410: ?line G2 ! {apply, {erlang, unlink, [G1]}}, 411: ?line expect({trace_ts, G2, in, {?MODULE, general, 0}, ts}), 412: ?line expect({trace, G1, getting_linked, G2}), 413: ?line expect({trace, G1, getting_unlinked, G2}), 414: ?line expect({trace_ts, G2, out, 0, ts}), 415: ?line expect({trace_ts, G2, in, 0, ts}), 416: ?line expect({trace_ts, G2, out, {?MODULE, general, 0}, ts}), 417: ?line expect(), 418: %% 419: ok. 420: 421: gc(doc) -> "Test sending garbage collection events to a port."; 422: gc(Config) when is_list(Config) -> 423: ?line start_tracer(Config), 424: ?line Garber = fun_spawn(fun garber/0, [{min_heap_size, 5000}]), 425: ?line trac(Garber, true, [garbage_collection]), 426: ?line trace_info(Garber, flags), 427: 428: ?line trace_info(Garber, flags), 429: Garber ! hi, 430: expect({trace,Garber,gc_start,info}), 431: expect({trace,Garber,gc_end,info}), 432: 433: ?line trac(Garber, true, [garbage_collection,timestamp]), 434: Garber ! hi, 435: expect({trace_ts,Garber,gc_start,info,ts}), 436: expect({trace_ts,Garber,gc_end,info,ts}), 437: 438: ok. 439: 440: default_tracer(doc) -> 441: "Test a port as default tracer."; 442: default_tracer(Config) when is_list(Config) -> 443: ?line Tracer = start_tracer(Config), 444: ?line TracerMonitor = erlang:monitor(process, Tracer), 445: ?line Port = get(tracer_port), 446: %% 447: ?line N = erlang:trace(all, true, [send, {tracer, Port}]), 448: ?line {flags, [send]} = erlang:trace_info(self(), flags), 449: ?line {tracer, Port} = erlang:trace_info(self(), tracer), 450: ?line {flags, [send]} = erlang:trace_info(new, flags), 451: ?line {tracer, Port} = erlang:trace_info(new, tracer), 452: ?line G1 = fun_spawn(fun general/0), 453: ?line {flags, [send]} = erlang:trace_info(G1, flags), 454: ?line {tracer, Port} = erlang:trace_info(G1, tracer), 455: ?line unlink(Tracer), 456: ?line exit(Port, done), 457: ?line receive 458: {'DOWN', TracerMonitor, process, Tracer, TracerExitReason} -> 459: ?line done = TracerExitReason 460: end, 461: ?line {flags, []} = erlang:trace_info(self(), flags), 462: ?line {tracer, []} = erlang:trace_info(self(), tracer), 463: ?line {flags, []} = erlang:trace_info(new, flags), 464: ?line {tracer, []} = erlang:trace_info(new, tracer), 465: ?line M = erlang:trace(all, false, [all]), 466: ?line {flags, []} = erlang:trace_info(self(), flags), 467: ?line {tracer, []} = erlang:trace_info(self(), tracer), 468: ?line {flags, []} = erlang:trace_info(G1, flags), 469: ?line {tracer, []} = erlang:trace_info(G1, tracer), 470: ?line G1 ! {apply,{erlang,exit,[normal]}}, 471: ?line io:format("~p = ~p.~n", [M, N]), 472: ?line M = N, 473: ok. 474: 475: %%% Help functions. 476: 477: huge_data() -> huge_data(16384). 478: huge_data(0) -> []; 479: huge_data(N) when N rem 2 == 0 -> 480: P = huge_data(N div 2), 481: [P|P]; 482: huge_data(N) -> 483: P = huge_data(N div 2), 484: [16#1234566,P|P]. 485: 486: expect() -> 487: receive 488: Other -> 489: ok = io:format("Unexpected; got ~p", [Other]), 490: test_server:fail({unexpected, Other}) 491: after 200 -> 492: ok 493: end. 494: 495: expect({trace_ts,E1,E2,info,ts}=Message) -> 496: receive 497: {trace_ts,E1,E2,_Info,_Ts}=MessageTs -> 498: ok = io:format("Expected and got ~p", [MessageTs]), 499: MessageTs; 500: Other -> 501: io:format("Expected ~p; got ~p", [Message,Other]), 502: test_server:fail({unexpected,Other}) 503: after 5000 -> 504: io:format("Expected ~p; got nothing", [Message]), 505: test_server:fail(no_trace_message) 506: end; 507: expect({trace,E1,E2,info}=Message) -> 508: receive 509: {trace,E1,E2,_Info}=MessageTs -> 510: ok = io:format("Expected and got ~p", [MessageTs]), 511: MessageTs; 512: Other -> 513: io:format("Expected ~p; got ~p", [Message,Other]), 514: test_server:fail({unexpected,Other}) 515: after 5000 -> 516: io:format("Expected ~p; got nothing", [Message]), 517: test_server:fail(no_trace_message) 518: end; 519: expect({trace_ts,E1,E2,E3,ts}=Message) -> 520: receive 521: {trace_ts,E1,E2,E3,_Ts}=MessageTs -> 522: ok = io:format("Expected and got ~p", [MessageTs]), 523: MessageTs; 524: Other -> 525: io:format("Expected ~p; got ~p", [Message,Other]), 526: test_server:fail({unexpected,Other}) 527: after 5000 -> 528: io:format("Expected ~p; got nothing", [Message]), 529: test_server:fail(no_trace_message) 530: end; 531: expect({trace_ts,E1,E2,E3,E4,ts}=Message) -> 532: receive 533: {trace_ts,E1,E2,E3,E4,_Ts}=MessageTs -> 534: ok = io:format("Expected and got ~p", [MessageTs]), 535: MessageTs; 536: Other -> 537: io:format("Expected ~p; got ~p", [Message,Other]), 538: test_server:fail({unexpected,Other}) 539: after 5000 -> 540: io:format("Expected ~p; got nothing", [Message]), 541: test_server:fail(no_trace_message) 542: end; 543: expect(Message) -> 544: receive 545: Message -> 546: ok = io:format("Expected and got ~p", [Message]), 547: Message; 548: Other -> 549: io:format("Expected ~p; got ~p", [Message,Other]), 550: test_server:fail({unexpected,Other}) 551: after 5000 -> 552: io:format("Expected ~p; got nothing", [Message]), 553: test_server:fail(no_trace_message) 554: end. 555: 556: trac(What, On, Flags0) -> 557: Flags = [{tracer,get(tracer_port)}|Flags0], 558: get(tracer) ! {apply,self(),{erlang,trace,[What,On,Flags]}}, 559: Res = receive 560: {apply_result,Result} -> Result 561: end, 562: ok = io:format("erlang:trace(~p, ~p, ~p) -> ~p", 563: [What,On,Flags,Res]), 564: Res. 565: 566: trace_info(What, Key) -> 567: get(tracer) ! {apply,self(),{erlang,trace_info,[What,Key]}}, 568: Res = receive 569: {apply_result,Result} -> Result 570: end, 571: ok = io:format("erlang:trace_info(~p, ~p) -> ~p", 572: [What,Key,Res]), 573: Res. 574: 575: trace_func(MFA, MatchProg) -> 576: get(tracer) ! {apply,self(),{erlang,trace_pattern,[MFA,MatchProg]}}, 577: Res = receive 578: {apply_result,Result} -> Result 579: end, 580: ok = io:format("erlang:trace_pattern(~p, ~p) -> ~p", [MFA,MatchProg,Res]), 581: Res. 582: 583: trace_func(MFA, MatchProg, Flags) -> 584: get(tracer) ! {apply,self(),{erlang,trace_pattern,[MFA,MatchProg,Flags]}}, 585: Res = receive 586: {apply_result,Result} -> Result 587: end, 588: ok = io:format("erlang:trace_pattern(~p, ~p) -> ~p", [MFA,MatchProg,Res]), 589: Res. 590: 591: trace_pid(Pid, On, Flags0) -> 592: Flags = [{tracer,get(tracer_port)}|Flags0], 593: get(tracer) ! {apply,self(),{erlang,trace,[Pid,On,Flags]}}, 594: Res = receive 595: {apply_result,Result} -> Result 596: end, 597: ok = io:format("erlang:trace(~p, ~p, ~p) -> ~p", 598: [Pid,On,Flags,Res]), 599: Res. 600: 601: start_tracer(Config) -> 602: Path = ?config(data_dir, Config), 603: ok = load_driver(Path, echo_drv), 604: Self = self(), 605: put(tracer, fun_spawn(fun() -> tracer(Self) end)), 606: receive 607: {started,Port} -> 608: put(tracer_port, Port) 609: end, 610: get(tracer). 611: 612: load_driver(Dir, Driver) -> 613: case erl_ddll:load_driver(Dir, Driver) of 614: ok -> ok; 615: {error, Error} = Res -> 616: io:format("~s\n", [erl_ddll:format_error(Error)]), 617: Res 618: end. 619: 620: tracer(RelayTo) -> 621: Port = open_port({spawn,echo_drv}, [eof,binary]), 622: RelayTo ! {started,Port}, 623: tracer_loop(RelayTo, Port). 624: 625: tracer_loop(RelayTo, Port) -> 626: receive 627: {apply,From,{M,F,A}} -> 628: From ! {apply_result,apply(M, F, A)}, 629: tracer_loop(RelayTo, Port); 630: {Port,{data,Msg}} -> 631: RelayTo ! binary_to_term(Msg), 632: tracer_loop(RelayTo, Port); 633: Other -> 634: exit({bad_message,Other}) 635: end. 636: 637: fun_spawn(Fun) -> 638: spawn_link(erlang, apply, [Fun,[]]). 639: 640: fun_spawn(Fun, Opts) -> 641: spawn_opt(erlang, apply, [Fun,[]], [link | Opts]). 642: 643: % flush() -> 644: % receive 645: % X -> 646: % [X | flush()] 647: % after 2000 -> 648: % [] 649: % end. 650: 651: 652: %%% Models for various kinds of processes. 653: 654: %% Sends messages when ordered to. 655: 656: sender() -> 657: receive 658: {send_please, To, What} -> 659: To ! What, 660: sender() 661: end. 662: 663: %% Just consumes messages from its message queue. 664: 665: receiver() -> 666: receive 667: _Any -> receiver() 668: end. 669: 670: %% Does a garbage collection when it receives a message. 671: 672: garber() -> 673: receive 674: _Any -> 675: lists:seq(1, 100), 676: erlang:garbage_collect(), 677: garber() 678: end. 679: 680: %% All-purpose process 681: 682: general() -> 683: receive 684: {apply, {M, F, Args}} -> 685: erlang:apply(M, F, Args), 686: general(); 687: {send, Dest, Msg} -> 688: Dest ! Msg, 689: general(); 690: {call_f_1, Arg} -> 691: f(Arg), 692: general(); 693: nop -> 694: general() 695: end. 696: 697: f(Arg) -> 698: Arg.