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.