1: %%
    2: %% %CopyrightBegin%
    3: %% 
    4: %% Copyright Ericsson AB 1997-2013. All Rights Reserved.
    5: %% 
    6: %% The contents of this file are subject to the Erlang Public License,
    7: %% Version 1.1, (the "License"); you may not use this file except in
    8: %% compliance with the License. You should have received a copy of the
    9: %% Erlang Public License along with this software. If not, it can be
   10: %% retrieved online at http://www.erlang.org/.
   11: %% 
   12: %% Software distributed under the License is distributed on an "AS IS"
   13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
   14: %% the License for the specific language governing rights and limitations
   15: %% under the License.
   16: %% 
   17: %% %CopyrightEnd%
   18: 
   19: %%% Purpose : Test interaction Erlang/Drivers (new features as of R3A)
   20: 
   21: %%% Checks that new features (as of R3) of the Erlang/Driver
   22: %%% implementation works as expected.
   23: %%%
   24: %%% Things that should be tested:
   25: %%% - outputv
   26: %%% - timeouts
   27: %%% - queueing
   28: 
   29: -module(driver_SUITE).
   30: -export([all/0, suite/0,groups/0,init_per_suite/1, 
   31: 	 end_per_suite/1, init_per_group/2,end_per_group/2,
   32: 	 init_per_testcase/2,
   33: 	 end_per_testcase/2,
   34: 	 outputv_echo/1,
   35: 	
   36: 	 timer_measure/1,
   37: 	 timer_cancel/1,
   38: 	 timer_change/1,
   39: 	 timer_delay/1,
   40: 	 queue_echo/1,
   41: 	 outputv_errors/1,
   42: 	 driver_unloaded/1,
   43: 	 io_ready_exit/1,
   44: 	 use_fallback_pollset/1,
   45: 	 bad_fd_in_pollset/1,
   46: 	 driver_event/1,
   47: 	 fd_change/1,
   48: 	 steal_control/1,
   49: 	 otp_6602/1,
   50: 	 driver_system_info_base_ver/1,
   51: 	 driver_system_info_prev_ver/1,
   52: 	 driver_system_info_current_ver/1,
   53: 	 driver_monitor/1,
   54: 	
   55: 	 ioq_exit_ready_input/1,
   56: 	 ioq_exit_ready_output/1,
   57: 	 ioq_exit_timeout/1,
   58: 	 ioq_exit_ready_async/1,
   59: 	 ioq_exit_event/1,
   60: 	 ioq_exit_ready_input_async/1,
   61: 	 ioq_exit_ready_output_async/1,
   62: 	 ioq_exit_timeout_async/1,
   63: 	 ioq_exit_event_async/1,
   64: 	 zero_extended_marker_garb_drv/1,
   65: 	 invalid_extended_marker_drv/1,
   66: 	 larger_major_vsn_drv/1,
   67: 	 larger_minor_vsn_drv/1,
   68: 	 smaller_major_vsn_drv/1,
   69: 	 smaller_minor_vsn_drv/1,
   70: 	 peek_non_existing_queue/1,
   71: 	 otp_6879/1,
   72: 	 caller/1,
   73: 	 many_events/1,
   74: 	 missing_callbacks/1,
   75: 	 smp_select/1,
   76: 	 driver_select_use/1,
   77: 	 thread_mseg_alloc_cache_clean/1,
   78: 	 otp_9302/1,
   79: 	 thr_free_drv/1,
   80: 	 async_blast/1,
   81: 	 thr_msg_blast/1,
   82: 	 consume_timeslice/1]).
   83: 
   84: -export([bin_prefix/2]).
   85: 
   86: -include_lib("test_server/include/test_server.hrl").
   87: 
   88: 
   89: % First byte in communication with the timer driver
   90: -define(START_TIMER, 0).
   91: -define(CANCEL_TIMER, 1).
   92: -define(DELAY_START_TIMER, 2).
   93: -define(TIMER, 3).
   94: -define(CANCELLED, 4).
   95: 
   96: % First byte in communication with queue driver
   97: -define(PUSHQ, 0).
   98: -define(ENQ, 1).
   99: -define(PUSHQ_BIN, 2).
  100: -define(ENQ_BIN, 3).
  101: -define(PUSHQV, 4).
  102: -define(ENQV, 5).
  103: 
  104: -define(DEQ, 6).
  105: -define(BYTES_QUEUED, 7).
  106: -define(READ_HEAD, 8).
  107: 
  108: -define(RANDOM, random).
  109: 
  110: % Max data size that is queued in one instance
  111: -define(MAX_DATA_SIZE, 16384).
  112: 
  113: % This is the allowed delay when testing the driver timer functionality
  114: -define(delay, 100).
  115: 
  116: -define(heap_binary_size, 64).
  117: 
  118: init_per_testcase(Case, Config) when is_atom(Case), is_list(Config) ->
  119:     Dog=?t:timetrap(?t:minutes(2)),
  120:     case catch erts_debug:get_internal_state(available_internal_state) of
  121: 	true -> ok;
  122: 	_ -> erts_debug:set_internal_state(available_internal_state, true)
  123:     end,
  124:     erlang:display({init_per_testcase, Case}),
  125:     ?line 0 = erts_debug:get_internal_state(check_io_debug),
  126:     [{watchdog, Dog},{testcase, Case}|Config].
  127: 
  128: end_per_testcase(Case, Config) ->
  129:     Dog = ?config(watchdog, Config),
  130:     erlang:display({end_per_testcase, Case}),
  131:     ?line 0 = erts_debug:get_internal_state(check_io_debug),
  132:     ?t:timetrap_cancel(Dog).
  133: 
  134: suite() -> [{ct_hooks,[ts_install_cth]}].
  135: 
  136: all() -> 
  137:     [outputv_errors, outputv_echo, queue_echo, {group, timer},
  138:      driver_unloaded, io_ready_exit, use_fallback_pollset,
  139:      bad_fd_in_pollset, driver_event, fd_change,
  140:      steal_control, otp_6602, driver_system_info_base_ver,
  141:      driver_system_info_prev_ver,
  142:      driver_system_info_current_ver, driver_monitor,
  143:      {group, ioq_exit}, zero_extended_marker_garb_drv,
  144:      invalid_extended_marker_drv, larger_major_vsn_drv,
  145:      larger_minor_vsn_drv, smaller_major_vsn_drv,
  146:      smaller_minor_vsn_drv, peek_non_existing_queue,
  147:      otp_6879, caller, many_events, missing_callbacks,
  148:      smp_select, driver_select_use,
  149:      thread_mseg_alloc_cache_clean,
  150:      otp_9302,
  151:      thr_free_drv,
  152:      async_blast,
  153:      thr_msg_blast,
  154:      consume_timeslice].
  155: 
  156: groups() -> 
  157:     [{timer, [],
  158:       [timer_measure, timer_cancel, timer_delay,
  159:        timer_change]},
  160:      {ioq_exit, [],
  161:       [ioq_exit_ready_input, ioq_exit_ready_output,
  162:        ioq_exit_timeout, ioq_exit_ready_async, ioq_exit_event,
  163:        ioq_exit_ready_input_async, ioq_exit_ready_output_async,
  164:        ioq_exit_timeout_async, ioq_exit_event_async]}].
  165: 
  166: init_per_suite(Config) ->
  167:     Config.
  168: 
  169: end_per_suite(_Config) ->
  170:     catch erts_debug:set_internal_state(available_internal_state, false).
  171: 
  172: init_per_group(_GroupName, Config) ->
  173:     Config.
  174: 
  175: end_per_group(_GroupName, Config) ->
  176:     Config.
  177: 
  178: outputv_errors(doc) -> "Test sending bad types to port with an outputv-capable driver.";
  179: outputv_errors(Config) when is_list(Config) ->
  180:     ?line Path = ?config(data_dir, Config),
  181:     ?line erl_ddll:start(),
  182:     ?line ok = load_driver(Path, outputv_drv),
  183: 
  184:     outputv_bad_types(fun(T) ->
  185: 			      ?line outputv_errors_1(T),
  186: 			      ?line outputv_errors_1([1|T]),
  187: 			      ?line L = [1,2,3],
  188: 			      ?line outputv_errors_1([L,T]),
  189: 			      ?line outputv_errors_1([L|T])
  190: 		      end),
  191:     outputv_errors_1(42),
  192: 
  193:     %% Test iolists that do not fit in the address space.
  194:     %% Unfortunately, it would be too slow to test in a 64-bit emulator.
  195:     case erlang:system_info(wordsize) of
  196: 	4 -> outputv_huge_iolists();
  197: 	_ -> ok
  198:     end.
  199: 
  200: outputv_bad_types(Test) ->
  201:     Types = [-1,256,atom,42.0,{a,b,c},make_ref(),fun() -> 42 end,
  202: 	     [1|2],<<1:1>>,<<1:9>>,<<1:15>>],
  203:     _ = [Test(Type) || Type <- Types],
  204:     ok.
  205: 
  206: outputv_huge_iolists() ->
  207:     FourGigs = 1 bsl 32,
  208:     ?line Sizes = [FourGigs+N || N <- lists:seq(0, 64)] ++
  209: 	[1 bsl N || N <- lists:seq(33, 37)],
  210:     ?line Base = <<0:(1 bsl 20)/unit:8>>,
  211:     [begin
  212: 	 ?line L = build_iolist(Sz, Base),
  213: 	 ?line outputv_errors_1(L)
  214:      end || Sz <- Sizes],
  215:     ok.
  216: 
  217: outputv_errors_1(Term) ->
  218:     Port = open_port({spawn_driver,outputv_drv}, []),
  219:     {'EXIT',{badarg,_}} = (catch port_command(Port, Term)),
  220:     port_close(Port).
  221: 
  222: build_iolist(N, Base) when N < 16 ->
  223:     case random:uniform(3) of
  224: 	1 ->
  225: 	    <<Bin:N/binary,_/binary>> = Base,
  226: 	    Bin;
  227: 	_ ->
  228: 	    lists:seq(1, N)
  229:     end;
  230: build_iolist(N, Base) when N =< byte_size(Base) ->
  231:     case random:uniform(3) of
  232: 	1 ->
  233: 	    <<Bin:N/binary,_/binary>> = Base,
  234: 	    Bin;
  235: 	2 ->
  236: 	    <<Bin:N/binary,_/binary>> = Base,
  237: 	    [Bin];
  238: 	3 ->
  239: 	    case N rem 2 of
  240: 		0 ->
  241: 		    L = build_iolist(N div 2, Base),
  242: 		    [L,L];
  243: 		1 ->
  244: 		    L = build_iolist(N div 2, Base),
  245: 		    [L,L,45]
  246: 	    end
  247:     end;
  248: build_iolist(N0, Base) ->
  249:     Small = random:uniform(15),
  250:     Seq = lists:seq(1, Small),
  251:     N = N0 - Small,
  252:     case N rem 2 of
  253: 	0 ->
  254: 	    L = build_iolist(N div 2, Base),
  255: 	    [L,L|Seq];
  256: 	1 ->
  257: 	    L = build_iolist(N div 2, Base),
  258: 	    [47,L,L|Seq]
  259:     end.
  260: 
  261: outputv_echo(doc) -> ["Test echoing data with a driver that supports outputv."];
  262: outputv_echo(Config) when is_list(Config) ->
  263:     ?line Dog = test_server:timetrap(test_server:minutes(10)),
  264:     Name = 'outputv_drv',
  265:     P = start_driver(Config, Name, true),
  266: 
  267:     ?line ov_test(P, {bin,0}),
  268:     ?line ov_test(P, {bin,1}),
  269:     ?line ov_test(P, {bin,2}),
  270:     ?line ov_test(P, {bin,3}),
  271:     ?line ov_test(P, {bin,4}),
  272:     ?line ov_test(P, {bin,5}),
  273:     ?line ov_test(P, {bin,6}),
  274:     ?line ov_test(P, {bin,7}),
  275:     ?line ov_test(P, {bin,8}),
  276:     ?line ov_test(P, {bin,15}),
  277:     ?line ov_test(P, {bin,16}),
  278:     ?line ov_test(P, {bin,17}),
  279: 
  280:     ?line ov_test(P, {list,0}),
  281:     ?line ov_test(P, {list,1}),
  282:     ?line ov_test(P, {list,2}),
  283:     ?line ov_test(P, [int,int,{list,0},int]),
  284:     ?line ov_test(P, [int,int,{list,1},int]),
  285:     ?line ov_test(P, [int,int,{list,2}]),
  286:     ?line ov_test(P, [{list,3},int,int,{list,2}]),
  287:     ?line ov_test(P, {list,33}),
  288: 
  289:     ?line ov_test(P, [{bin,0}]),
  290:     ?line ov_test(P, [{bin,1}]),
  291:     ?line ov_test(P, [{bin,2}]),
  292:     ?line ov_test(P, [{bin,3}]),
  293:     ?line ov_test(P, [{bin,4}]),
  294:     ?line ov_test(P, [{bin,5}]),
  295:     ?line ov_test(P, [{bin,6},int]),
  296:     ?line ov_test(P, [int,{bin,3}]),
  297:     ?line ov_test(P, [int|{bin,4}]),
  298:     ?line ov_test(P, [{bin,17},int,{bin,13}|{bin,3}]),
  299: 
  300:     ?line ov_test(P, [int,{bin,17},int,{bin,?heap_binary_size+1}|{bin,3}]),
  301: 
  302:     stop_driver(P, Name),
  303:     ?line test_server:timetrap_cancel(Dog),
  304:     ok.
  305: 
  306: ov_test(Port, Template) ->
  307:     Self = self(),
  308:     spawn_opt(erlang, apply, [fun () -> ov_test(Self, Port, Template) end,[]],
  309: 	      [link,{fullsweep_after,0}]),
  310:     receive
  311: 	done -> ok
  312:     end.
  313: 
  314: ov_test(Parent, Port, Template) ->
  315:     true = port_connect(Port, self()),
  316: 
  317:     HeapData = build_data(Template),
  318:     io:format("Mostly heap binaries"),
  319:     ov_send_and_test(Port, HeapData, HeapData),
  320: 
  321:     %% Try sub binaries.
  322:     io:format("Mostly sub binaries of heap binaries"),
  323:     SubHeapData = make_sub_binaries(HeapData),
  324:     ov_send_and_test(Port, SubHeapData, HeapData),
  325: 
  326:     %% Try refc binaries.
  327:     io:format("Refc binaries"),
  328:     RefcData = make_refc_binaries(HeapData),
  329:     ov_send_and_test(Port, RefcData, RefcData),
  330: 
  331:     %% Try sub binaries of heap binaries.
  332:     io:format("Sub binaries of refc binaries"),
  333:     SubRefcData = make_sub_binaries(RefcData),
  334:     ov_send_and_test(Port, SubRefcData, RefcData),
  335:     io:format("", []),
  336: 
  337:     %% Garbage collect and make sure that there are no binaries left.
  338:     %% R7 note:
  339:     %%  - dead variables on the stack are killed after last use,
  340:     %%  - erlang:garbage_collect/0 collects garbage immediately.
  341:     %%  (there used to be dummy functions here)
  342:     erlang:garbage_collect(),
  343:     {binary,[]} = process_info(self(), binary),
  344: 
  345:     %% Reassign Port back to parent and tell him we are done.
  346:     true = port_connect(Port, Parent),
  347:     Parent ! done.
  348: 
  349: ov_send_and_test(Port, Data, ExpectedResult) ->
  350:     io:format("~p ! ~P", [Port,Data,12]),
  351:     Port ! {self(),{command,Data}},
  352:     receive 
  353: 	{Port,{data,ReturnData}} ->
  354: 	    io:format("~p returned ~P", [Port,ReturnData,12]),
  355: 	    compare(ReturnData, ExpectedResult);
  356: 	{Port,{data,OtherData}} ->
  357: 	    io:format("~p returned WRONG data ~p", [Port,OtherData]),
  358: 	    ?line test_server:fail();
  359: 	Wrong ->
  360: 	    ?line test_server:fail({unexpected_port_or_data,Wrong})
  361:     end.
  362: 
  363: compare(Got, Expected) ->
  364:     case {list_to_binary([Got]),list_to_binary([Expected])} of
  365: 	{B,B} -> ok;
  366: 	{_Gb,_Eb} ->
  367: 	    ?t:fail(got_bad_data)
  368:     end.
  369: 
  370: 
  371: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  372: %% 		Driver timer test suites
  373: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  374: 
  375: 
  376: timer_measure(doc) -> ["Check that timers time out in good time."];
  377: timer_measure(Config) when is_list(Config) ->
  378:     ?line Dog = test_server:timetrap(test_server:minutes(1)),
  379:     Name = 'timer_drv',
  380:     ?line Port = start_driver(Config, Name, false),
  381: 
  382:     ?line try_timeouts(Port, 8997),
  383: 
  384:     ?line stop_driver(Port, Name),
  385:     ?line test_server:timetrap_cancel(Dog),
  386:     ok.
  387: 
  388: try_timeouts(_, 0) -> ok;
  389: try_timeouts(Port, Timeout) ->
  390:     ?line TimeBefore = now(),
  391:     ?line erlang:port_command(Port, <<?START_TIMER,Timeout:32>>),
  392:     receive
  393: 	{Port,{data,[?TIMER]}} ->
  394: 	    ?line Elapsed = erl_millisecs() - erl_millisecs(TimeBefore),
  395: 	    io:format("Elapsed: ~p Timeout: ~p\n", [Elapsed,Timeout]),
  396: 	    if
  397: 		Elapsed < Timeout ->
  398: 		    ?line ?t:fail(too_short);
  399: 		Elapsed > Timeout + ?delay ->
  400: 		    ?line ?t:fail(too_long);
  401: 		true ->
  402: 		    try_timeouts(Port, Timeout div 2)
  403: 	    end
  404:     after Timeout + ?delay ->
  405: 	    ?line test_server:fail("driver failed to timeout")
  406:     end.
  407: 
  408: timer_cancel(doc) -> ["Try cancelling timers set in a driver."];
  409: timer_cancel(Config) when is_list(Config) ->
  410:     ?line Dog = test_server:timetrap(test_server:minutes(1)),
  411:     Name = 'timer_drv',
  412:     ?line Port = start_driver(Config, Name, false),
  413: 
  414:     ?line try_cancel(Port, 10000),
  415: 
  416:     ?line stop_driver(Port, Name),
  417:     ?line test_server:timetrap_cancel(Dog),
  418:     ok.
  419:     
  420: try_cancel(Port, Timeout) ->
  421:     ?line T_before = erl_millisecs(),
  422:     Port ! {self(),{command,<<?START_TIMER,(Timeout + ?delay):32>>}},
  423:     receive
  424: 	{Port, {data, [?TIMER]}} ->
  425: 	    ?line test_server:fail("driver timed out before cancelling it")
  426:     after Timeout -> 
  427: 	    Port ! {self(), {command, [?CANCEL_TIMER]}},
  428: 	    receive 
  429: 		{Port, {data, [?TIMER]}} ->
  430: 		    ?line test_server:fail("driver timed out after cancelling it");
  431: 		{Port, {data, [?CANCELLED]}} ->
  432: 		    ?line Time_milli_secs = erl_millisecs() - T_before,
  433: 
  434: 		    io:format("Time_milli_secs: ~p Timeout: ~p\n",
  435: 			      [Time_milli_secs, Timeout]), 
  436: 		    if
  437: 			Time_milli_secs > (Timeout + ?delay) ->
  438: 			    ?line test_server:fail("too long real time");
  439: 			Timeout == 0 -> ok;
  440: 			true -> try_cancel(Port, Timeout div 2)
  441: 		    end
  442: 	    after ?delay ->
  443: 		    test_server:fail("No message from driver")
  444: 	    end
  445:     end.
  446: 
  447: %% Test that timers don't time out too early if we do a sleep
  448: %% before setting a timer.
  449: 
  450: timer_delay(Config) when is_list(Config) ->
  451:     ?line Dog = test_server:timetrap(test_server:minutes(1)),
  452:     Name = 'timer_drv',
  453:     ?line Port = start_driver(Config, Name, false),
  454: 
  455:     ?line TimeBefore = now(),
  456:     Timeout0 = 350,
  457:     ?line erlang:port_command(Port, <<?DELAY_START_TIMER,Timeout0:32>>),
  458:     Timeout = Timeout0 +
  459: 	case os:type() of
  460: 	    {win32,_} -> 0;			%Driver doesn't sleep on Windows.
  461: 	    _ -> 1000
  462: 	end,
  463:     receive
  464: 	{Port,{data,[?TIMER]}} ->
  465: 	    ?line Elapsed = erl_millisecs() - erl_millisecs(TimeBefore),
  466: 	    io:format("Elapsed time: ~p Timeout: ~p\n",
  467: 		      [Elapsed,Timeout]), 
  468: 	    if
  469: 		Elapsed < Timeout ->
  470: 		    ?line ?t:fail(too_short);
  471: 		Elapsed > Timeout + ?delay ->
  472: 		    ?line ?t:fail(too_long);
  473: 		true ->
  474: 		    ok
  475: 	    end
  476:     end,
  477: 
  478:     ?line stop_driver(Port, Name),
  479:     ?line test_server:timetrap_cancel(Dog),
  480:     ok.
  481: 
  482: %% Test that driver_set_timer with new timout really changes
  483: %% the timer (ticket OTP-5942), it didn't work before
  484: 
  485: timer_change(Config) when is_list(Config) ->
  486:     ?line Dog = test_server:timetrap(test_server:minutes(1)),
  487:     Name = 'timer_drv',
  488:     ?line Port = start_driver(Config, Name, false),
  489: 
  490:     ?line try_change_timer(Port, 10000),
  491: 
  492:     ?line stop_driver(Port, Name),
  493:     ?line test_server:timetrap_cancel(Dog),
  494:     ok.
  495:     
  496: try_change_timer(_Port, 0) -> ok;
  497: try_change_timer(Port, Timeout) ->
  498:     ?line Timeout_3 = Timeout*3,
  499:     ?line TimeBefore = now(),
  500:     ?line erlang:port_command(Port, <<?START_TIMER,Timeout_3:32>>),
  501:     ?line erlang:port_command(Port, <<?START_TIMER,Timeout:32>>),
  502:     receive
  503: 	{Port,{data,[?TIMER]}} ->
  504: 	    ?line Elapsed = erl_millisecs() - erl_millisecs(TimeBefore),
  505: 	    io:format("Elapsed: ~p Timeout: ~p\n", [Elapsed,Timeout]),
  506: 	    if
  507: 		Elapsed < Timeout ->
  508: 		    ?line ?t:fail(too_short);
  509: 		Elapsed > Timeout + ?delay ->
  510: 		    ?line ?t:fail(too_long);
  511: 		true ->
  512: 		    try_timeouts(Port, Timeout div 2)
  513: 	    end
  514:     after Timeout + ?delay ->
  515: 	    ?line test_server:fail("driver failed to timeout")
  516:     end.
  517: 
  518: 
  519: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  520: %% 		Queue test suites
  521: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  522: 
  523: queue_echo(doc) ->
  524:     ["1) Queue up data in a driver that uses the full driver_queue API to do this."
  525:      "2) Get the data back, a random amount at a time."];
  526: queue_echo(Config) when is_list(Config) ->
  527:     case ?t:is_native(?MODULE) of
  528: 	true -> exit(crashes_native_code);
  529: 	false -> queue_echo_1(Config)
  530:     end.
  531: 
  532: queue_echo_1(Config) ->
  533:     ?line Dog = test_server:timetrap(test_server:minutes(10)),
  534:     Name = 'queue_drv',
  535:     ?line P = start_driver(Config, Name, true),
  536: 
  537:     ?line q_echo(P, [{?ENQ, {list,1}},
  538: 		     {?ENQ, {list,0}},
  539: 		     {?ENQ, {bin,0}},
  540: 		     {?ENQ, {bin,1}},
  541: 		     {?ENQ, {bin,2}},
  542: 		     {?ENQ, {bin,3}},
  543: 		     {?ENQ, {bin,4}},
  544: 		     {?ENQ, {bin,5}},
  545: 		     {?ENQ, {bin,600}},
  546: 		     {?PUSHQ, {list,0}},
  547: 		     {?PUSHQ, {list,1}},
  548: 		     {?PUSHQ, {bin,0}},
  549: 		     {?PUSHQ, {bin,1}},
  550: 		     {?PUSHQ, {bin,888}},
  551: 		     {?ENQ_BIN, {bin,0}},
  552: 		     {?ENQ_BIN, {bin,1}},
  553: 		     {?ENQ_BIN, {bin,2}},
  554: 		     {?ENQ_BIN, {bin,3}},
  555: 		     {?ENQ_BIN, {bin,4}},
  556: 		     {?ENQ_BIN, {bin,777}},
  557: 		     {?PUSHQ_BIN, {bin,0}},
  558: 		     {?PUSHQ_BIN, {bin,1}},
  559: 		     {?PUSHQ_BIN, {bin,334}},
  560: 		     {?ENQV, [{bin,0},{list,1},{bin,1},{bin,555}]},
  561: 		     {?ENQV, [{bin,0},{list,1},{bin,1}]},
  562: 		     {?PUSHQV, [{bin,0},{list,1},{bin,1},{bin,319}]}]),
  563: 
  564:     ?line stop_driver(P, Name),
  565:     ?line test_server:timetrap_cancel(Dog),
  566:     ok.
  567: 
  568: q_echo(Port, SpecList) ->
  569:     io:format("Heap binaries"),
  570:     HeapData = [{M,build_data(T)} || {M,T} <- SpecList],
  571:     {HeapDataReturn,HeapDataLen} = feed_driver(Port, HeapData),
  572:     dequeue(Port, HeapDataReturn, HeapDataLen, 1),
  573: 
  574:     %% Try sub binaries.
  575:     io:format("Sub binaries of heap binaries"),
  576:     SubHeapData = make_sub_binaries(HeapData),
  577:     %% The following line will generate a warning.
  578:     {HeapDataReturn,HeapDataLen} = feed_driver(Port, SubHeapData),
  579:     dequeue(Port, HeapDataReturn, HeapDataLen, 1),
  580: 
  581:     %% Try refc binaries.
  582:     io:format("Refc binaries"),
  583:     RefcData = make_refc_binaries(HeapData),
  584:     {RefcDataReturn,RefcDataLen} = feed_driver(Port, RefcData),
  585:     dequeue(Port, RefcDataReturn, RefcDataLen, 1),
  586: 
  587:     %% Try sub binaries of refc binaries.
  588:     io:format("Sub binaries of refc binaries"),
  589:     SubRefcData = make_sub_binaries(RefcData),
  590:     {RefcDataReturn,RefcDataLen} = feed_driver(Port, SubRefcData),
  591:     dequeue(Port, RefcDataReturn, RefcDataLen, 1),
  592: 
  593:     %% Try a writable binary.
  594:     io:format("Writable binaries"),
  595:     WritableBinData = make_writable_binaries(HeapData),
  596:     {WritableDataReturn,WritableDatalen} = feed_driver(Port, WritableBinData),
  597:     _ = append_to_writable_binaries(WritableBinData),
  598:     dequeue(Port, WritableDataReturn, WritableDatalen, 1),
  599: 
  600:     %% Try dequeing more than one byte at the time.
  601:     io:format("Heap binaries -- dequeueing more than one byte at the time"),
  602:     feed_and_dequeue(Port, HeapData, 2),
  603:     feed_and_dequeue(Port, HeapData, 3),
  604:     feed_and_dequeue(Port, HeapData, 4),
  605:     
  606:     io:format("\n").
  607: 
  608: feed_and_dequeue(Port, Data, DeqSize) ->
  609:     {DataReturn,DataLen} = feed_driver(Port, Data),
  610:     dequeue(Port, DataReturn, DataLen, DeqSize),
  611:     ok.
  612: 
  613: %% Send all data according to the specification to the driver side (where it
  614: %% is queued up for later return to this process).    
  615: 
  616: feed_driver(Port, Description) ->
  617:     feed_driver(Port, Description, <<>>, 0).
  618: 
  619: feed_driver(Port, [], ExpectedInPort, Qb) ->
  620:     io:format("Expected in port: ~P", [ExpectedInPort,12]),
  621:     io:format("In port: ~P", [read_head(Port, Qb),12]),
  622:     {ExpectedInPort,Qb};
  623: feed_driver(Port, [{Method0,Data}|T], Expected_return, Qb_before) ->
  624:     Method = case Method0 of
  625: 		 ?RANDOM -> uniform(6)-1;
  626: 		 Other -> Other
  627: 	     end,
  628:     Size = size(list_to_binary([Data])),
  629: 
  630:     %% ***********************************************************************
  631:     %% NOTE! Never never never change this to io:format/2, as that will imply
  632:     %% message sending, and sending as message will spoil the test of
  633:     %% writable binaries.
  634: 
  635:     %% erlang:display({sending,method_name(Method),Data}),
  636:     %% ***********************************************************************
  637: 
  638:     queue_op(Port, Method, Data),
  639: 
  640:     Qb_in_driver = bytes_queued(Port),
  641:     case Qb_before + Size of
  642: 	Qb_in_driver -> ok;
  643: 	Sum ->
  644: 	    io:format("Qb_before: ~p\n"
  645: 		      "Qb_before+Size: ~p\n"
  646: 		      "Qb_in_driver: ~p",
  647: 		      [Qb_before,Sum,Qb_in_driver]),
  648: 	    ?t:fail()
  649:     end,
  650:     X_return = case Method of
  651: 		   ?ENQ -> list_to_binary([Expected_return,Data]);
  652: 		   ?PUSHQ -> list_to_binary([Data,Expected_return]);
  653: 		   ?PUSHQ_BIN -> list_to_binary([Data,Expected_return]);
  654: 		   ?ENQ_BIN -> list_to_binary([Expected_return,Data]);
  655: 		   ?PUSHQV -> list_to_binary([Data,Expected_return]);
  656: 		   ?ENQV -> list_to_binary([Expected_return,Data])
  657: 	       end,
  658:     feed_driver(Port, T, X_return, Qb_before + Size).
  659: 
  660: %% method_name(0) -> pushq;
  661: %% method_name(1) -> enq;
  662: %% method_name(2) -> pushq_bin;
  663: %% method_name(3) -> enq_bin;
  664: %% method_name(4) -> pushqv;
  665: %% method_name(5) -> enqv.
  666: 
  667: dequeue(Port, DataList, LenToGet, DeqSize) ->
  668:     io:format("Dequeuing ~p bytes, ~p byte(s) at once...", [LenToGet,DeqSize]),
  669:     compare_return(Port, DataList, LenToGet, DeqSize).
  670: 
  671: compare_return(Port, _Data_list, 0, _Back_len) ->
  672:     0 = bytes_queued(Port);
  673: compare_return(Port, QueuedInPort0, Len_to_get, DeqSize) ->
  674:     case bytes_queued(Port) of
  675: 	Len_to_get -> ok;
  676: 	BytesInQueue ->
  677: 	    io:format("Len_to_get: ~p", [Len_to_get]),
  678: 	    io:format("Bytes in queue: ~p", [BytesInQueue]),
  679: 	    ?line test_server:fail()
  680:     end,
  681:     BytesToDequeue = if (DeqSize > Len_to_get) -> Len_to_get;
  682: 			true -> DeqSize
  683: 		     end,
  684:     Dequeued = read_head(Port, BytesToDequeue),
  685:     case bin_prefix(Dequeued, QueuedInPort0) of
  686: 	true ->
  687: 	    deq(Port, BytesToDequeue),
  688: 	    <<_:BytesToDequeue/binary,QueuedInPort/binary>> = QueuedInPort0,
  689: 	    compare_return(Port, QueuedInPort, Len_to_get - BytesToDequeue, DeqSize);
  690: 	false ->
  691: 	    io:format("Bytes to dequeue: ~p", [BytesToDequeue]),
  692: 	    io:format("Dequeued: ~p", [Dequeued]),
  693: 	    io:format("Queued in port: ~P", [QueuedInPort0,12]),
  694: 	    ?t:fail()
  695:     end.
  696: 
  697: %% bin_prefix(PrefixBinary, Binary)
  698: %%  Is PrefixBinary a prefix of Binary?
  699: 
  700: bin_prefix(<<C:8,PreTail/binary>>, <<C:8,Tail/binary>>) ->
  701:     bin_prefix(PreTail, Tail);
  702: bin_prefix(<<>>, _Bin) -> true;
  703: bin_prefix(_, _) -> false.
  704: 
  705: queue_op(Port, Method, Data) ->
  706:     [] = erlang:port_control(Port, Method, []),
  707:     Port ! {self(),{command,Data}},
  708:     ok.
  709: 
  710: bytes_queued(Port) ->
  711:     case erlang:port_control(Port, ?BYTES_QUEUED, []) of
  712: 	<<I:32>> -> I;
  713: 	Bad -> ?t:fail({bad_result,Bad})
  714:     end.
  715: 
  716: deq(Port, Size) ->
  717:     [] = erlang:port_control(Port, ?DEQ, <<Size:32>>).
  718: 
  719: read_head(Port, Size) ->
  720:     erlang:port_control(Port, ?READ_HEAD, <<Size:32>>).
  721: 
  722: 
  723: driver_unloaded(doc) ->
  724:     [];
  725: driver_unloaded(suite) ->
  726:     [];
  727: driver_unloaded(Config) when is_list(Config) ->
  728:     ?line process_flag(trap_exit, true),
  729:     ?line Drv = timer_drv,
  730:     ?line User = self(),
  731:     ?line Loaded = make_ref(),
  732:     ?line Die = make_ref(),
  733:     ?line Loader = spawn(fun () ->
  734: 				 erl_ddll:start(),
  735: 				 ok = load_driver(?config(data_dir,
  736: 								   Config),
  737: 							   Drv),
  738: 				 User ! Loaded,
  739: 				 receive Die -> exit(bye) end
  740: 			 end),
  741:     ?line receive Loaded -> ok end,
  742:     ?line Port = open_port({spawn, Drv}, []),
  743:     ?line Loader ! Die,
  744:     ?line receive
  745: 	      {'EXIT', Port, Reason} ->
  746: 		  ?line driver_unloaded = Reason
  747: 		  %% Reason used to be -1
  748: 	  end.
  749: 					 
  750: 
  751: io_ready_exit(doc) -> [];
  752: io_ready_exit(suite) -> [];
  753: io_ready_exit(Config) when is_list(Config) ->
  754:     ?line OTE = process_flag(trap_exit, true),
  755:     ?line Test = self(),
  756:     ?line Dgawd = spawn(fun () ->
  757: 				ok = dgawd_handler:install(),
  758: 				Mon = erlang:monitor(process, Test),
  759: 				Test ! dgawd_handler_started,
  760: 				receive
  761: 				    {'DOWN', Mon, _, _, _} -> ok;
  762: 				    stop_dgawd_handler -> ok
  763: 				end,
  764: 				dgawd_handler:restore(),
  765: 				Test ! dgawd_handler_stopped
  766: 			end),
  767:     ?line receive dgawd_handler_started -> ok end,
  768:     ?line Drv = io_ready_exit_drv,
  769:     ?line erl_ddll:start(),
  770:     ?line ok = load_driver(?config(data_dir, Config), Drv),
  771:     ?line Port = open_port({spawn, Drv}, []),
  772:     ?line case erlang:port_control(Port, 0, "") of
  773: 	      "ok" ->
  774: 		  receive
  775: 		      {'EXIT', Port, Reason} ->
  776: 			  ?line case Reason of
  777: 				    ready_output_driver_failure ->
  778: 					?t:format("Exited in output_ready()~n"),
  779: 					?line ok;
  780: 				    ready_input_driver_failure ->
  781: 					?t:format("Exited in input_ready()~n"),
  782: 					?line ok;
  783: 				    Error -> ?line ?t:fail(Error)
  784: 				end
  785: 		  end,
  786: 		  receive after 2000 -> ok end,
  787: 		  ?line false = dgawd_handler:got_dgawd_report(),
  788: 		  ?line Dgawd ! stop_dgawd_handler,
  789: 		  ?line receive dgawd_handler_stopped -> ok end,
  790: 		  ?line process_flag(trap_exit, OTE),
  791: 		  ?line ok;
  792: 	      "nyiftos" ->
  793: 		  ?line process_flag(trap_exit, OTE),
  794: 		  ?line {skipped, "Not yet implemented for this OS"};
  795: 	      Error ->
  796: 		  ?line process_flag(trap_exit, OTE),
  797: 		  ?line ?t:fail({unexpected_control_result, Error})
  798: 	  end.
  799:     
  800: 
  801: -define(CHKIO_STOP, 0).
  802: -define(CHKIO_USE_FALLBACK_POLLSET, 1).
  803: -define(CHKIO_BAD_FD_IN_POLLSET, 2).
  804: -define(CHKIO_DRIVER_EVENT, 3).
  805: -define(CHKIO_FD_CHANGE, 4).
  806: -define(CHKIO_STEAL, 5).
  807: -define(CHKIO_STEAL_AUX, 6).
  808: -define(CHKIO_SMP_SELECT, 7).
  809: -define(CHKIO_DRV_USE, 8).
  810: 
  811: use_fallback_pollset(doc) -> [];
  812: use_fallback_pollset(suite) -> [];
  813: use_fallback_pollset(Config) when is_list(Config) ->
  814:     FlbkFun = fun () ->
  815: 		      ChkIoDuring = erlang:system_info(check_io),
  816: 		      case lists:keysearch(fallback_poll_set_size,
  817: 					   1,
  818: 					   ChkIoDuring) of
  819: 			  {value,
  820: 			   {fallback_poll_set_size, N}} when N > 0 ->
  821: 			      ?line ok;
  822: 			  Error ->
  823: 			      ?line ?t:fail({failed_to_use_fallback, Error})
  824: 		      end
  825: 	      end,
  826:     ?line {BckupTest, Handel, OkRes}
  827: 	= case chkio_test_init(Config) of
  828: 	      {erts_poll_info, ChkIo} = Hndl ->
  829: 		  case lists:keysearch(fallback, 1, ChkIo) of
  830: 		      {value, {fallback, B}} when B =/= false ->
  831: 			  ?line {FlbkFun, Hndl, ok};
  832: 		      _ ->
  833: 			  ?line {fun () -> ok end,
  834: 				 Hndl,
  835: 				 {comment,
  836: 				  "This implementation does not use "
  837: 				  "a fallback pollset"}}
  838: 		  end;
  839: 	      Skip ->
  840: 		  {fun () -> ok end, Skip, ok}
  841: 	  end,
  842:     ?line case chkio_test_fini(chkio_test(Handel,
  843: 					  ?CHKIO_USE_FALLBACK_POLLSET,
  844: 					  fun () ->
  845: 						  ?line sleep(1000),
  846: 						  ?line BckupTest()
  847: 					  end)) of
  848: 	      {skipped, _} = Res -> ?line Res;
  849: 	      _ -> ?line OkRes
  850: 	  end.
  851: 
  852: bad_fd_in_pollset(doc) -> [];
  853: bad_fd_in_pollset(suite) -> [];
  854: bad_fd_in_pollset(Config) when is_list(Config) ->
  855:     ?line chkio_test_fini(chkio_test(chkio_test_init(Config),
  856: 				     ?CHKIO_BAD_FD_IN_POLLSET,
  857: 				     fun () -> ?line sleep(1000) end)).
  858: 
  859: driver_event(doc) -> [];
  860: driver_event(suite) -> [];
  861: driver_event(Config) when is_list(Config) ->
  862:     ?line chkio_test_fini(chkio_test(chkio_test_init(Config),
  863: 				     ?CHKIO_DRIVER_EVENT,
  864: 				     fun () -> ?line sleep(1000) end)).
  865: 
  866: fd_change(doc) -> [];
  867: fd_change(suite) -> [];
  868: fd_change(Config) when is_list(Config) ->
  869:     ?line chkio_test_fini(chkio_test(chkio_test_init(Config),
  870: 				     ?CHKIO_FD_CHANGE,
  871: 				     fun () -> ?line sleep(1000) end)).
  872: 
  873: steal_control(doc) -> [];
  874: steal_control(suite) -> [];
  875: steal_control(Config) when is_list(Config) ->
  876:     ?line chkio_test_fini(case chkio_test_init(Config) of
  877: 			      {erts_poll_info, _} = Hndl ->
  878: 				  ?line steal_control_test(Hndl);
  879: 			      Skip ->
  880: 				  ?line Skip
  881: 			  end).
  882: 
  883: steal_control_test(Hndl = {erts_poll_info, Before}) ->
  884:     ?line Port = open_chkio_port(),
  885:     ?line case erlang:port_control(Port, ?CHKIO_STEAL_AUX, "") of
  886: 	      [$f,$d,$s,$:| _] = FdList ->
  887: 		  ?line chk_chkio_port(Port),
  888: 		  sleep(500),
  889: 		  ?line chk_chkio_port(Port),
  890: 		  ?line Res = chkio_test(Hndl,
  891: 					 ?CHKIO_STEAL,
  892: 					 FdList,
  893: 					 fun () ->
  894: 						 ?line chk_chkio_port(Port),
  895: 						 ?line sleep(500),
  896: 						 ?line chk_chkio_port(Port)
  897: 					 end),
  898: 		  ?line case erlang:port_control(Port, ?CHKIO_STOP, "") of
  899: 			    "ok" ->
  900: 				?line chk_chkio_port(Port),
  901: 				?line ok;
  902: 			    StopErr ->
  903: 				?line chk_chkio_port(Port),
  904: 				?line ?t:fail({stop_error, StopErr})
  905: 			end,
  906: 		  ?line close_chkio_port(Port),
  907: 		  ?line Res;
  908: 	      [$s,$k,$i,$p,$:,$\ |Skip] ->
  909: 		  ?line chk_chkio_port(Port),
  910: 		  ?line close_chkio_port(Port),
  911: 		  {chkio_test_result,
  912: 		   {skipped, Skip},
  913: 		   Before};
  914: 	      StartErr ->
  915: 		  ?line chk_chkio_port(Port),
  916: 		  ?line ?t:fail({start_error, StartErr})
  917: 	  end.
  918: 
  919: chkio_test_init(Config) when is_list(Config) ->
  920:     ?line wait_until_no_pending_updates(),
  921:     ?line ChkIo = erlang:system_info(check_io),
  922:     ?line case catch lists:keysearch(name, 1, ChkIo) of
  923: 	      {value, {name, erts_poll}} ->
  924: 		  ?line ?t:format("Before test: ~p~n", [ChkIo]),
  925: 		  ?line Path = ?config(data_dir, Config),
  926: 		  ?line erl_ddll:start(),
  927: 		  ?line ok = load_driver(Path, 'chkio_drv'),
  928: 		  ?line process_flag(trap_exit, true),
  929: 		  ?line {erts_poll_info, ChkIo};
  930: 	      _ ->
  931: 		  ?line {skipped, "Test written to test erts_poll() which isn't used"}
  932: 	  end.
  933: 		  
  934: 
  935: chkio_test_fini({skipped, _} = Res) ->
  936:     Res;
  937: chkio_test_fini({chkio_test_result, Res, Before}) ->
  938:     ?line ok = erl_ddll:unload_driver('chkio_drv'),
  939:     ?line ok = erl_ddll:stop(),
  940:     ?line wait_until_no_pending_updates(),
  941:     ?line After = erlang:system_info(check_io),
  942:     ?line ?t:format("After test: ~p~n", [After]),
  943:     ?line verify_chkio_state(Before, After),
  944:     ?line Res.
  945: 
  946: open_chkio_port() ->
  947:     open_port({spawn, 'chkio_drv'}, []).
  948: 
  949: close_chkio_port(Port) when is_port(Port) ->
  950:     true = erlang:port_close(Port),
  951:     receive
  952: 	{'EXIT', Port, normal} ->
  953: 	    ok;
  954: 	{'EXIT', Port, Reason} ->
  955: 	    ?t:fail({abnormal_port_exit, Port, Reason});
  956: 	{Port, Message} ->
  957: 	    ?t:fail({strange_message_from_port, Message})
  958:     end.
  959: 
  960: chk_chkio_port(Port) ->
  961:     receive
  962: 	{'EXIT', Port, Reason} when Reason /= normal ->
  963: 	    ?t:fail({port_exited, Port, Reason})
  964:     after 0 ->
  965: 	    ok
  966:     end.
  967: 	    
  968: 
  969: chkio_test({skipped, _} = Res, _Test, _Fun) ->
  970:     ?line Res;
  971: chkio_test({erts_poll_info, _Before} = EPI, Test, Fun) when is_integer(Test) ->
  972:     chkio_test(EPI, Test, "", Fun).
  973: 
  974: chkio_test({skipped, _} = Res, _Test, _TestArgs, _Fun) ->
  975:     ?line Res;
  976: chkio_test({erts_poll_info, Before},
  977: 	   Test,
  978: 	   TestArgs,
  979: 	   Fun) when is_integer(Test),
  980: 		     is_list(TestArgs) ->
  981:     ?line Port = open_chkio_port(),
  982:     ?line case erlang:port_control(Port, Test, TestArgs) of
  983: 	      "ok" ->
  984: 		  ?line chk_chkio_port(Port),
  985: 		  ?line Fun(),
  986: 		  ?line During = erlang:system_info(check_io),
  987: 		  ?line erlang:display(During),
  988: 		  ?line 0 = erts_debug:get_internal_state(check_io_debug),
  989: 		  ?line ?t:format("During test: ~p~n", [During]),
  990: 		  ?line chk_chkio_port(Port),
  991: 		  ?line case erlang:port_control(Port, ?CHKIO_STOP, "") of
  992: 			    Res when is_list(Res) ->
  993: 				?line chk_chkio_port(Port),
  994: 				?line ?t:format("~s", [Res]),
  995: 				?line close_chkio_port(Port),
  996: 				?line Res,
  997: 				?line case Res of
  998: 					  [$c,$o,$m,$m,$e,$n,$t,$:,$\ |Cmnt] ->
  999: 					      ?line {chkio_test_result,
 1000: 						     {comment, Cmnt},
 1001: 						     Before};
 1002: 					  _ ->
 1003: 					      ?line {chkio_test_result,
 1004: 						     Res,
 1005: 						     Before}
 1006: 				      end;
 1007: 			    StopErr ->
 1008: 				?line chk_chkio_port(Port),
 1009: 				?line ?t:fail({stop_error, StopErr})
 1010: 			end;
 1011: 	      [$s,$k,$i,$p,$:,$\ |Skip] ->
 1012: 		  ?line chk_chkio_port(Port),
 1013: 		  ?line close_chkio_port(Port),
 1014: 		  {chkio_test_result,
 1015: 		   {skipped, Skip},
 1016: 		   Before};
 1017: 	      StartErr ->
 1018: 		  ?line chk_chkio_port(Port),
 1019: 		  ?line ?t:fail({start_error, StartErr})
 1020: 	  end.
 1021: 
 1022: verify_chkio_state(Before, After) ->
 1023:     ?line TotSetSize = lists:keysearch(total_poll_set_size, 1, Before),
 1024:     ?line TotSetSize = lists:keysearch(total_poll_set_size, 1, After),
 1025:     ?line case lists:keysearch(fallback, 1, Before) of
 1026: 	      {value,{fallback,false}} ->
 1027: 		  ?line ok;
 1028: 	      _ ->
 1029: 		  ?line BckupSetSize = lists:keysearch(fallback_poll_set_size,
 1030: 						       1,
 1031: 						       Before),
 1032: 		  ?line BckupSetSize = lists:keysearch(fallback_poll_set_size,
 1033: 						       1,
 1034: 						       After)
 1035: 	  end,
 1036:     ?line ok.
 1037:     
 1038:     
 1039: 
 1040: wait_until_no_pending_updates() ->
 1041:     case lists:keysearch(pending_updates, 1, erlang:system_info(check_io)) of
 1042: 	{value, {pending_updates, 0}} ->
 1043: 	    ok;
 1044: 	false ->
 1045: 	    ok;
 1046: 	_ ->
 1047: 	    receive after 10 -> ok end,
 1048: 	    wait_until_no_pending_updates()
 1049:     end.
 1050: 
 1051: otp_6602(doc) -> ["Missed port lock when stealing control of fd from a "
 1052: 		  "driver that didn't use the same lock. The lock checker "
 1053: 		  "used to trigger on this and dump core."];
 1054: otp_6602(suite) ->
 1055:     [];
 1056: otp_6602(Config) when is_list(Config) ->
 1057:     ?line {ok, Node} = start_node(Config),
 1058:     ?line Done = make_ref(),
 1059:     ?line Parent = self(),
 1060:     ?line Tester = spawn_link(Node,
 1061: 			      fun () ->
 1062: 				      %% Inet driver use port locking...
 1063: 				      {ok, S} = gen_udp:open(0),
 1064: 				      {ok, Fd} = inet:getfd(S),
 1065: 				      {ok, Port} = inet:port(S),
 1066: 				      %% Steal fd (lock checker used to
 1067: 				      %% trigger here).
 1068: 				      {ok, _S2} = gen_udp:open(Port,[{fd,Fd}]),
 1069: 				      Parent ! Done
 1070: 			      end),
 1071:     ?line receive Done -> ok end,
 1072:     ?line unlink(Tester),
 1073:     ?line stop_node(Node),
 1074:     ?line ok.
 1075: 
 1076: -define(EXPECTED_SYSTEM_INFO_NAMES1,
 1077: 	["drv_drv_vsn",
 1078: 	 "emu_drv_vsn",
 1079: 	 "erts_vsn",
 1080: 	 "otp_vsn",
 1081: 	 "thread",
 1082: 	 "smp"]).
 1083: -define(EXPECTED_SYSTEM_INFO_NAMES2,
 1084: 	(?EXPECTED_SYSTEM_INFO_NAMES1 ++
 1085: 	 ["async_thrs",
 1086: 	  "sched_thrs"])).
 1087: 
 1088: -define(EXPECTED_SYSTEM_INFO_NAMES, ?EXPECTED_SYSTEM_INFO_NAMES2).
 1089: 
 1090: 'driver_system_info_base_ver'(doc) ->
 1091:     [];
 1092: 'driver_system_info_base_ver'(suite) ->
 1093:     [];
 1094: 'driver_system_info_base_ver'(Config) when is_list(Config) ->
 1095:     ?line driver_system_info_test(Config, sys_info_base_drv).
 1096: 
 1097: 'driver_system_info_prev_ver'(doc) ->
 1098:     [];
 1099: 'driver_system_info_prev_ver'(suite) ->
 1100:     [];
 1101: 'driver_system_info_prev_ver'(Config) when is_list(Config) ->
 1102:     ?line driver_system_info_test(Config, sys_info_prev_drv).
 1103: 
 1104: driver_system_info_current_ver(doc) ->    
 1105:     [];
 1106: driver_system_info_current_ver(suite) ->
 1107:     [];
 1108: driver_system_info_current_ver(Config) when is_list(Config) ->
 1109:     ?line driver_system_info_test(Config, sys_info_curr_drv).
 1110: 
 1111: driver_system_info_test(Config, Name) ->
 1112:     ?line Port = start_driver(Config, Name, false),
 1113:     ?line case erlang:port_control(Port, 0, []) of
 1114: 	      [$o,$k,$:,_ | Result] ->
 1115: 		  ?line check_driver_system_info_result(Result);
 1116: 	      [$e,$r,$r,$o,$r,$:,_ | Error] ->
 1117: 		  ?line ?t:fail(Error);
 1118: 	      Unexpected ->
 1119: 		  ?line ?t:fail({unexpected_result, Unexpected})
 1120: 	  end,
 1121:     ?line stop_driver(Port, Name),
 1122:     ?line ok.
 1123: 
 1124: check_driver_system_info_result(Result) ->
 1125:     ?line ?t:format("All names: ~p~n", [?EXPECTED_SYSTEM_INFO_NAMES]),
 1126:     ?line ?t:format("Result: ~p~n", [Result]),
 1127:     ?line {[], Ns, DDVSN} = chk_sis(lists:map(fun (Str) ->
 1128: 						      string:tokens(Str, "=")
 1129: 					      end,
 1130: 					      string:tokens(Result, " ")),
 1131: 				    ?EXPECTED_SYSTEM_INFO_NAMES),
 1132:     ?line case {DDVSN,
 1133: 		drv_vsn_str2tup(erlang:system_info(driver_version))} of
 1134: 	      {DDVSN, DDVSN} ->
 1135: 		  ?line [] = Ns;
 1136: 	      {{1, 0}, _} ->
 1137: 		  ?line ExpNs = lists:sort(?EXPECTED_SYSTEM_INFO_NAMES
 1138: 					   -- ?EXPECTED_SYSTEM_INFO_NAMES1),
 1139: 		  ?line ExpNs = lists:sort(Ns);
 1140: 	      {{1, 1}, _} ->
 1141: 		  ?line ExpNs = lists:sort(?EXPECTED_SYSTEM_INFO_NAMES
 1142: 					   -- ?EXPECTED_SYSTEM_INFO_NAMES2),
 1143: 		  ?line ExpNs = lists:sort(Ns);
 1144: 	      {{2, 0}, _} ->
 1145: 		  ?line [] = Ns
 1146: 	  end.
 1147: 
 1148: chk_sis(SIs, Ns) ->
 1149:     chk_sis(SIs, Ns, unknown).
 1150: 
 1151: chk_sis(SIs, [], DDVSN) ->
 1152:     ?line {SIs, [], DDVSN};
 1153: chk_sis([], Ns, DDVSN) ->
 1154:     ?line {[], Ns, DDVSN};
 1155: chk_sis([[N, _] = SI| SIs], Ns, DDVSN) ->
 1156:     ?line true = lists:member(N, Ns),
 1157:     ?line case check_si_res(SI) of
 1158: 	      {driver_version, NewDDVSN} ->
 1159: 		  ?line chk_sis(SIs, lists:delete(N, Ns), NewDDVSN);
 1160: 	      _ ->
 1161: 		  ?line chk_sis(SIs, lists:delete(N, Ns), DDVSN)
 1162: 	  end.
 1163: 
 1164: %% Data in first version of driver_system_info() (driver version 1.0)
 1165: check_si_res(["drv_drv_vsn", Value]) ->
 1166:     ?line DDVSN = drv_vsn_str2tup(Value),
 1167:     ?line {Major, DMinor} = DDVSN,
 1168:     ?line {Major, EMinor} = drv_vsn_str2tup(erlang:system_info(driver_version)),
 1169:     ?line true = DMinor =< EMinor,
 1170:     ?line {driver_version, DDVSN};
 1171: check_si_res(["emu_drv_vsn", Value]) ->
 1172:     ?line Value = erlang:system_info(driver_version);
 1173: check_si_res(["erts_vsn", Value]) ->
 1174:     ?line Value = erlang:system_info(version);
 1175: check_si_res(["otp_vsn", Value]) ->
 1176:     ?line Value = erlang:system_info(otp_release);
 1177: check_si_res(["thread", "true"]) ->
 1178:     ?line true = erlang:system_info(threads);
 1179: check_si_res(["thread", "false"]) ->
 1180:     ?line false = erlang:system_info(threads);
 1181: check_si_res(["smp", "true"]) ->
 1182:     ?line true = erlang:system_info(smp_support);
 1183: check_si_res(["smp", "false"]) ->
 1184:     ?line false = erlang:system_info(smp_support);
 1185: 
 1186: %% Data added in second version of driver_system_info() (driver version 1.1)
 1187: check_si_res(["async_thrs", Value]) ->
 1188:     ?line Value = integer_to_list(erlang:system_info(thread_pool_size));
 1189: check_si_res(["sched_thrs", Value]) ->
 1190:     ?line Value = integer_to_list(erlang:system_info(schedulers));
 1191: 
 1192: check_si_res(Unexpected) ->
 1193:     ?line ?t:fail({unexpected_result, Unexpected}).
 1194: 
 1195: -define(MON_OP_I_AM_IPID,1).
 1196: -define(MON_OP_MONITOR_ME,2).
 1197: -define(MON_OP_DEMONITOR_ME,3).
 1198: -define(MON_OP_MONITOR_ME_LATER,4).
 1199: -define(MON_OP_DO_DELAYED_MONITOR,5).
 1200: 
 1201: driver_monitor(suite) ->
 1202:     [];
 1203: driver_monitor(doc) ->    
 1204:     ["Test monitoring of processes from drivers"];
 1205: driver_monitor(Config) when is_list(Config) ->
 1206:     ?line Name = monitor_drv,
 1207:     ?line Port = start_driver(Config, Name, false),
 1208:     ?line "ok" = port_control(Port,?MON_OP_I_AM_IPID,[]),
 1209:     ?line "ok" = port_control(Port,?MON_OP_MONITOR_ME,[]),
 1210:     ?line "ok" = port_control(Port,?MON_OP_DEMONITOR_ME,[]),
 1211:     ?line {monitors, []} = erlang:port_info(Port,monitors),
 1212:     
 1213:     ?line "ok:"++Id1 = port_control(Port,?MON_OP_MONITOR_ME_LATER,[]),
 1214:     ?line {monitored_by, []} = process_info(self(),monitored_by),
 1215:     ?line "ok" = port_control(Port,?MON_OP_DO_DELAYED_MONITOR,Id1),
 1216:     ?line {monitored_by, [Port]} = process_info(self(),monitored_by),
 1217:     ?line "ok" = port_control(Port,?MON_OP_DEMONITOR_ME,[]),
 1218:     ?line {monitored_by, []} = process_info(self(),monitored_by),
 1219:     
 1220:     ?line "ok" = port_control(Port,?MON_OP_MONITOR_ME,[]),
 1221:     ?line Me = self(),
 1222:     ?line {Pid1,Ref1} =
 1223: 	spawn_monitor(fun() ->
 1224: 			      Me ! port_control(Port,?MON_OP_MONITOR_ME,[]), 
 1225: 			      Me ! process_info(self(),monitored_by), 
 1226: 			      Me ! erlang:port_info(Port,monitors) 
 1227: 		      end),
 1228:     ?line ok = receive
 1229: 		   "ok" ->
 1230: 		       ok
 1231: 	       after 1000 ->
 1232: 		       timeout
 1233: 	       end,
 1234:     ?line ok = receive
 1235: 		   {monitored_by, L} ->
 1236: 		       L2 = lists:sort(L),
 1237: 		       L3 = lists:sort([Me,Port]),
 1238: 		       case L2 of
 1239: 			   L3 ->
 1240: 			       ok;
 1241: 			   _ ->
 1242: 			       mismatch
 1243: 		       end
 1244: 	       after 1000 ->
 1245: 		       timeout
 1246: 	       end,
 1247:     ?line ok = receive
 1248: 		   {monitors, LL} ->
 1249: 		       LL2 = lists:sort(LL),
 1250: 		       LL3 = lists:sort([{process,Me},{process,Pid1}]),
 1251: 		       case LL2 of
 1252: 			   LL3 ->
 1253: 			       ok;
 1254: 			   _ ->
 1255: 			       mismatch
 1256: 		       end
 1257: 	       after 1000 ->
 1258: 		       timeout
 1259: 	       end,
 1260:     ?line ok = receive
 1261: 		   {'DOWN', Ref1, process, Pid1, _} ->
 1262: 		       ok
 1263: 	       after 1000 ->
 1264: 		       timeout
 1265: 	       end,
 1266:     ?line ok = receive
 1267: 		   {monitor_fired,Port,Pid1} ->
 1268: 		       ok
 1269: 	       after 1000 ->
 1270: 		       timeout
 1271: 	       end,
 1272:     ?line "ok" = port_control(Port,?MON_OP_DEMONITOR_ME,[]),
 1273:     ?line {monitors,[]} = erlang:port_info(Port,monitors),
 1274:     ?line {monitored_by, []} = process_info(self(),monitored_by),
 1275: 
 1276:     ?line "ok" = port_control(Port,?MON_OP_MONITOR_ME,[]),
 1277:     ?line {Pid2,Ref2} =
 1278: 	spawn_monitor(fun() -> 			       
 1279: 			      receive go -> ok end,
 1280: 			      Me ! port_control(Port,?MON_OP_MONITOR_ME_LATER,[]), 
 1281: 			      Me ! process_info(self(),monitored_by), 
 1282: 			      Me ! erlang:port_info(Port,monitors) 
 1283: 		      end),
 1284:     ?line Pid2 ! go,
 1285:     ?line {ok,Id2} = receive
 1286: 		   "ok:"++II ->
 1287: 		       {ok,II}
 1288: 	       after 1000 ->
 1289: 		       timeout
 1290: 	       end,
 1291:     ?line ok = receive
 1292: 		   {monitored_by, [Me]} ->
 1293: 		       ok
 1294: 	       after 1000 ->
 1295: 		       timeout
 1296: 	       end,
 1297:     ?line ok = receive
 1298: 		   {monitors, [{process,Me}]} ->
 1299: 		       ok
 1300: 	       after 1000 ->
 1301: 		       timeout
 1302: 	       end,
 1303:     ?line ok = receive
 1304: 		   {'DOWN', Ref2, process, Pid2, _} ->
 1305: 		       ok
 1306: 	       after 1000 ->
 1307: 		       timeout
 1308: 	       end,
 1309:     ?line "noproc" = port_control(Port,?MON_OP_DO_DELAYED_MONITOR,Id2),
 1310:     ?line {monitors,[{process,Me}]} = erlang:port_info(Port,monitors),
 1311:     ?line "ok" = port_control(Port,?MON_OP_DEMONITOR_ME,[]),
 1312:     ?line "not_monitored" = port_control(Port,?MON_OP_DEMONITOR_ME,[]),
 1313:     ?line {monitors,[]} = erlang:port_info(Port,monitors),
 1314:     ?line {monitored_by, []} = process_info(self(),monitored_by),
 1315: 
 1316: 
 1317:     ?line "ok" = port_control(Port,?MON_OP_MONITOR_ME,[]),
 1318:     ?line {Pid3,Ref3} =
 1319: 	spawn_monitor(fun() ->
 1320: 			      receive go -> ok end,
 1321: 			      Me ! port_control(Port,?MON_OP_MONITOR_ME_LATER,[]), 
 1322: 			      Me ! process_info(self(),monitored_by), 
 1323: 			      Me ! erlang:port_info(Port,monitors) ,
 1324: 			      receive die -> ok end
 1325: 		      end),
 1326:     ?line Pid3 ! go,
 1327:     ?line {ok,Id3} = receive
 1328: 		   "ok:"++III ->
 1329: 		       {ok,III}
 1330: 	       after 1000 ->
 1331: 		       timeout
 1332: 	       end,
 1333:     ?line ok = receive
 1334: 		   {monitored_by, [Me]} ->
 1335: 		       ok
 1336: 	       after 1000 ->
 1337: 		       timeout
 1338: 	       end,
 1339:     ?line ok = receive
 1340: 		   {monitors, [{process,Me}]} ->
 1341: 		       ok
 1342: 	       after 1000 ->
 1343: 		       timeout
 1344: 	       end,
 1345:     ?line "ok" = port_control(Port,?MON_OP_DO_DELAYED_MONITOR,Id3),
 1346:     ?line LLL1 = lists:sort([{process,Me},{process,Pid3}]),
 1347:     ?line {monitors,LLL2} = erlang:port_info(Port,monitors),
 1348:     ?line LLL1 = lists:sort(LLL2),
 1349:     ?line "ok" = port_control(Port,?MON_OP_DEMONITOR_ME,[]),
 1350:     ?line {monitors,[{process,Pid3}]} = erlang:port_info(Port,monitors),
 1351:     ?line Pid3 ! die,
 1352:     ?line ok = receive
 1353: 		   {'DOWN', Ref3, process, Pid3, _} ->
 1354: 		       ok
 1355: 	       after 1000 ->
 1356: 		       timeout
 1357: 	       end,
 1358:     ?line "not_found" = port_control(Port,?MON_OP_DO_DELAYED_MONITOR,Id2),
 1359:     ?line {monitors,[]} = erlang:port_info(Port,monitors),
 1360:     ?line "not_monitored" = port_control(Port,?MON_OP_DEMONITOR_ME,[]),
 1361:     ?line {monitors,[]} = erlang:port_info(Port,monitors),
 1362:     ?line {monitored_by, []} = process_info(self(),monitored_by),
 1363:     
 1364:     ?line stop_driver(Port, Name),
 1365:     ?line ok.
 1366: 
 1367: 
 1368: -define(IOQ_EXIT_READY_INPUT, 1).
 1369: -define(IOQ_EXIT_READY_OUTPUT, 2).
 1370: -define(IOQ_EXIT_TIMEOUT, 3).
 1371: -define(IOQ_EXIT_READY_ASYNC, 4).
 1372: -define(IOQ_EXIT_EVENT, 5).
 1373: -define(IOQ_EXIT_READY_INPUT_ASYNC, 6).
 1374: -define(IOQ_EXIT_READY_OUTPUT_ASYNC, 7).
 1375: -define(IOQ_EXIT_TIMEOUT_ASYNC, 8).
 1376: -define(IOQ_EXIT_EVENT_ASYNC, 9).
 1377: 
 1378: ioq_exit_test(Config, TestNo) ->
 1379:     ?line Drv = ioq_exit_drv,
 1380:     ?line try
 1381: 	      begin
 1382: 		  ?line case load_driver(?config(data_dir, Config),
 1383: 						  Drv) of
 1384: 			    ok -> ?line ok;
 1385: 			    {error, permanent} -> ?line ok;
 1386: 			    LoadError -> ?line ?t:fail({load_error, LoadError})
 1387: 			end,
 1388: 		  case open_port({spawn, Drv}, []) of
 1389: 		      Port when is_port(Port) ->
 1390: 			      try port_control(Port, TestNo, "") of
 1391: 				  "ok" ->
 1392: 				      ?line ok;
 1393: 				  "nyiftos" ->
 1394: 				      ?line throw({skipped,
 1395: 						   "Not yet implemented for "
 1396: 						   "this OS"});
 1397: 				  [$s,$k,$i,$p,$:,$ | Comment] ->
 1398: 				      ?line throw({skipped, Comment});
 1399: 				  [$e,$r,$r,$o,$r,$:,$ | Error] ->
 1400: 				      ?line ?t:fail(Error)
 1401: 			      after
 1402: 				  Port ! {self(), close},
 1403: 				receive {Port, closed} -> ok end,
 1404: 				false = lists:member(Port, erlang:ports()),
 1405: 				ok
 1406: 			      end;
 1407: 		      Error ->
 1408: 			  ?line ?t:fail({open_port_failed, Error})
 1409: 		  end
 1410: 	      end
 1411: 	  catch
 1412: 	      throw:Term -> ?line Term
 1413: 	  after
 1414: 	      erl_ddll:unload_driver(Drv)
 1415: 	  end.
 1416: 
 1417: ioq_exit_ready_input(doc) -> [];
 1418: ioq_exit_ready_input(suite) -> [];
 1419: ioq_exit_ready_input(Config) when is_list(Config) ->
 1420:     ioq_exit_test(Config, ?IOQ_EXIT_READY_INPUT).
 1421: 
 1422: ioq_exit_ready_output(doc) -> [];
 1423: ioq_exit_ready_output(suite) -> [];
 1424: ioq_exit_ready_output(Config) when is_list(Config) ->
 1425:     ioq_exit_test(Config, ?IOQ_EXIT_READY_OUTPUT).
 1426: 
 1427: ioq_exit_timeout(doc) -> [];
 1428: ioq_exit_timeout(suite) -> [];
 1429: ioq_exit_timeout(Config) when is_list(Config) ->
 1430:     ioq_exit_test(Config, ?IOQ_EXIT_TIMEOUT).
 1431: 
 1432: ioq_exit_ready_async(doc) -> [];
 1433: ioq_exit_ready_async(suite) -> [];
 1434: ioq_exit_ready_async(Config) when is_list(Config) ->
 1435:     ioq_exit_test(Config, ?IOQ_EXIT_READY_ASYNC).
 1436: 
 1437: ioq_exit_event(doc) -> [];
 1438: ioq_exit_event(suite) -> [];
 1439: ioq_exit_event(Config) when is_list(Config) ->
 1440:     ioq_exit_test(Config, ?IOQ_EXIT_EVENT).
 1441: 
 1442: ioq_exit_ready_input_async(doc) -> [];
 1443: ioq_exit_ready_input_async(suite) -> [];
 1444: ioq_exit_ready_input_async(Config) when is_list(Config) ->
 1445:     ioq_exit_test(Config, ?IOQ_EXIT_READY_INPUT_ASYNC).
 1446: 
 1447: ioq_exit_ready_output_async(doc) -> [];
 1448: ioq_exit_ready_output_async(suite) -> [];
 1449: ioq_exit_ready_output_async(Config) when is_list(Config) ->
 1450:     ioq_exit_test(Config, ?IOQ_EXIT_READY_OUTPUT_ASYNC).
 1451: 
 1452: ioq_exit_timeout_async(doc) -> [];
 1453: ioq_exit_timeout_async(suite) -> [];
 1454: ioq_exit_timeout_async(Config) when is_list(Config) ->
 1455:     ioq_exit_test(Config, ?IOQ_EXIT_TIMEOUT_ASYNC).
 1456: 
 1457: ioq_exit_event_async(doc) -> [];
 1458: ioq_exit_event_async(suite) -> [];
 1459: ioq_exit_event_async(Config) when is_list(Config) ->
 1460:     ioq_exit_test(Config, ?IOQ_EXIT_EVENT_ASYNC).
 1461: 
 1462: 
 1463: vsn_mismatch_test(Config, LoadResult) ->
 1464:     ?line Path = ?config(data_dir, Config),
 1465:     ?line DrvName = ?config(testcase, Config),
 1466:     ?line LoadResult = load_driver(Path, DrvName),
 1467:     ?line case LoadResult of
 1468: 	      ok ->
 1469: 		  ?line Port = open_port({spawn, DrvName}, []),
 1470: 		  ?line true = is_port(Port),
 1471: 		  ?line true = port_close(Port),
 1472: 		  ?line ok = erl_ddll:unload_driver(DrvName);
 1473: 	      _ ->
 1474: 		  ?line ok
 1475: 	  end.
 1476: 
 1477: zero_extended_marker_garb_drv(doc) -> [];
 1478: zero_extended_marker_garb_drv(suite) -> [];
 1479: zero_extended_marker_garb_drv(Config) when is_list(Config) ->
 1480:     vsn_mismatch_test(Config, {error, driver_incorrect_version}).
 1481: 
 1482: invalid_extended_marker_drv(doc) -> [];
 1483: invalid_extended_marker_drv(suite) -> [];
 1484: invalid_extended_marker_drv(Config) when is_list(Config) ->
 1485:     vsn_mismatch_test(Config, {error, driver_incorrect_version}).
 1486: 
 1487: larger_major_vsn_drv(doc) -> [];
 1488: larger_major_vsn_drv(suite) -> [];
 1489: larger_major_vsn_drv(Config) when is_list(Config) ->
 1490:     vsn_mismatch_test(Config, {error, driver_incorrect_version}).
 1491: 
 1492: larger_minor_vsn_drv(doc) -> [];
 1493: larger_minor_vsn_drv(suite) -> [];
 1494: larger_minor_vsn_drv(Config) when is_list(Config) ->
 1495:     vsn_mismatch_test(Config, {error, driver_incorrect_version}).
 1496: 
 1497: smaller_major_vsn_drv(doc) -> [];
 1498: smaller_major_vsn_drv(suite) -> [];
 1499: smaller_major_vsn_drv(Config) when is_list(Config) ->
 1500:     vsn_mismatch_test(Config, {error, driver_incorrect_version}).
 1501: 
 1502: smaller_minor_vsn_drv(doc) -> [];
 1503: smaller_minor_vsn_drv(suite) -> [];
 1504: smaller_minor_vsn_drv(Config) when is_list(Config) ->
 1505:     DrvVsnStr = erlang:system_info(driver_version),
 1506:     case drv_vsn_str2tup(DrvVsnStr) of
 1507: 	{_, 0} ->
 1508: 	    {skipped,
 1509: 	     "Cannot perform test when minor driver version is 0. "
 1510: 	     "Current driver version is " ++ DrvVsnStr ++ "."};
 1511: 	_ ->
 1512: 	    vsn_mismatch_test(Config, ok)
 1513:     end.
 1514: 
 1515: -define(PEEK_NONXQ_TEST, 0).
 1516: -define(PEEK_NONXQ_WAIT, 1).
 1517: 
 1518: peek_non_existing_queue(doc) -> [];
 1519: peek_non_existing_queue(suite) -> [];
 1520: peek_non_existing_queue(Config) when is_list(Config) ->
 1521:     ?line OTE = process_flag(trap_exit, true),
 1522:     ?line Drv = peek_non_existing_queue_drv,
 1523:     ?line try
 1524: 	      begin
 1525: 		  ?line case load_driver(?config(data_dir, Config),
 1526: 						  Drv) of
 1527: 			    ok -> ?line ok;
 1528: 			    {error, permanent} -> ?line ok;
 1529: 			    LoadError -> ?line ?t:fail({load_error, LoadError})
 1530: 			end,
 1531: 		  case open_port({spawn, Drv}, []) of
 1532: 		      Port1 when is_port(Port1) ->
 1533: 			  try port_control(Port1, ?PEEK_NONXQ_TEST, "") of
 1534: 			      "ok" ->
 1535: 				  ?line ok;
 1536: 			      [$s,$k,$i,$p,$p,$e,$d,$:,$ | SkipReason] ->
 1537: 				  ?line throw({skipped, SkipReason});
 1538: 			      [$e,$r,$r,$o,$r,$:,$ | Error1] ->
 1539: 				  ?line ?t:fail(Error1)
 1540: 			  after
 1541: 			      exit(Port1, kill),
 1542: 			    receive {'EXIT', Port1, _} -> ok end
 1543: 			  end;
 1544: 		      Error1 ->
 1545: 			  ?line ?t:fail({open_port1_failed, Error1})
 1546: 		  end,
 1547: 		  case open_port({spawn, Drv}, []) of
 1548: 		      Port2 when is_port(Port2) ->
 1549: 			  try port_control(Port2, ?PEEK_NONXQ_WAIT, "") of
 1550: 			      "ok" ->
 1551: 				  ?line ok;
 1552: 			      [$e,$r,$r,$o,$r,$:,$ | Error2] ->
 1553: 				  ?line ?t:fail(Error2)
 1554: 			  after
 1555: 			      receive {Port2, test_successful} -> ok end,
 1556: 			    Port2 ! {self(), close},
 1557: 			    receive {Port2, closed} -> ok end
 1558: 			  end;
 1559: 		      Error2 ->
 1560: 			  ?line ?t:fail({open_port2_failed, Error2})
 1561: 		  end
 1562: 	      end
 1563: 	  catch
 1564: 	      throw:Term -> ?line Term
 1565: 	  after
 1566: 	      process_flag(trap_exit, OTE),
 1567: 	      erl_ddll:unload_driver(Drv)
 1568: 	  end.    
 1569: 
 1570: otp_6879(doc) ->
 1571:     [];
 1572: otp_6879(suite) ->
 1573:     [];
 1574: otp_6879(Config) when is_list(Config) ->
 1575:     ?line Drv = 'otp_6879_drv',
 1576:     ?line Parent = self(),
 1577:     ?line ok = load_driver(?config(data_dir, Config), Drv),
 1578:     ?line Procs = lists:map(
 1579: 		    fun (No) ->
 1580: 			    spawn_link(
 1581: 			      fun () ->
 1582: 				      case open_port({spawn, Drv}, []) of
 1583: 					  Port when is_port(Port) ->
 1584: 					      Res = otp_6879_call(Port, No, 10000),
 1585: 					      erlang:port_close(Port),
 1586: 					      Parent ! {self(), Res};
 1587: 					  _ ->
 1588: 					      Parent ! {self(),
 1589: 							open_port_failed}
 1590: 				      end
 1591: 			      end)
 1592: 		    end,
 1593: 		    lists:seq(1,10)),
 1594:     ?line lists:foreach(fun (P) ->
 1595: 				?line receive
 1596: 					  {P, ok} ->
 1597: 					      ?line ok;
 1598: 					  {P, Error} ->
 1599: 					      ?line ?t:fail({P, Error})
 1600: 				      end
 1601: 			end,
 1602: 			Procs),
 1603:     %% Also try it when input exceeds default buffer (256 bytes)
 1604:     ?line Data = lists:seq(1, 1000),
 1605:     ?line case open_port({spawn, Drv}, []) of
 1606: 	      Port when is_port(Port) ->
 1607: 		  ?line ok = otp_6879_call(Port, Data, 10),
 1608: 		  ?line erlang:port_close(Port);
 1609: 	      _ ->
 1610: 		  ?line ?t:fail(open_port_failed)
 1611: 	  end,
 1612:     ?line erl_ddll:unload_driver(Drv),
 1613:     ?line ok.
 1614: 
 1615: otp_6879_call(_Port, _Data, 0) ->
 1616:     ok;
 1617: otp_6879_call(Port, Data, N) ->
 1618:     case catch erlang:port_call(Port, 0, Data) of
 1619: 	Data -> otp_6879_call(Port, Data, N-1);
 1620: 	BadData -> {mismatch, Data, BadData}
 1621:     end.
 1622: 
 1623: caller(doc) ->
 1624:     [];
 1625: caller(suite) ->
 1626:     [];
 1627: caller(Config) when is_list(Config) ->
 1628:     ?line run_caller_test(Config, false),
 1629:     ?line run_caller_test(Config, true).
 1630:     
 1631: run_caller_test(Config, Outputv) ->
 1632:     ?line Drv = 'caller_drv',
 1633:     ?line Cmd = case Outputv of
 1634: 		    true ->
 1635: 			?line os:putenv("CALLER_DRV_USE_OUTPUTV",
 1636: 					"true"),
 1637: 			outputv;
 1638: 		    false ->
 1639: 			?line os:putenv("CALLER_DRV_USE_OUTPUTV",
 1640: 					"false"),
 1641: 			output
 1642: 		end,
 1643:     ?line ok = load_driver(?config(data_dir, Config), Drv),
 1644:     ?line Port = open_port({spawn, Drv}, []),
 1645:     ?line true = is_port(Port),
 1646:     ?line chk_caller(Port, start, self()),
 1647:     ?line chk_caller(Port,
 1648: 		     Cmd,
 1649: 		     spawn_link(
 1650: 		       fun () ->
 1651: 			       port_command(Port, "")
 1652: 		       end)),
 1653:     ?line Port ! {self(), {command, ""}},
 1654:     ?line chk_caller(Port, Cmd, self()),
 1655:     ?line chk_caller(Port,
 1656: 		     control,
 1657: 		     spawn_link(
 1658: 		       fun () ->
 1659: 			       port_control(Port, 0, "")
 1660: 		       end)),
 1661:     ?line chk_caller(Port,
 1662: 		     call,
 1663: 		     spawn_link(
 1664: 		       fun () ->
 1665: 			       erlang:port_call(Port, 0, "")
 1666: 		       end)),
 1667:     ?line true = port_close(Port),
 1668:     ?line erl_ddll:unload_driver(Drv),
 1669:     ?line ok.
 1670: 
 1671: chk_caller(Port, Callback, ExpectedCaller) ->
 1672:     receive
 1673: 	{caller, Port, Callback, Caller} ->
 1674: 	    ExpectedCaller = Caller
 1675:     end.
 1676: 
 1677: many_events(suite) ->
 1678:     [];
 1679: many_events(doc) ->
 1680:     ["Check that many simultaneously signalled events work (win32)"];
 1681: many_events(Config) when is_list(Config) ->
 1682:     ?line Name = 'many_events_drv',
 1683:     ?line Port = start_driver(Config, Name, false),
 1684:     Number = "1000",
 1685:     Port ! {self(), {command, Number}},
 1686:     receive 
 1687: 	{Port, {data,Number}} ->
 1688: 	    ?line receive %% Just to make sure the emulator does not crash 
 1689: 		    %% after this case is run (if faulty)
 1690: 		      after 2000 ->
 1691: 			      ok
 1692: 		      end
 1693:     after 1000 ->
 1694: 	    ?line exit(the_driver_does_not_respond)
 1695:     end,
 1696:     ?line stop_driver(Port, Name),
 1697:     ?line ok.
 1698: 	     
 1699: 
 1700: missing_callbacks(doc) ->
 1701:     [];
 1702: missing_callbacks(suite) ->
 1703:     [];
 1704: missing_callbacks(Config) when is_list(Config) ->
 1705:     ?line Name = 'missing_callback_drv',
 1706:     ?line Port = start_driver(Config, Name, false),
 1707: 
 1708:     ?line Port ! {self(), {command, "tjenix"}},
 1709:     ?line true = erlang:port_command(Port, "halloj"),
 1710:     ?line {'EXIT', {badarg, _}} = (catch erlang:port_control(Port, 4711, "mors")),
 1711:     ?line {'EXIT', {badarg, _}} = (catch erlang:port_call(Port, 17, "hej")),
 1712: 
 1713:     ?line %% Give the (non-existing) ready_output(), ready_input(), event(),
 1714:     ?line %% and timeout() some time to be called.
 1715:     ?line receive after 1000 -> ok end,
 1716: 
 1717:     ?line stop_driver(Port, Name),
 1718:     ?line ok.
 1719: 
 1720: smp_select(doc) ->
 1721:     ["Test concurrent calls to driver_select."];
 1722: smp_select(suite) ->
 1723:     [];
 1724: smp_select(Config) when is_list(Config) -> 
 1725:     case os:type() of
 1726: 	{win32,_} -> {skipped, "Test not implemented for this OS"};
 1727: 	_ -> smp_select0(Config)
 1728:     end.
 1729:     
 1730: smp_select0(Config) ->
 1731:     ?line DrvName = 'chkio_drv',
 1732:     Path = ?config(data_dir, Config),
 1733:     erl_ddll:start(),
 1734:     ?line ok = load_driver(Path, DrvName),    
 1735:     Master = self(),
 1736:     ProcFun = fun()-> io:format("Worker ~p starting\n",[self()]),	
 1737: 		      ?line Port = open_port({spawn, DrvName}, []),
 1738: 		      smp_select_loop(Port, 100000),
 1739: 		      sleep(1000), % wait for driver to handle pending events
 1740: 		      ?line true = erlang:port_close(Port),
 1741: 		      Master ! {ok,self()},
 1742: 		      io:format("Worker ~p finished\n",[self()])
 1743: 	     end,
 1744:     ?line Pids = lists:map(fun(_) -> spawn_link(ProcFun) end,
 1745: 			   lists:seq(1,4)),
 1746:     TimeoutMsg = make_ref(),
 1747:     {ok,TRef} = timer:send_after(5*1000, TimeoutMsg), % Limit test duration on slow machines
 1748:     smp_select_wait(Pids, TimeoutMsg),
 1749:     timer:cancel(TRef),
 1750:     ?line ok = erl_ddll:unload_driver(DrvName),
 1751:     ?line ok = erl_ddll:stop(),
 1752:     ok.
 1753: 
 1754: smp_select_loop(_, 0) ->
 1755:     ok;
 1756: smp_select_loop(Port, N) ->
 1757:     ?line "ok" = erlang:port_control(Port, ?CHKIO_SMP_SELECT, []),
 1758:     receive
 1759: 	stop -> 
 1760: 	    io:format("Worker ~p stopped with ~p laps left\n",[self(), N]), 
 1761: 	    ok
 1762:     after 0 ->
 1763: 	smp_select_loop(Port, N-1)
 1764:     end.
 1765: 
 1766: smp_select_wait([], _) ->
 1767:     ok;
 1768: smp_select_wait(Pids, TimeoutMsg) ->
 1769:     receive
 1770: 	{ok,Pid} when is_pid(Pid) ->
 1771: 	    smp_select_wait(lists:delete(Pid,Pids), TimeoutMsg);
 1772: 	TimeoutMsg ->
 1773: 	    lists:foreach(fun(Pid)-> Pid ! stop end,
 1774: 			  Pids),
 1775: 	    smp_select_wait(Pids, TimeoutMsg)
 1776:     end.
 1777: 
 1778: 
 1779: driver_select_use(doc) ->
 1780:     ["Test driver_select() with new ERL_DRV_USE flag."];
 1781: driver_select_use(suite) ->
 1782:     [];
 1783: driver_select_use(Config) when is_list(Config) -> 
 1784:     case os:type() of
 1785: 	{win32,_} -> {skipped, "Test not implemented for this OS"};
 1786: 	_ -> driver_select_use0(Config)
 1787:     end.
 1788:     
 1789: driver_select_use0(Config) ->
 1790:     ?line DrvName = 'chkio_drv',
 1791:     Path = ?config(data_dir, Config),
 1792:     erl_ddll:start(),
 1793:     ?line ok = load_driver(Path, DrvName),    
 1794:     ?line Port = open_port({spawn, DrvName}, []),
 1795:     ?line "ok" = erlang:port_control(Port, ?CHKIO_DRV_USE, []),
 1796:     ?line {Port,{data,"TheEnd"}} = receive Msg -> Msg
 1797: 				   after 10000 -> timeout end,
 1798:     ?line true = erlang:port_close(Port),
 1799:     ?line ok = erl_ddll:unload_driver(DrvName),
 1800:     ?line ok = erl_ddll:stop(),
 1801:     ok.
 1802: 
 1803: thread_mseg_alloc_cache_clean(Config) when is_list(Config) ->
 1804:     case {erlang:system_info(threads),
 1805: 	  erlang:system_info({allocator,mseg_alloc}),
 1806: 	  driver_alloc_sbct()} of
 1807: 	{_, false, _} ->
 1808: 	    ?line {skipped, "No mseg_alloc"};
 1809: 	{false, _, _} ->
 1810: 	    ?line {skipped, "No threads"};
 1811: 	{_, _, false} ->
 1812: 	    ?line {skipped, "driver_alloc() not using the alloc_util framework"};
 1813: 	{_, _, SBCT} when is_integer(SBCT), SBCT > 10*1024*1024 ->
 1814: 	    ?line {skipped, "driver_alloc() using too large single block threshold"};
 1815: 	{_, _, 0} ->
 1816: 	    ?line {skipped, "driver_alloc() using too low single block threshold"};
 1817: 	{true, _MsegAllocInfo, SBCT} ->
 1818: 	    ?line DrvName = 'thr_alloc_drv',
 1819: 	    ?line Path = ?config(data_dir, Config),
 1820: 	    ?line erl_ddll:start(),
 1821: 	    ?line ok = load_driver(Path, DrvName),   
 1822: 	    ?line Port = open_port({spawn, DrvName}, []),
 1823: 	    ?line CCI = 1000,
 1824: 	    ?line ?t:format("CCI = ~p~n", [CCI]),
 1825: 	    ?line CCC = mseg_alloc_ccc(),
 1826: 	    ?line ?t:format("CCC = ~p~n", [CCC]),
 1827: 	    ?line thread_mseg_alloc_cache_clean_test(Port,
 1828: 						     10,
 1829: 						     CCI,
 1830: 						     SBCT+100),
 1831: 	    ?line true = erlang:port_close(Port),
 1832: 	    ?line ok = erl_ddll:unload_driver(DrvName),
 1833: 	    ?line ok = erl_ddll:stop(),
 1834: 	    ?line ok
 1835:     end.
 1836: 
 1837: mseg_alloc_cci(MsegAllocInfo) ->
 1838:     ?line {value,{options, OL}}
 1839: 	= lists:keysearch(options, 1, MsegAllocInfo),
 1840:     ?line {value,{cci,CCI}} = lists:keysearch(cci,1,OL),
 1841:     ?line CCI.
 1842: 
 1843: mseg_alloc_ccc() ->
 1844:     mseg_alloc_ccc(mseg_inst_info(0)).
 1845: 
 1846: mseg_alloc_ccc(MsegAllocInfo) ->
 1847:     ?line {value,{memkind, MKL}} = lists:keysearch(memkind,1,MsegAllocInfo),
 1848:     ?line {value,{calls, CL}} = lists:keysearch(calls, 1, MKL),
 1849:     ?line {value,{mseg_check_cache, GigaCCC, CCC}}
 1850: 	= lists:keysearch(mseg_check_cache, 1, CL),
 1851:     ?line GigaCCC*1000000000 + CCC.
 1852: 
 1853: mseg_alloc_cached_segments() ->
 1854:     mseg_alloc_cached_segments(mseg_inst_info(0)).
 1855: 
 1856: mseg_alloc_cached_segments(MsegAllocInfo) ->
 1857:     MemName = case is_halfword_vm() of
 1858: 	true -> "high memory";
 1859: 	false -> "all memory"
 1860:     end,
 1861:     ?line [{memkind,DrvMem}]
 1862: 	= lists:filter(fun(E) -> case E of
 1863: 				    {memkind, [{name, MemName} | _]} -> true;
 1864: 				    _ -> false
 1865: 		       end end, MsegAllocInfo),
 1866:     ?line {value,{status, SL}}
 1867: 	= lists:keysearch(status, 1, DrvMem),
 1868:     ?line {value,{cached_segments, CS}}
 1869: 	= lists:keysearch(cached_segments, 1, SL),
 1870:     ?line CS.
 1871: 
 1872: mseg_inst_info(I) ->
 1873:     {value, {instance, I, Value}}
 1874: 	= lists:keysearch(I,
 1875: 			  2,
 1876: 			  erlang:system_info({allocator,mseg_alloc})),
 1877:     Value.
 1878: 
 1879: is_halfword_vm() ->
 1880:     case {erlang:system_info({wordsize, internal}),
 1881: 	  erlang:system_info({wordsize, external})} of
 1882: 	{4, 8} -> true;
 1883: 	{WS, WS} -> false
 1884:     end.
 1885: 
 1886: driver_alloc_sbct() ->
 1887:     {_, _, _, As} = erlang:system_info(allocator),
 1888:     case lists:keysearch(driver_alloc, 1, As) of
 1889: 	{value,{driver_alloc,DAOPTs}} ->
 1890: 	    case lists:keysearch(sbct, 1, DAOPTs) of
 1891: 		{value,{sbct,SBCT}} ->
 1892: 		    SBCT;
 1893: 		_ ->
 1894: 		    false
 1895: 	    end;
 1896: 	_ ->
 1897: 	    false
 1898:     end.
 1899: 
 1900: thread_mseg_alloc_cache_clean_test(_Port, 0, _CCI, _Size) ->
 1901:     ?line ok;
 1902: thread_mseg_alloc_cache_clean_test(Port, N, CCI, Size) ->
 1903:     ?line wait_until(fun () -> 0 == mseg_alloc_cached_segments() end),
 1904:     ?line receive after CCI+500 -> ok end,
 1905:     ?line OCCC = mseg_alloc_ccc(),
 1906:     ?line "ok" = erlang:port_control(Port, 0, integer_to_list(Size)),
 1907:     ?line receive after CCI+500 -> ok end,
 1908:     ?line CCC = mseg_alloc_ccc(),
 1909:     ?line ?t:format("CCC = ~p~n", [CCC]),
 1910:     ?line true = CCC > OCCC,
 1911:     ?line thread_mseg_alloc_cache_clean_test(Port, N-1, CCI, Size).
 1912: 
 1913: otp_9302(Config) when is_list(Config) ->
 1914:     ?line Path = ?config(data_dir, Config),
 1915:     ?line erl_ddll:start(),
 1916:     ?line ok = load_driver(Path, otp_9302_drv),
 1917:     ?line Port = open_port({spawn, otp_9302_drv}, []),
 1918:     ?line true = is_port(Port),
 1919:     ?line port_command(Port, ""),
 1920:     ?line {msg, block} = get_port_msg(Port, infinity),
 1921:     ?line {msg, job} = get_port_msg(Port, infinity),
 1922:     ?line C = case erlang:system_info(thread_pool_size) of
 1923: 		  0 ->
 1924: 		      ?line {msg, cancel} = get_port_msg(Port, infinity),
 1925: 		      ?line {msg, job} = get_port_msg(Port, infinity),
 1926: 		      ?line false;
 1927: 		  _ ->
 1928: 		      case get_port_msg(Port, infinity) of
 1929: 			  {msg, cancel} -> %% Cancel always fail in Rel >= 15
 1930: 			      ?line {msg, job} = get_port_msg(Port, infinity),
 1931: 			      ?line false;
 1932: 			  {msg, job} ->
 1933: 			      ?line ok,
 1934: 			      ?line true
 1935: 		      end
 1936: 	      end,
 1937:     ?line {msg, end_of_jobs} = get_port_msg(Port, infinity),
 1938:     ?line no_msg = get_port_msg(Port, 2000),
 1939:     ?line port_close(Port),
 1940:     ?line case C of
 1941: 	      true ->
 1942: 		  ?line {comment, "Async job cancelled"};
 1943: 	      false ->
 1944: 		  ?line {comment, "Async job not cancelled"}
 1945: 	  end.
 1946: 
 1947: thr_free_drv(Config) when is_list(Config) ->
 1948:     ?line Path = ?config(data_dir, Config),
 1949:     ?line erl_ddll:start(),
 1950:     ?line ok = load_driver(Path, thr_free_drv),
 1951:     ?line MemBefore = driver_alloc_size(),
 1952: %    io:format("SID=~p", [erlang:system_info(scheduler_id)]),
 1953:     ?line Port = open_port({spawn, thr_free_drv}, []),
 1954:     ?line MemPeek = driver_alloc_size(),
 1955:     ?line true = is_port(Port),
 1956:     ?line ok = thr_free_drv_control(Port, 0),
 1957:     ?line port_close(Port),
 1958:     ?line MemAfter = driver_alloc_size(),
 1959:     ?line io:format("MemPeek=~p~n", [MemPeek]),
 1960:     ?line io:format("MemBefore=~p, MemAfter=~p~n", [MemBefore, MemAfter]),
 1961:     ?line MemBefore = MemAfter,
 1962:     ?line case MemPeek of
 1963: 	      undefined -> ok;
 1964: 	      _ ->
 1965: 		  ?line true = MemPeek > MemBefore
 1966: 	  end,
 1967:     ?line ok.
 1968: 
 1969: thr_free_drv_control(Port, N) ->
 1970:     case erlang:port_control(Port, 0, "") of
 1971: 	"done" ->
 1972: 	    ok;
 1973: 	"more" ->
 1974: 	    erlang:yield(),
 1975: %	    io:format("N=~p, SID=~p", [N, erlang:system_info(scheduler_id)]),
 1976: 	    thr_free_drv_control(Port, N+1)
 1977:     end.
 1978: 	    
 1979: async_blast(Config) when is_list(Config) ->
 1980:     ?line Path = ?config(data_dir, Config),
 1981:     ?line erl_ddll:start(),
 1982:     ?line ok = load_driver(Path, async_blast_drv),
 1983:     ?line SchedOnln = erlang:system_info(schedulers_online),
 1984:     ?line MemBefore = driver_alloc_size(),
 1985:     ?line Start = os:timestamp(),
 1986:     ?line Blast = fun () ->
 1987: 			  Port = open_port({spawn, async_blast_drv}, []),
 1988: 			  true = is_port(Port),
 1989: 			  port_command(Port, ""),
 1990: 			  receive
 1991: 			      {Port, done} ->
 1992: 				  ok
 1993: 			  end,
 1994: 			  port_close(Port)
 1995: 		  end,
 1996:     ?line Ps = lists:map(fun (N) ->
 1997: 				 spawn_opt(Blast,
 1998: 					   [{scheduler,
 1999: 					     (N rem SchedOnln)+ 1},
 2000: 					    monitor])
 2001: 			 end,
 2002: 			 lists:seq(1, 100)),
 2003:     ?line MemMid = driver_alloc_size(),
 2004:     ?line lists:foreach(fun ({Pid, Mon}) ->
 2005: 				receive
 2006: 				    {'DOWN',Mon,process,Pid,_} -> ok
 2007: 				end
 2008: 			end, Ps),
 2009:     ?line End = os:timestamp(),
 2010:     ?line MemAfter = driver_alloc_size(),
 2011:     ?line io:format("MemBefore=~p, MemMid=~p, MemAfter=~p~n",
 2012: 		    [MemBefore, MemMid, MemAfter]),
 2013:     ?line AsyncBlastTime = timer:now_diff(End,Start)/1000000,
 2014:     ?line io:format("AsyncBlastTime=~p~n", [AsyncBlastTime]),
 2015:     ?line MemBefore = MemAfter,
 2016:     ?line erlang:display({async_blast_time, AsyncBlastTime}),
 2017:     ?line ok.
 2018: 
 2019: thr_msg_blast_receiver(_Port, N, N) ->
 2020:     ok;
 2021: thr_msg_blast_receiver(Port, N, Max) ->
 2022:     receive
 2023: 	{Port, hi} ->
 2024: 	    thr_msg_blast_receiver(Port, N+1, Max)
 2025:     end.
 2026: 
 2027: thr_msg_blast_receiver_proc(Port, Max, Parent, Done) ->
 2028:     case port_control(Port, 0, "") of
 2029: 	"receiver" ->
 2030: 	    spawn(fun () ->
 2031: 			  thr_msg_blast_receiver_proc(Port, Max+1, Parent, Done)
 2032: 		  end),
 2033: 	    thr_msg_blast_receiver(Port, 0, Max);
 2034: 	"done" ->
 2035: 	    Parent ! Done
 2036:     end.
 2037: 
 2038: thr_msg_blast(Config) when is_list(Config) ->
 2039:     case erlang:system_info(smp_support) of
 2040: 	false ->
 2041: 	    {skipped, "Non-SMP emulator; nothing to test..."};
 2042: 	true ->
 2043: 	    Path = ?config(data_dir, Config),
 2044: 	    erl_ddll:start(),
 2045: 	    ok = load_driver(Path, thr_msg_blast_drv),
 2046: 	    MemBefore = driver_alloc_size(),
 2047: 	    Start = os:timestamp(),
 2048: 	    Port = open_port({spawn, thr_msg_blast_drv}, []),
 2049: 	    true = is_port(Port),
 2050: 	    Done = make_ref(),
 2051: 	    Me = self(),
 2052: 	    spawn(fun () ->
 2053: 			  thr_msg_blast_receiver_proc(Port, 1, Me, Done)
 2054: 		  end),
 2055: 	    receive
 2056: 		Done -> ok
 2057: 	    end,
 2058: 	    ok = thr_msg_blast_receiver(Port, 0, 32*10000),
 2059: 	    port_close(Port),
 2060: 	    End = os:timestamp(),
 2061: 	    receive
 2062: 		Garbage ->
 2063: 		    ?t:fail({received_garbage, Port, Garbage})
 2064: 	    after 2000 ->
 2065: 		    ok
 2066: 	    end,
 2067: 	    MemAfter = driver_alloc_size(),
 2068: 	    io:format("MemBefore=~p, MemAfter=~p~n",
 2069: 		      [MemBefore, MemAfter]),
 2070: 	    ThrMsgBlastTime = timer:now_diff(End,Start)/1000000,
 2071: 	    io:format("ThrMsgBlastTime=~p~n", [ThrMsgBlastTime]),
 2072: 	    MemBefore = MemAfter,
 2073: 	    Res = {thr_msg_blast_time, ThrMsgBlastTime},
 2074: 	    erlang:display(Res),
 2075: 	    Res
 2076:     end.
 2077: 
 2078: consume_timeslice(Config) when is_list(Config) ->
 2079:     %%
 2080:     %% Verify that erl_drv_consume_timeslice() works.
 2081:     %%
 2082:     %% The first four cases expect that the command signal is
 2083:     %% delivered immediately, i.e., isn't scheduled. Since there
 2084:     %% are no conflicts these signals should normally be delivered
 2085:     %% immediately. However some builds and configurations may
 2086:     %% schedule these ops anyway, in these cases we do not verify
 2087:     %% scheduling counts.
 2088:     %%
 2089:     %% When signal is delivered immediately we must take into account
 2090:     %% that process and port are "virtualy" scheduled out and in
 2091:     %% in the trace generated.
 2092:     %%
 2093:     %% Port ! {_, {command, _}, and port_command() differs. The send
 2094:     %% instruction needs to check if the caller is out of reductions
 2095:     %% at the end of the instruction, since no erlang function call
 2096:     %% is involved. Otherwise, a sequence of send instructions would
 2097:     %% not be scheduled out even when out of reductions. port_commond()
 2098:     %% doesn't do that since it will always (since R16A) be called via
 2099:     %% the erlang wrappers in the erlang module.
 2100:     %%
 2101:     %% The last two cases tests scheduled operations. We create
 2102:     %% a conflict by executing at the same time on different
 2103:     %% schedulers. When only one scheduler we enable parallelism on
 2104:     %% the port instead.
 2105:     %%
 2106: 
 2107:     Path = ?config(data_dir, Config),
 2108:     erl_ddll:start(),
 2109:     ok = load_driver(Path, consume_timeslice_drv),
 2110:     Port = open_port({spawn, consume_timeslice_drv}, [{parallelism, false}]),
 2111: 
 2112:     Parent = self(),
 2113:     Go = make_ref(),
 2114: 
 2115:     "enabled" = port_control(Port, $E, ""),
 2116:     Proc1 = spawn_link(fun () ->
 2117: 			       receive Go -> ok end,
 2118: 			       Port ! {Parent, {command, ""}},
 2119: 			       Port ! {Parent, {command, ""}},
 2120: 			       Port ! {Parent, {command, ""}},
 2121: 			       Port ! {Parent, {command, ""}},
 2122: 			       Port ! {Parent, {command, ""}},
 2123: 			       Port ! {Parent, {command, ""}},
 2124: 			       Port ! {Parent, {command, ""}},
 2125: 			       Port ! {Parent, {command, ""}},
 2126: 			       Port ! {Parent, {command, ""}},
 2127: 			       Port ! {Parent, {command, ""}}
 2128: 		       end),
 2129:     receive after 100 -> ok end,
 2130:     count_pp_sched_start(),
 2131:     Proc1 ! Go,
 2132:     wait_command_msgs(Port, 10),
 2133:     [{Port, Sprt1}, {Proc1, Sproc1}] = count_pp_sched_stop([Port, Proc1]),
 2134:     case Sprt1 of
 2135: 	10 ->
 2136: 	    true = in_range(5, Sproc1-10, 7);
 2137: 	_ ->
 2138: 	    case erlang:system_info(lock_checking) of
 2139: 		true -> ?t:format("Ignore bad sched count due to lock checking", []);
 2140: 		false -> ?t:fail({unexpected_sched_counts, Sprt1, Sproc1})
 2141: 	    end
 2142:     end,
 2143: 
 2144:     "disabled" = port_control(Port, $D, ""),
 2145:     Proc2 = spawn_link(fun () ->
 2146: 			       receive Go -> ok end,
 2147: 			       Port ! {Parent, {command, ""}},
 2148: 			       Port ! {Parent, {command, ""}},
 2149: 			       Port ! {Parent, {command, ""}},
 2150: 			       Port ! {Parent, {command, ""}},
 2151: 			       Port ! {Parent, {command, ""}},
 2152: 			       Port ! {Parent, {command, ""}},
 2153: 			       Port ! {Parent, {command, ""}},
 2154: 			       Port ! {Parent, {command, ""}},
 2155: 			       Port ! {Parent, {command, ""}},
 2156: 			       Port ! {Parent, {command, ""}}
 2157: 		       end),
 2158:     receive after 100 -> ok end,
 2159:     count_pp_sched_start(),
 2160:     Proc2 ! Go,
 2161:     wait_command_msgs(Port, 10),
 2162:     [{Port, Sprt2}, {Proc2, Sproc2}] = count_pp_sched_stop([Port, Proc2]),
 2163:     case Sprt2 of
 2164: 	10 ->
 2165: 	    true = in_range(1, Sproc2-10, 2);
 2166: 	_ ->
 2167: 	    case erlang:system_info(lock_checking) of
 2168: 		true -> ?t:format("Ignore bad sched count due to lock checking", []);
 2169: 		false -> ?t:fail({unexpected_sched_counts, Sprt2, Sproc2})
 2170: 	    end
 2171:     end,
 2172: 
 2173:     "enabled" = port_control(Port, $E, ""),
 2174:     Proc3 = spawn_link(fun () ->
 2175: 			       receive Go -> ok end,
 2176: 			       port_command(Port, ""),
 2177: 			       port_command(Port, ""),
 2178: 			       port_command(Port, ""),
 2179: 			       port_command(Port, ""),
 2180: 			       port_command(Port, ""),
 2181: 			       port_command(Port, ""),
 2182: 			       port_command(Port, ""),
 2183: 			       port_command(Port, ""),
 2184: 			       port_command(Port, ""),
 2185: 			       port_command(Port, "")
 2186: 		       end),
 2187:     count_pp_sched_start(),
 2188:     Proc3 ! Go,
 2189:     wait_command_msgs(Port, 10),
 2190:     [{Port, Sprt3}, {Proc3, Sproc3}] = count_pp_sched_stop([Port, Proc3]),
 2191:     case Sprt3 of
 2192: 	10 ->
 2193: 	    true = in_range(5, Sproc3-10, 7);
 2194: 	_ ->
 2195: 	    case erlang:system_info(lock_checking) of
 2196: 		true -> ?t:format("Ignore bad sched count due to lock checking", []);
 2197: 		false -> ?t:fail({unexpected_sched_counts, Sprt3, Sproc3})
 2198: 	    end
 2199:     end,
 2200: 
 2201:     "disabled" = port_control(Port, $D, ""),
 2202:     Proc4 = spawn_link(fun () ->
 2203: 			       receive Go -> ok end,
 2204: 			       port_command(Port, ""),
 2205: 			       port_command(Port, ""),
 2206: 			       port_command(Port, ""),
 2207: 			       port_command(Port, ""),
 2208: 			       port_command(Port, ""),
 2209: 			       port_command(Port, ""),
 2210: 			       port_command(Port, ""),
 2211: 			       port_command(Port, ""),
 2212: 			       port_command(Port, ""),
 2213: 			       port_command(Port, "")
 2214: 		       end),
 2215:     count_pp_sched_start(),
 2216:     Proc4 ! Go,
 2217:     wait_command_msgs(Port, 10),
 2218:     [{Port, Sprt4}, {Proc4, Sproc4}] = count_pp_sched_stop([Port, Proc4]),
 2219:     case Sprt4 of
 2220: 	10 ->
 2221: 	    true = in_range(1, Sproc4-10, 2);
 2222: 	_ ->
 2223: 	    case erlang:system_info(lock_checking) of
 2224: 		true -> ?t:format("Ignore bad sched count due to lock checking", []);
 2225: 		false -> ?t:fail({unexpected_sched_counts, Sprt4, Sproc4})
 2226: 	    end
 2227:     end,
 2228: 
 2229:     SOnl = erlang:system_info(schedulers_online),
 2230:     %% If only one scheduler use port with parallelism set to true,
 2231:     %% in order to trigger scheduling of command signals
 2232:     Port2 = case SOnl of
 2233: 		1 ->
 2234: 		    Port ! {self(), close},
 2235: 		    receive {Port, closed} -> ok end,
 2236: 		    open_port({spawn, consume_timeslice_drv},
 2237: 			      [{parallelism, true}]);
 2238: 		_ ->
 2239: 		    process_flag(scheduler, 1),
 2240: 		    1 = erlang:system_info(scheduler_id),
 2241: 		    Port
 2242: 	    end,
 2243:     count_pp_sched_start(),
 2244:     "enabled" = port_control(Port2, $E, ""),
 2245:     W5 = case SOnl of
 2246: 	     1 ->
 2247: 		 false;
 2248: 	     _ ->
 2249: 		 W1= spawn_opt(fun () ->
 2250: 				       2 = erlang:system_info(scheduler_id),
 2251: 				       "sleeped" = port_control(Port2, $S, "")
 2252: 			       end, [link,{scheduler,2}]),
 2253: 		 receive after 100 -> ok end,
 2254: 		 W1
 2255: 	 end,
 2256:     Proc5 = spawn_opt(fun () ->
 2257: 			      receive Go -> ok end,
 2258: 			      1 = erlang:system_info(scheduler_id),
 2259: 			      Port2 ! {Parent, {command, ""}},
 2260: 			      Port2 ! {Parent, {command, ""}},
 2261: 			      Port2 ! {Parent, {command, ""}},
 2262: 			      Port2 ! {Parent, {command, ""}},
 2263: 			      Port2 ! {Parent, {command, ""}},
 2264: 			      Port2 ! {Parent, {command, ""}},
 2265: 			      Port2 ! {Parent, {command, ""}},
 2266: 			      Port2 ! {Parent, {command, ""}},
 2267: 			      Port2 ! {Parent, {command, ""}},
 2268: 			      Port2 ! {Parent, {command, ""}}
 2269: 		      end, [link,{scheduler,1}]),
 2270:     receive after 100 -> ok end,
 2271:     Proc5 ! Go,
 2272:     wait_procs_exit([W5, Proc5]),
 2273:     wait_command_msgs(Port2, 10),
 2274:     [{Port2, Sprt5}, {Proc5, Sproc5}] = count_pp_sched_stop([Port2, Proc5]),
 2275:     true = in_range(2, Sproc5, 3),
 2276:     true = in_range(7, Sprt5, 20),
 2277: 		  
 2278:     count_pp_sched_start(),
 2279:     "disabled" = port_control(Port2, $D, ""),
 2280:     W6 = case SOnl of
 2281: 	     1 ->
 2282: 		 false;
 2283: 	     _ ->
 2284: 		 W2= spawn_opt(fun () ->
 2285: 				       2 = erlang:system_info(scheduler_id),
 2286: 				       "sleeped" = port_control(Port2, $S, "")
 2287: 			       end, [link,{scheduler,2}]),
 2288: 		 receive after 100 -> ok end,
 2289: 		 W2
 2290: 	 end,
 2291:     Proc6 = spawn_opt(fun () ->
 2292: 			      receive Go -> ok end,
 2293: 			      1 = erlang:system_info(scheduler_id),
 2294: 			      Port2 ! {Parent, {command, ""}},
 2295: 			      Port2 ! {Parent, {command, ""}},
 2296: 			      Port2 ! {Parent, {command, ""}},
 2297: 			      Port2 ! {Parent, {command, ""}},
 2298: 			      Port2 ! {Parent, {command, ""}},
 2299: 			      Port2 ! {Parent, {command, ""}},
 2300: 			      Port2 ! {Parent, {command, ""}},
 2301: 			      Port2 ! {Parent, {command, ""}},
 2302: 			      Port2 ! {Parent, {command, ""}},
 2303: 			      Port2 ! {Parent, {command, ""}}
 2304: 		      end, [link,{scheduler,1}]),
 2305:     receive after 100 -> ok end,
 2306:     Proc6 ! Go,
 2307:     wait_procs_exit([W6, Proc6]),
 2308:     wait_command_msgs(Port2, 10),
 2309:     [{Port2, Sprt6}, {Proc6, Sproc6}] = count_pp_sched_stop([Port2, Proc6]),
 2310:     true = in_range(2, Sproc6, 3),
 2311:     true = in_range(3, Sprt6, 6),
 2312: 
 2313:     process_flag(scheduler, 0),
 2314: 
 2315:     Port2 ! {self(), close},
 2316:     receive {Port2, closed} -> ok end,
 2317:     ok.
 2318: 
 2319: wait_command_msgs(_, 0) ->
 2320:     ok;
 2321: wait_command_msgs(Port, N) ->
 2322:     receive
 2323: 	{Port, command} ->
 2324: 	    wait_command_msgs(Port, N-1)
 2325:     end.
 2326: 
 2327: in_range(Low, Val, High) when is_integer(Low),
 2328: 			      is_integer(Val),
 2329: 			      is_integer(High),
 2330: 			      Low =< Val,
 2331: 			      Val =< High ->
 2332:     true;
 2333: in_range(Low, Val, High) when is_integer(Low),
 2334: 			      is_integer(Val),
 2335: 			      is_integer(High) ->
 2336:     false.
 2337: 
 2338: count_pp_sched_start() ->
 2339:     erlang:trace(all, true, [running_procs, running_ports, {tracer, self()}]),
 2340:     ok.
 2341: 
 2342: count_pp_sched_stop(Ps) ->
 2343:     Td = erlang:trace_delivered(all),
 2344:     erlang:trace(all, false, [running_procs, running_ports, {tracer, self()}]),
 2345:     PNs = lists:map(fun (P) -> {P, 0} end, Ps),
 2346:     receive {trace_delivered, all, Td} -> ok end,
 2347:     Res = count_proc_sched(Ps, PNs),
 2348:     ?t:format("Scheduling counts: ~p~n", [Res]),
 2349:     erlang:display({scheduling_counts, Res}),
 2350:     Res.
 2351: 
 2352: do_inc_pn(_P, []) ->
 2353:     throw(undefined);
 2354: do_inc_pn(P, [{P,N}|PNs]) ->
 2355:     [{P,N+1}|PNs];
 2356: do_inc_pn(P, [PN|PNs]) ->
 2357:     [PN|do_inc_pn(P, PNs)].
 2358: 
 2359: inc_pn(P, PNs) ->
 2360:     try
 2361: 	do_inc_pn(P, PNs)
 2362:     catch
 2363: 	throw:undefined -> PNs
 2364:     end.
 2365: 
 2366: count_proc_sched(Ps, PNs) ->
 2367:     receive
 2368: 	TT when element(1, TT) == trace, element(3, TT) == in ->
 2369: %	    erlang:display(TT),
 2370: 	    count_proc_sched(Ps, inc_pn(element(2, TT), PNs));
 2371: 	TT when element(1, TT) == trace, element(3, TT) == out ->
 2372: 	    count_proc_sched(Ps, PNs)
 2373:     after 0 ->
 2374: 	    PNs
 2375:     end.
 2376:     
 2377: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 2378: %% 		Utilities
 2379: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 2380: 
 2381: %flush_msgs() ->
 2382: %    receive
 2383: %	M ->
 2384: %	    erlang:display(M),
 2385: %	    flush_msgs()
 2386: %    after 0 ->
 2387: %	    ok
 2388: %    end.
 2389: 
 2390: wait_procs_exit([]) ->
 2391:     ok;
 2392: wait_procs_exit([P|Ps]) when is_pid(P) ->
 2393:     Mon = erlang:monitor(process, P),
 2394:     receive
 2395: 	{'DOWN', Mon, process, P, _} ->
 2396: 	    wait_procs_exit(Ps)
 2397:     end;
 2398: wait_procs_exit([_|Ps]) ->
 2399:     wait_procs_exit(Ps).
 2400: 
 2401: get_port_msg(Port, Timeout) ->
 2402:     receive
 2403: 	{Port, What} ->
 2404: 	    {msg, What}
 2405:     after Timeout ->
 2406: 	    no_msg
 2407:     end.
 2408: 
 2409: wait_until(Fun) ->
 2410:     case Fun() of
 2411: 	true -> ok;
 2412: 	false ->
 2413: 	    receive after 100 -> ok end,
 2414: 	    wait_until(Fun)
 2415:     end.
 2416: 
 2417: drv_vsn_str2tup(Str) ->
 2418:     [Major, Minor] = string:tokens(Str, "."),
 2419:     {list_to_integer(Major), list_to_integer(Minor)}.
 2420: 
 2421: %% Build port data from a template.
 2422: 
 2423: build_data({bin,Size})  -> build_binary(Size);
 2424: build_data({list,Size}) -> build_list(Size);
 2425: build_data(int) -> random_char();
 2426: build_data([])  -> [];
 2427: build_data([H|T]) -> [build_data(H)|build_data(T)].
 2428: 
 2429: %% Transform all binaries in a term.
 2430: 
 2431: transform_bins(_Transform, []) -> [];
 2432: transform_bins(Transform, [H|T]) ->
 2433:     [transform_bins(Transform, H)|transform_bins(Transform, T)];
 2434: transform_bins(Transform, Tuple) when is_tuple(Tuple) ->
 2435:     list_to_tuple([transform_bins(Transform, E) || E <- tuple_to_list(Tuple)]);
 2436: transform_bins(Transform, Bin) when is_binary(Bin) ->
 2437:     Transform(Bin);
 2438: transform_bins(_Transform, Other) -> Other.
 2439: 
 2440: 
 2441: %% Convert all binaries in a term to sub binaries.
 2442: 
 2443: make_sub_binaries(Term) ->
 2444:     MakeSub = fun(Bin0) ->
 2445: 		      Bin1 = <<243:8,0:3,Bin0/binary,31:5,19:8>>,
 2446: 		      Sz = size(Bin0),
 2447: 		      <<243:8,0:3,Bin:Sz/binary,31:5,19:8>> = id(Bin1),
 2448: 		      Bin
 2449: 	      end,
 2450:     transform_bins(MakeSub, Term).
 2451: 
 2452: id(I) -> I.
 2453: 
 2454: %% Convert all binaries in a term to refc binaries.
 2455: 
 2456: make_refc_binaries(Term) ->
 2457:     F = fun(B0) -> list_to_binary([build_binary(?heap_binary_size+1),B0]) end,
 2458:     transform_bins(F, Term).
 2459: 
 2460: build_binary(Elements) ->
 2461:     list_to_binary(build_list(Elements)).
 2462: 
 2463: build_list(Elements) -> build_list(Elements, []).
 2464: 
 2465: build_list(0, Acc) -> Acc;
 2466: build_list(Elements, Acc) -> build_list(Elements-1, [random_char()|Acc]).
 2467: 
 2468: 
 2469: %% Convert all binaries in a list to writable binaries.
 2470: 
 2471: make_writable_binaries(Term) ->
 2472:     transform_bins(fun(Bin) -> <<Bin/binary,1,2,3>> end, Term).
 2473: 
 2474: append_to_writable_binaries(Term) ->
 2475:     transform_bins(fun(Bin) -> <<Bin/binary,0:(64*1024*8)>> end, Term).
 2476: 
 2477: random_char() ->
 2478:     uniform(256) - 1.
 2479: 
 2480: uniform(N) ->
 2481:     case get(random_seed) of
 2482: 	undefined ->
 2483: 	    {X, Y, Z} = time(),
 2484: 	    random:seed(X, Y, Z);
 2485: 	_ ->
 2486: 	    ok
 2487:     end,
 2488:     random:uniform(N).
 2489: 
 2490: %% return millisecs from statistics source
 2491: erl_millisecs() ->
 2492:     {Ms, S, Us} = erlang:now(),
 2493:     Ms * 1000000000 + S * 1000 + Us / 1000.
 2494: 
 2495: erl_millisecs({Ms,S,Us}) ->
 2496:     Ms * 1000000000 + S * 1000 + Us / 1000.
 2497: 
 2498: %% Start/stop drivers.
 2499: start_driver(Config, Name, Binary) ->
 2500:     Path = ?config(data_dir, Config),
 2501:     erl_ddll:start(),
 2502: 
 2503:     %% Load the driver
 2504:     ok = load_driver(Path, Name),
 2505: 
 2506:     %% open port.
 2507:     case Binary of
 2508: 	true ->
 2509: 	    open_port({spawn, Name}, [binary]);
 2510: 	false ->
 2511: 	    open_port({spawn, Name}, [])
 2512:     end.
 2513: 
 2514: stop_driver(Port, Name) ->
 2515:     ?line true = erlang:port_close(Port),
 2516:     receive
 2517: 	{Port,Message} ->
 2518: 	    ?t:fail({strange_message_from_port,Message})
 2519:     after 0 ->
 2520: 	    ok
 2521:     end,
 2522: 
 2523:     %% Unload the driver.
 2524:     ok = erl_ddll:unload_driver(Name),
 2525:     ?line ok = erl_ddll:stop().
 2526: 
 2527: load_driver(Dir, Driver) ->
 2528:     case erl_ddll:load_driver(Dir, Driver) of
 2529: 	ok -> ok;
 2530: 	{error, Error} = Res ->
 2531: 	    io:format("~s\n", [erl_ddll:format_error(Error)]),
 2532: 	    Res
 2533:     end.
 2534: 
 2535: sleep() ->
 2536:     receive after infinity -> ok end.
 2537: 
 2538: sleep(infinity) ->
 2539:     sleep();
 2540: sleep(Ms) when is_integer(Ms), Ms >= 0 ->
 2541:     receive after Ms -> ok end.
 2542: 
 2543: 
 2544: start_node(Config) when is_list(Config) ->
 2545:     ?line Pa = filename:dirname(code:which(?MODULE)),
 2546:     ?line {A, B, C} = now(),
 2547:     ?line Name = list_to_atom(atom_to_list(?MODULE)
 2548: 			      ++ "-"
 2549: 			      ++ atom_to_list(?config(testcase, Config))
 2550: 			      ++ "-"
 2551: 			      ++ integer_to_list(A)
 2552: 			      ++ "-"
 2553: 			      ++ integer_to_list(B)
 2554: 			      ++ "-"
 2555: 			      ++ integer_to_list(C)),
 2556:     ?line ?t:start_node(Name, slave, [{args, "-pa "++Pa}]).
 2557: 
 2558: stop_node(Node) ->
 2559:     ?t:stop_node(Node).
 2560: 
 2561: wait_deallocations() ->
 2562:     try
 2563: 	erts_debug:set_internal_state(wait, deallocations)
 2564:     catch error:undef ->
 2565: 	    erts_debug:set_internal_state(available_internal_state, true),
 2566: 	    wait_deallocations()
 2567:     end.
 2568: 
 2569: driver_alloc_size() ->
 2570:     case erlang:system_info(smp_support) of
 2571: 	true ->
 2572: 	    ok;
 2573: 	false ->
 2574: 	    %% driver_alloc also used by elements in lock-free queues,
 2575: 	    %% give these some time to be deallocated...
 2576: 	    receive after 100 -> ok end
 2577:     end,
 2578:     wait_deallocations(),
 2579:     case erlang:system_info({allocator_sizes, driver_alloc}) of
 2580: 	false ->
 2581: 	    undefined;
 2582: 	MemInfo ->
 2583: 	    CS = lists:foldl(
 2584: 		   fun ({instance, _, L}, Acc) ->
 2585: 			   {value,{_,MBCS}} = lists:keysearch(mbcs, 1, L),
 2586: 			   {value,{_,SBCS}} = lists:keysearch(sbcs, 1, L),
 2587: 			   [MBCS,SBCS | Acc]
 2588: 		   end,
 2589: 		   [],
 2590: 		   MemInfo),
 2591: 	    lists:foldl(
 2592: 	      fun(L, Sz0) ->
 2593: 		      {value,{_,Sz,_,_}} = lists:keysearch(blocks_size, 1, L),
 2594: 		      Sz0+Sz
 2595: 	      end, 0, CS)
 2596:     end.