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: 
   20: -module(ddll_SUITE).
   21: 
   22: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   23: %%% Checks if the dynamic driver and linker loader works.
   24: %%%
   25: %%% These tests can only be run installed (outside clearcase).
   26: %%%
   27: %%% XXX In this suite is missing test cases for reference counts
   28: %%% and that drivers are unloaded when their processes die.
   29: %%% (For me to add :-)
   30: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
   31: 
   32: 
   33: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 
   34: 	 init_per_group/2,end_per_group/2, ddll_test/1, errors/1,
   35: 	 reference_count/1,
   36: 	 kill_port/1, dont_kill_port/1]).
   37: -export([unload_on_process_exit/1, delayed_unload_with_ports/1, 
   38: 	 unload_due_to_process_exit/1,
   39: 	 no_unload_due_to_process_exit/1, no_unload_due_to_process_exit_2/1,
   40: 	 unload_reload_thingie/1, unload_reload_thingie_2/1,
   41: 	 unload_reload_thingie_3/1, reload_pending/1, reload_pending_kill/1,
   42: 	 load_fail_init/1,
   43: 	 reload_pending_fail_init/1,
   44: 	 more_error_codes/1, forced_port_killing/1, 
   45: 	 no_trap_exit_and_kill_ports/1,
   46: 	 monitor_demonitor/1, monitor_demonitor_load/1, new_interface/1, 
   47: 	 lock_driver/1]).
   48: 
   49: % Private exports
   50: -export([echo_loader/2, nice_echo_loader/2 ,properties/1, load_and_unload/1]).
   51: 
   52: -import(ordsets, [subtract/2]).
   53: 
   54: -include_lib("test_server/include/test_server.hrl").
   55: 
   56: suite() -> [{ct_hooks,[ts_install_cth]}].
   57: 
   58: all() -> 
   59:     [ddll_test, errors, reference_count, kill_port,
   60:      dont_kill_port, properties, load_and_unload,
   61:      unload_on_process_exit, delayed_unload_with_ports,
   62:      unload_due_to_process_exit,
   63:      no_unload_due_to_process_exit,
   64:      no_unload_due_to_process_exit_2, unload_reload_thingie,
   65:      unload_reload_thingie_2, unload_reload_thingie_3,
   66:      reload_pending, load_fail_init,
   67:      reload_pending_fail_init, reload_pending_kill,
   68:      more_error_codes, forced_port_killing,
   69:      no_trap_exit_and_kill_ports, monitor_demonitor,
   70:      monitor_demonitor_load, new_interface, lock_driver].
   71: 
   72: groups() -> 
   73:     [].
   74: 
   75: init_per_suite(Config) ->
   76:     Config.
   77: 
   78: end_per_suite(_Config) ->
   79:     ok.
   80: 
   81: init_per_group(_GroupName, Config) ->
   82:     Config.
   83: 
   84: end_per_group(_GroupName, Config) ->
   85:     Config.
   86: 
   87: 
   88: unload_on_process_exit(suite) ->
   89:     [];
   90: unload_on_process_exit(doc) ->
   91:     ["Check that the driver is unloaded on process exit"];
   92: unload_on_process_exit(Config) when is_list(Config) ->
   93:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
   94:     ?line Path = ?config(data_dir, Config),
   95:     ?line false = lists:member("echo_drv",element(2,erl_ddll:loaded_drivers())),
   96:     Parent = self(),
   97:     ?line Pid = spawn(fun() ->
   98: 			      receive go -> ok end,
   99: 			      erl_ddll:try_load(Path, echo_drv, []),
  100: 			      Parent ! gone,
  101: 			      receive go -> ok end,
  102: 			      erl_ddll:loaded_drivers(),
  103: 			      exit(banan)
  104: 		      end),
  105:     ?line Ref = erlang:monitor(process,Pid),
  106:     ?line false = lists:member("echo_drv",element(2,erl_ddll:loaded_drivers())),
  107:     Pid ! go,
  108:     ?line receive
  109: 	gone -> ok
  110:     end,
  111:     ?line true = lists:member("echo_drv",element(2,erl_ddll:loaded_drivers())),
  112:     Pid ! go,
  113:     ?line receive
  114: 	{'DOWN', Ref, process, Pid, banan} ->
  115: 	    ok
  116:     end,
  117:     receive after 500 -> ok end,
  118:     ?line false = lists:member("echo_drv",element(2,erl_ddll:loaded_drivers())),
  119:     ?line test_server:timetrap_cancel(Dog),
  120:     ok.
  121: 
  122: delayed_unload_with_ports(suite) ->
  123:     [];
  124: delayed_unload_with_ports(doc) ->
  125:     ["Check that the driver is unloaded when the last port is closed"];
  126: delayed_unload_with_ports(Config) when is_list(Config) ->
  127:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  128:     ?line Path = ?config(data_dir, Config),
  129:     ?line erl_ddll:try_load(Path, echo_drv, []),
  130:     ?line erl_ddll:try_load(Path, echo_drv, []),
  131:     ?line Port = open_port({spawn, echo_drv}, [eof]),
  132:     ?line 1 = erl_ddll:info(echo_drv, port_count),
  133:     ?line Port2 = open_port({spawn, echo_drv}, [eof]),
  134:     ?line 2 = erl_ddll:info(echo_drv, port_count),
  135:     ?line {ok,pending_process} = erl_ddll:try_unload(echo_drv,[{monitor, pending_driver}]),
  136:     ?line {ok,pending_driver,Ref} = erl_ddll:try_unload(echo_drv,[{monitor, pending_driver}]),
  137:     ?line ok = receive _ -> false after 0 -> ok end,
  138:     ?line Port ! {self(), close},
  139:     ?line ok = receive {Port,closed} -> ok after 1000 -> false end,
  140:     ?line 1 = erl_ddll:info(echo_drv, port_count),
  141:     ?line Port2 ! {self(), close},
  142:     ?line ok = receive {Port2,closed} -> ok after 1000 -> false end,
  143:     ?line ok = receive {'DOWN', Ref, driver, echo_drv, unloaded} -> ok after 1000 -> false end,
  144:     ?line test_server:timetrap_cancel(Dog),
  145:     ok.
  146: 
  147: unload_due_to_process_exit(suite) ->
  148:     [];
  149: unload_due_to_process_exit(doc) ->
  150:     ["Check that the driver with ports is unloaded on process exit"];
  151: unload_due_to_process_exit(Config) when is_list(Config) ->
  152:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  153:     ?line Path = ?config(data_dir, Config),
  154:     ?line Parent = self(),
  155:     ?line F3 = fun() -> 
  156: 		       Parent ! erl_ddll:monitor(driver,{echo_drv,unloaded}), 
  157: 		       receive X -> Parent ! {got,X} end 
  158: 	       end,
  159:     ?line Pid = spawn(fun() ->
  160: 			      receive go -> ok end,
  161: 			      {ok, loaded} = erl_ddll:try_load(Path, echo_drv, []),
  162: 			      spawn(F3),
  163: 			      receive go -> ok end,
  164: 			      _Port = open_port({spawn, echo_drv}, [eof]),
  165: 			      _Port2 = open_port({spawn, echo_drv}, [eof]),
  166: 			      exit(banan)
  167: 		      end),
  168:     ?line Ref = erlang:monitor(process,Pid),
  169:     Pid ! go,
  170:     ?line {ok,Ref2} = receive 
  171: 			  R when is_reference(R) -> {ok,R}; 
  172: 			  Other -> {error, Other} 
  173: 		      after 500 -> {error, timeout} 
  174: 		      end,
  175:     Pid ! go,
  176:     ?line ok = receive {'DOWN', Ref, process, Pid, banan} -> ok after 300 -> error end,
  177:     ?line ok = receive {got,{'DOWN', Ref2, driver, echo_drv, unloaded}} -> ok after 300 -> error end,
  178:     ?line test_server:timetrap_cancel(Dog),
  179:     ok.
  180: 
  181: no_unload_due_to_process_exit(suite) ->
  182:     [];
  183: no_unload_due_to_process_exit(doc) ->
  184:     ["Check that a driver with driver loaded in another process is not unloaded on process exit"];
  185: no_unload_due_to_process_exit(Config) when is_list(Config) ->
  186:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  187:     ?line Path = ?config(data_dir, Config),
  188:     ?line Parent = self(),
  189:     ?line F3 = fun() -> 
  190: 		       Parent ! erl_ddll:monitor(driver,{echo_drv,unloaded}), 
  191: 		       receive X -> Parent ! {got,X} end 
  192: 	       end,
  193:     ?line Pid = spawn(fun() ->
  194: 			      receive go -> ok end,
  195: 			      {ok, loaded} = erl_ddll:try_load(Path, echo_drv, []),
  196: 			      spawn(F3),
  197: 			      receive go -> ok end,
  198: 			      _Port = open_port({spawn, echo_drv}, [eof]),
  199: 			      _Port2 = open_port({spawn, echo_drv}, [eof]),
  200: 			      exit(banan)
  201: 		      end),
  202:     ?line Ref = erlang:monitor(process,Pid),
  203:     Pid ! go,
  204:     ?line {ok,Ref2} = receive 
  205: 			  R when is_reference(R) -> {ok,R}; 
  206: 			  Other -> {error, Other} 
  207: 		      after 500 -> {error, timeout} 
  208: 		      end,
  209:     ?line {ok, already_loaded} = erl_ddll:try_load(Path, echo_drv, []),
  210:     Pid ! go,
  211:     ?line ok = receive {'DOWN', Ref, process, Pid, banan} -> ok after 300 -> error end,
  212:     ?line ok = receive X -> {error, X} after 300 -> ok end,
  213:     ?line ok = unload_expect_fast(echo_drv,[]),
  214:     ?line ok = receive {got,{'DOWN', Ref2, driver, echo_drv, unloaded}} -> ok after 300 -> error end,
  215:     ?line test_server:timetrap_cancel(Dog),
  216:     ok.
  217: 
  218: no_unload_due_to_process_exit_2(suite) ->
  219:     [];
  220: no_unload_due_to_process_exit_2(doc) ->
  221:     ["Check that a driver with open ports in another process is not unloaded on process exit"];
  222: no_unload_due_to_process_exit_2(Config) when is_list(Config) ->
  223:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  224:     ?line Path = ?config(data_dir, Config),
  225:     ?line Parent = self(),
  226:     ?line F3 = fun() -> 
  227: 		       Parent ! erl_ddll:monitor(driver,{echo_drv,unloaded}), 
  228: 		       receive X -> Parent ! {got,X} end 
  229: 	       end,
  230:     ?line Pid = spawn(fun() ->
  231: 			      receive go -> ok end,
  232: 			      {ok, loaded} = erl_ddll:try_load(Path, echo_drv, []),
  233: 			      spawn(F3),
  234: 			      receive go -> ok end,
  235: 			      _Port = open_port({spawn, echo_drv}, [eof]),
  236: 			      _Port2 = open_port({spawn, echo_drv}, [eof]),
  237: 			      exit(banan)
  238: 		      end),
  239:     ?line Ref = erlang:monitor(process,Pid),
  240:     Pid ! go,
  241:     ?line {ok,Ref2} = receive 
  242: 			  R when is_reference(R) -> {ok,R}; 
  243: 			  Other -> {error, Other} 
  244: 		      after 500 -> {error, timeout} 
  245: 		      end,
  246:     ?line Port = open_port({spawn, echo_drv}, [eof]),
  247:     Pid ! go,
  248:     ?line ok = receive {'DOWN', Ref, process, Pid, banan} -> ok after 300 -> error end,
  249:     ?line ok = receive X -> {error, X} after 300 -> ok end,
  250:     ?line erlang:port_close(Port),
  251:     ?line ok = receive {got,{'DOWN', Ref2, driver, echo_drv, unloaded}} -> ok after 300 -> error end,
  252:     ?line test_server:timetrap_cancel(Dog),
  253:     ok.
  254: 
  255: unload_reload_thingie(suite) ->
  256:     [];
  257: unload_reload_thingie(doc) ->
  258:     ["Check delayed unload and reload"];
  259: unload_reload_thingie(Config) when is_list(Config) ->
  260:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  261:     ?line Path = ?config(data_dir, Config),
  262:     ?line Parent = self(),
  263:     ?line {ok, loaded} = erl_ddll:try_load(Path, echo_drv, []),
  264:     ?line F3 = fun() -> 
  265: 		       Parent ! erl_ddll:monitor(driver,{echo_drv,unloaded_only}), 
  266: 		       receive X -> Parent ! {got,X} end 
  267: 	       end,
  268:     ?line Pid = spawn(fun() ->
  269: 			      receive go -> ok end,
  270: 			      _Port = open_port({spawn, echo_drv}, [eof]),
  271: 			      spawn(F3),
  272: 			      receive go -> ok end,
  273: 			      exit(banan)
  274: 		      end),
  275:     ?line Ref = erlang:monitor(process,Pid),
  276:     Pid ! go,
  277:     ?line {ok,Ref2} = receive 
  278: 			  R when is_reference(R) -> {ok,R}; 
  279: 			  Other -> {error, Other} 
  280: 		      after 500 -> {error, timeout} 
  281: 		      end,
  282:     ?line {ok,pending_driver,Ref3} = erl_ddll:try_unload(echo_drv,[{monitor,pending}]),
  283:     ?line Ref4 = erl_ddll:monitor(driver,{echo_drv,loaded}),
  284:     ?line ok = receive {'DOWN',Ref4, driver,echo_drv,load_cancelled} -> ok after 1000 -> false end,
  285:     ?line {ok,already_loaded} = erl_ddll:try_load(Path, echo_drv, []),
  286:     ?line ok = receive {'UP',Ref3, driver,echo_drv,unload_cancelled} -> ok after 1000 -> false end,
  287:     ?line Pid ! go,
  288:     ?line ok = receive {'DOWN', Ref, process, Pid, banan} -> ok after 300 -> error end,
  289:     ?line [{Parent,1}] = erl_ddll:info(echo_drv, processes),
  290:     ?line 0 = erl_ddll:info(echo_drv, port_count),
  291:     ?line ok = unload_expect_fast(echo_drv,[{monitor,pending}]),
  292:     ?line ok = receive 
  293: 		   {got,{'DOWN', Ref2, driver, echo_drv, unloaded}} -> ok 
  294: 	       after 300 -> error 
  295: 	       end,
  296:     ?line ok = receive X -> {error, X} after 300 -> ok end,
  297:     ?line test_server:timetrap_cancel(Dog),
  298:     ok.
  299: 
  300: unload_reload_thingie_2(suite) ->
  301:     [];
  302: unload_reload_thingie_2(doc) ->
  303:     ["Check delayed unload and reload"];
  304: unload_reload_thingie_2(Config) when is_list(Config) ->
  305:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  306:     ?line Path = ?config(data_dir, Config),
  307:     ?line Parent = self(),
  308:     ?line {ok, loaded} = erl_ddll:try_load(Path, echo_drv, []),
  309:     ?line F3 = fun() -> 
  310: 		       Parent ! erl_ddll:monitor(driver,{echo_drv,unloaded_only}), 
  311: 		       receive X -> Parent ! {got,X} end 
  312: 	       end,
  313:     ?line Pid = spawn(fun() ->
  314: 			      receive go -> ok end,
  315: 			      _Port = open_port({spawn, echo_drv}, [eof]),
  316: 			      spawn(F3),
  317: 			      receive go -> ok end,
  318: 			      exit(banan)
  319: 		      end),
  320:     ?line Ref = erlang:monitor(process,Pid),
  321:     Pid ! go,
  322:     ?line {ok,Ref2} = receive 
  323: 			  R when is_reference(R) -> {ok,R}; 
  324: 			  Other -> {error, Other} 
  325: 		      after 500 -> {error, timeout} 
  326: 		      end,
  327:     ?line {ok,pending_driver,Ref3} = erl_ddll:try_load(Path,echo_drv,[{monitor,pending_driver},{reload,pending_driver}]),
  328:     ?line Ref4 = erl_ddll:monitor(driver,{echo_drv,unloaded}),
  329:     ?line Pid ! go,
  330:     ?line ok = receive {'DOWN', Ref, process, Pid, banan} -> ok after 300 -> error end,
  331:     ?line ok = receive {'DOWN',Ref4, driver,echo_drv,unloaded} -> ok after 1000 -> false end,
  332:     ?line ok = receive {'UP',Ref3, driver,echo_drv,loaded} -> ok after 1000 -> false end,
  333:     ?line [{Parent,1}] = erl_ddll:info(echo_drv, processes),
  334:     ?line 0 = erl_ddll:info(echo_drv, port_count),
  335:     ?line ok = receive 
  336: 		   {got,{'DOWN', Ref2, driver, echo_drv, unloaded}} -> ok 
  337: 	       after 300 -> error 
  338: 	       end,
  339:     ?line ok = unload_expect_fast(echo_drv,[{monitor,pending}]),
  340:     ?line ok = receive X -> {error, X} after 300 -> ok end,
  341:     ?line test_server:timetrap_cancel(Dog),
  342:     ok.
  343: 
  344: unload_reload_thingie_3(suite) ->
  345:     [];
  346: unload_reload_thingie_3(doc) ->
  347:     ["Check delayed unload and reload failure"];
  348: unload_reload_thingie_3(Config) when is_list(Config) ->
  349:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  350:     ?line Path = ?config(data_dir, Config),
  351:     ?line Parent = self(),
  352:     ?line {ok, loaded} = erl_ddll:try_load(Path, echo_drv, []),
  353:     ?line F3 = fun() -> 
  354: 		       Parent ! erl_ddll:monitor(driver,{echo_drv,unloaded}), 
  355: 		       receive X -> Parent ! {got,X} end 
  356: 	       end,
  357:     ?line Pid = spawn(fun() ->
  358: 			      receive go -> ok end,
  359: 			      _Port = open_port({spawn, echo_drv}, [eof]),
  360: 			      spawn(F3),
  361: 			      receive go -> ok end,
  362: 			      exit(banan)
  363: 		      end),
  364:     ?line Ref = erlang:monitor(process,Pid),
  365:     Pid ! go,
  366:     ?line {ok,Ref2} = receive 
  367: 			  R when is_reference(R) -> {ok,R}; 
  368: 			  Other -> {error, Other} 
  369: 		      after 500 -> {error, timeout} 
  370: 		      end,
  371:     ?line {ok,pending_driver,Ref3} = erl_ddll:try_load(filename:join([Path,"skrumpf"]),echo_drv,[{monitor,pending_driver},{reload,pending_driver}]),
  372:     ?line Ref4 = erl_ddll:monitor(driver,{echo_drv,unloaded}),
  373:     ?line Pid ! go,
  374:     ?line ok = receive {'DOWN', Ref, process, Pid, banan} -> ok after 300 -> error end,
  375:     ?line ok = receive 
  376: 		   {got,{'DOWN', Ref2, driver, echo_drv, unloaded}} -> ok 
  377: 	       after 300 -> error 
  378: 	       end,
  379:     ?line ok = receive {'DOWN',Ref4,driver,echo_drv,unloaded} -> ok after 300 -> false end,
  380:     ?line ok = receive 
  381: 		   {'DOWN',Ref3, driver,echo_drv,{load_failure,_}} -> ok 
  382: 	       after 1000 -> false 
  383: 	       end,
  384:     ?line {'EXIT',_} = (catch erl_ddll:info(echo_drv, port_count)),
  385:     ?line {error, not_loaded} = erl_ddll:try_unload(echo_drv,[{monitor,pending}]),
  386:     ?line ok = receive X -> {error, X} after 300 -> ok end,
  387:     ?line test_server:timetrap_cancel(Dog),
  388:     ok.
  389: 
  390: reload_pending(suite) -> [];
  391: reload_pending(doc) -> ["Reload a driver that is pending on a user"];
  392: reload_pending(Config) when is_list(Config) ->
  393:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  394:     ?line Path = ?config(data_dir, Config),
  395:     ?line Parent = self(),
  396:     ?line F3 = fun() -> 
  397: 		       Parent ! erl_ddll:monitor(driver,{echo_drv,unloaded}), 
  398: 		       receive X -> Parent ! {got,X} end 
  399: 	       end,
  400:     ?line Pid = spawn(fun() ->
  401: 			      receive go -> ok end,
  402: 			      {ok, loaded} = erl_ddll:try_load(Path, echo_drv, []),
  403: 			      spawn(F3),
  404: 			      receive go -> ok end,
  405: 			      _Port = open_port({spawn, echo_drv}, [eof]),
  406: 			      _Port2 = open_port({spawn, echo_drv}, [eof]),
  407: 			      Parent ! opened,
  408: 			      receive go -> ok end,
  409: 			      exit(banan)
  410: 		      end),
  411:     ?line Ref = erlang:monitor(process,Pid),
  412:     Pid ! go,
  413:     ?line {ok,Ref2} = receive 
  414: 			  R when is_reference(R) -> {ok,R}; 
  415: 			  Other -> {error, Other} 
  416: 		      after 500 -> {error, timeout} 
  417: 		      end,
  418:     ?line {ok, already_loaded} = erl_ddll:try_load(Path, echo_drv, []),
  419:     ?line Port = open_port({spawn, echo_drv}, [eof]),
  420:     Pid ! go,
  421:     ?line receive opened -> ok end,
  422:     ?line {error, pending_process} = 
  423: 	erl_ddll:try_load(Path, echo_drv,
  424: 			  [{reload,pending_driver},
  425: 			   {monitor,pending_driver}]),
  426:     ?line {ok, pending_process, Ref3} = 
  427: 	erl_ddll:try_load(Path, echo_drv,
  428: 			  [{reload,pending},
  429: 			   {monitor,pending}]),
  430:     ?line ok = receive X -> {error, X} after 300 -> ok end,
  431:     Pid ! go,
  432:     ?line ok = receive {'DOWN', Ref, process, Pid, banan} -> ok after 300 -> error end,
  433:     ?line ok = receive Y -> {error, Y} after 300 -> ok end,
  434:     ?line erlang:port_close(Port),
  435:     ?line ok = receive {got,{'DOWN', Ref2, driver, echo_drv, unloaded}} -> ok after 300 -> error end,
  436:     ?line ok = receive {'UP', Ref3, driver, echo_drv, loaded} -> ok after 300 -> error end,
  437:     [{Parent,1}] = erl_ddll:info(echo_drv,processes),
  438:     ?line ok = receive Z -> {error, Z} after 300 -> ok end,
  439:     ?line test_server:timetrap_cancel(Dog),
  440:     ok.
  441: 
  442: load_fail_init(suite) -> [];
  443: load_fail_init(doc) -> ["Tests failure in the init in driver struct."];
  444: load_fail_init(Config) when is_list(Config) ->
  445:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  446:     ?line Path = ?config(data_dir, Config),
  447:     ?line PathFailing = ?config(priv_dir, Config),
  448:     ?line [_|_] = AllFailInits = filelib:wildcard("echo_drv_fail_init.*",Path),
  449:     ?line lists:foreach(fun(Name) ->
  450: 				Src = filename:join([Path,Name]),
  451: 				Ext = filename:extension(Name),
  452: 				Dst =filename:join([PathFailing,"echo_drv"++Ext]),
  453: 				file:delete(Dst),
  454: 				{ok,_} = file:copy(Src,Dst)
  455: 			end,
  456: 			AllFailInits),
  457:     ?line [_|_] = filelib:wildcard("echo_drv.*",PathFailing),
  458:     ?line {error, driver_init_failed} = erl_ddll:try_load(PathFailing, 
  459: 							  echo_drv,
  460: 							  [{monitor,pending}]),
  461:     ?line ok = receive XX ->
  462: 		       {unexpected,XX}
  463: 	       after 300 ->
  464: 		       ok
  465: 	       end,
  466:     ?line test_server:timetrap_cancel(Dog),
  467:     ok.
  468: 
  469: 
  470: reload_pending_fail_init(suite) -> [];
  471: reload_pending_fail_init(doc) -> ["Reload a driver that is pending but init fails"];
  472: reload_pending_fail_init(Config) when is_list(Config) ->
  473:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  474:     ?line Path = ?config(data_dir, Config),
  475:     ?line PathFailing = ?config(priv_dir, Config),
  476:     ?line [_|_] = AllFailInits = filelib:wildcard("echo_drv_fail_init.*",Path),
  477:     ?line lists:foreach(fun(Name) ->
  478: 				Src = filename:join([Path,Name]),
  479: 				Ext = filename:extension(Name),
  480: 				Dst =filename:join([PathFailing,"echo_drv"++Ext]),
  481: 				file:delete(Dst),
  482: 				{ok,_} = file:copy(Src,Dst)
  483: 			end,
  484: 			AllFailInits),
  485:     ?line [_|_] = filelib:wildcard("echo_drv.*",PathFailing),
  486:     ?line Parent = self(),
  487:     ?line F3 = fun() -> 
  488: 		       Parent ! erl_ddll:monitor(driver,{echo_drv,unloaded}), 
  489: 		       receive X -> Parent ! {got,X} end 
  490: 	       end,
  491:     ?line Pid = spawn(fun() ->
  492: 			      receive go -> ok end,
  493: 			      {ok, loaded} = erl_ddll:try_load(Path, echo_drv, []),
  494: 			      spawn(F3),
  495: 			      receive go -> ok end,
  496: 			      _Port = open_port({spawn, echo_drv}, [eof]),
  497: 			      _Port2 = open_port({spawn, echo_drv}, [eof]),
  498: 			      Parent ! opened,
  499: 			      receive go -> ok end,
  500: 			      exit(banan)
  501: 		      end),
  502:     ?line Ref = erlang:monitor(process,Pid),
  503:     Pid ! go,
  504:     ?line {ok,Ref2} = receive 
  505: 			  R when is_reference(R) -> {ok,R}; 
  506: 			  Other -> {error, Other} 
  507: 		      after 500 -> {error, timeout} 
  508: 		      end,
  509:     ?line {ok, already_loaded} = erl_ddll:try_load(Path, echo_drv, []),
  510:     ?line Port = open_port({spawn, echo_drv}, [eof]),
  511:     Pid ! go,
  512:     ?line receive opened -> ok end,
  513:     ?line {ok, pending_process, Ref3} = 
  514: 	erl_ddll:try_load(PathFailing, echo_drv,
  515: 			  [{reload,pending},
  516: 			   {monitor,pending}]),
  517:     ?line ok = receive X -> {error, X} after 300 -> ok end,
  518:     Pid ! go,
  519:     ?line ok = receive {'DOWN', Ref, process, Pid, banan} -> ok after 300 -> error end,
  520:     ?line ok = receive Y -> {error, Y} after 300 -> ok end,
  521:     ?line erlang:port_close(Port),
  522:     ?line ok = receive {got,{'DOWN', Ref2, driver, echo_drv, unloaded}} -> ok after 300 -> error end,
  523:     ?line ok = receive {'DOWN', Ref3, driver, echo_drv, {load_failure,driver_init_failed}} -> ok  after 300 -> error end,
  524:     ?line {'EXIT',{badarg,_}} = (catch erl_ddll:info(echo_drv,processes)),
  525: 
  526:     ?line ok = receive Z -> {error, Z} after 300 -> ok end,
  527:     ?line test_server:timetrap_cancel(Dog),
  528:     ok.
  529: 
  530: reload_pending_kill(suite) -> [];
  531: reload_pending_kill(doc) -> ["Reload a driver with kill_ports option "
  532: 			     "that is pending on a user"];
  533: reload_pending_kill(Config) when is_list(Config) ->
  534:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  535:     ?line OldFlag = process_flag(trap_exit,true),
  536:     ?line Path = ?config(data_dir, Config),
  537:     ?line Parent = self(),
  538:     ?line F3 = fun() -> 
  539: 		       Parent ! erl_ddll:monitor(driver,{echo_drv,unloaded}), 
  540: 		       receive X -> Parent ! {got,X} end 
  541: 	       end,
  542:     ?line Pid = spawn(fun() ->
  543: 			      process_flag(trap_exit,true),
  544: 			      receive go -> ok end,
  545: 			      {ok, loaded} = erl_ddll:try_load(Path, echo_drv, [{driver_options,[kill_ports]}]),
  546: 			      spawn(F3),
  547: 			      receive go -> ok end,
  548: 			      Port = open_port({spawn, echo_drv}, [eof]),
  549: 			      Port2 = open_port({spawn, echo_drv}, [eof]),
  550: 			      Parent ! opened,
  551: 			      receive go -> ok end,
  552: 			      receive 
  553: 				  {'EXIT', Port2, driver_unloaded} ->
  554: 				      Parent ! first_exit 
  555: 			      end,
  556: 			      receive 
  557: 				  {'EXIT', Port, driver_unloaded} ->
  558: 				      Parent ! second_exit 
  559: 			      end,
  560: 			      receive go -> ok end,
  561: 			      exit(banan)
  562: 		      end),
  563:     ?line Ref = erlang:monitor(process,Pid),
  564:     Pid ! go,
  565:     ?line {ok,Ref2} = receive 
  566: 			  R when is_reference(R) -> {ok,R}; 
  567: 			  Other -> {error, Other} 
  568: 		      after 500 -> {error, timeout} 
  569: 		      end,
  570:     ?line {ok, already_loaded} = erl_ddll:try_load(Path, echo_drv, [{driver_options,[kill_ports]}]),
  571:     ?line {error,inconsistent} = erl_ddll:try_load(Path, echo_drv, []),
  572:     ?line Port = open_port({spawn, echo_drv}, [eof]),
  573:     Pid ! go,
  574:     ?line receive opened -> ok end,
  575:     ?line {error, pending_process} = 
  576: 	erl_ddll:try_load(Path, echo_drv,
  577: 			  [{driver_options,[kill_ports]},
  578: 			   {reload,pending_driver},
  579: 			   {monitor,pending_driver}]),
  580:     ?line {ok, pending_process, Ref3} = 
  581: 	erl_ddll:try_load(Path, echo_drv,
  582: 			  [{driver_options,[kill_ports]},
  583: 			   {reload,pending},
  584: 			   {monitor,pending}]),
  585:     ?line ok =  receive 
  586: 		    {'EXIT', Port, driver_unloaded} ->
  587: 			ok 
  588: 		after 300 -> error
  589: 		end,
  590:     Pid ! go,
  591:     ?line ok = receive {got,{'DOWN', Ref2, driver, echo_drv, unloaded}} -> ok after 300 -> error end,
  592:     ?line ok = receive {'UP', Ref3, driver, echo_drv, loaded} -> ok after 300 -> error end,
  593:     ?line [_,_] = erl_ddll:info(echo_drv,processes),
  594:     ?line ok = receive first_exit -> ok after 300 -> error end,
  595:     ?line ok = receive second_exit -> ok after 300 -> error end,
  596:     ?line 0 = erl_ddll:info(echo_drv,port_count), 
  597:     ?line ok = receive X -> {error, X} after 300 -> ok end,
  598:     Pid ! go,
  599:     ?line ok = receive {'DOWN', Ref, process, Pid, banan} -> ok after 300 -> error end,
  600:     ?line ok = receive Y -> {error, Y} after 300 -> ok end,
  601:     ?line Port2 = open_port({spawn, echo_drv}, [eof]),
  602:     ?line true = is_port(Port2),
  603:     [{Parent,1}] = erl_ddll:info(echo_drv,processes),
  604:     ?line 1 = erl_ddll:info(echo_drv,port_count), 
  605:     ?line erlang:port_close(Port2),
  606:     ?line ok = receive {'EXIT', Port2, normal} -> ok after 300 -> error end,
  607:     ?line 0 = erl_ddll:info(echo_drv,port_count), 
  608:     ?line [{Parent,1}] = erl_ddll:info(echo_drv,processes),
  609:     ?line Port3 = open_port({spawn, echo_drv}, [eof]),
  610:     ?line {ok, pending_driver, Ref4} = 
  611: 	erl_ddll:try_unload(echo_drv,[{monitor,pending_driver}]),
  612:     ?line ok =  receive 
  613: 		    {'EXIT', Port3, driver_unloaded} ->
  614: 			ok 
  615: 		after 300 -> error
  616: 		end,
  617:     ?line ok = receive {'DOWN', Ref4, driver, echo_drv, unloaded} -> ok after 300 -> error end,
  618:     io:format("Port = ~w, Port2 = ~w, Port3 = ~w~n",[Port,Port2,Port3]),
  619:     ?line ok = receive Z -> {error, Z} after 300 -> ok end,
  620:     ?line process_flag(trap_exit,OldFlag),
  621:     ?line test_server:timetrap_cancel(Dog),
  622:     ok.
  623: 
  624: 
  625: more_error_codes(suite) ->
  626:     [];
  627: more_error_codes(doc) ->
  628:     ["Some more error code checking"];
  629: more_error_codes(Config) when is_list(Config) ->
  630:     ?line {error,Err} = erl_ddll:try_load("./echo_dr",echo_dr,[]),
  631:     ?line true = is_list(erl_ddll:format_error(Err)),
  632:     ?line true = is_list(erl_ddll:format_error(not_loaded)),
  633:     ok.
  634: 
  635: forced_port_killing(suite) ->
  636:     [];
  637: forced_port_killing(doc) ->
  638:     ["Check kill_ports option to try_unload "];
  639: forced_port_killing(Config) when is_list(Config) ->
  640:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  641:     ?line Path = ?config(data_dir, Config),
  642:     ?line OldFlag=process_flag(trap_exit,true),
  643:     ?line Parent = self(),
  644:     ?line F3 = fun() -> 
  645: 		       Parent ! erl_ddll:monitor(driver,{echo_drv,unloaded}), 
  646: 		       receive X -> Parent ! {got,X} end 
  647: 	       end,
  648:     ?line {ok, loaded} = erl_ddll:try_load(Path, echo_drv, []),
  649:     ?line spawn(F3),
  650:     ?line {ok,Ref2} = receive 
  651: 			  R when is_reference(R) -> {ok,R}; 
  652: 			  Other -> {error, Other} 
  653: 		      after 500 -> {error, timeout} 
  654: 		      end,
  655:     ?line Port = open_port({spawn, echo_drv}, [eof]),
  656:     ?line Port2 = open_port({spawn, echo_drv}, [eof]),
  657:     ?line {ok, pending_driver, Ref1} = 
  658: 	erl_ddll:try_unload(echo_drv,[{monitor,pending_driver},kill_ports]),
  659:     ?line ok = receive 
  660: 		   {got,{'DOWN', Ref2, driver, echo_drv, unloaded}} -> ok 
  661: 	       after 300 -> error 
  662: 	       end,
  663:     ?line ok = receive {'EXIT',Port,driver_unloaded} -> ok after 300 -> false end,
  664:     ?line ok = receive {'EXIT',Port2,driver_unloaded} -> ok after 300 -> false end,
  665:     ?line ok = receive {'DOWN',Ref1, driver, echo_drv, unloaded} -> ok after 300 -> false end,
  666:     ?line process_flag(trap_exit,OldFlag),
  667:     ?line ok = receive X -> {error, X} after 300 -> ok end,
  668:     ?line test_server:timetrap_cancel(Dog),
  669:     ok.
  670: 
  671: no_trap_exit_and_kill_ports(suite) ->
  672:     [];
  673: no_trap_exit_and_kill_ports(doc) ->
  674:     ["Check delayed unload and reload with no trap_exit"];
  675: no_trap_exit_and_kill_ports(Config) when is_list(Config) ->
  676:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  677:     ?line Path = ?config(data_dir, Config),
  678:     ?line Parent = self(),
  679:     ?line OldFlag=process_flag(trap_exit,true),
  680:     ?line F3 = fun() -> 
  681: 		       Parent ! erl_ddll:monitor(driver,{echo_drv,unloaded}), 
  682: 		       receive X -> Parent ! {got,X} end 
  683: 	       end,
  684:     ?line Pid = spawn(fun() ->
  685: 			      process_flag(trap_exit,false),
  686: 			      receive go -> ok end,
  687: 			      {ok, loaded} = erl_ddll:try_load(Path, echo_drv, 
  688: 							       [{driver_options,[kill_ports]}]),
  689: 			      spawn(F3),
  690: 			      receive go -> ok end,
  691: 			      _Port = open_port({spawn, echo_drv}, [eof]),
  692: 			      _Port2 = open_port({spawn, echo_drv}, [eof]),
  693: 			      exit(banan)
  694: 		      end),
  695:     ?line Ref = erlang:monitor(process,Pid),
  696:     Pid ! go,
  697:     ?line {ok,Ref2} = receive 
  698: 			  R when is_reference(R) -> {ok,R}; 
  699: 			  Other -> {error, Other} 
  700: 		      after 500 -> {error, timeout} 
  701: 		      end,
  702:     ?line {error, inconsistent} = erl_ddll:try_load(Path, echo_drv, []),
  703:     ?line MyPort = open_port({spawn, echo_drv}, [eof]),
  704:     Pid ! go,
  705:     ?line ok = receive {'DOWN', Ref, process, Pid, banan} -> ok after 300 -> error end,
  706:     ?line ok = receive {got,{'DOWN', Ref2, driver, echo_drv, unloaded}} -> ok after 300 -> error end,
  707:     ?line ok = receive {'EXIT',MyPort,driver_unloaded} -> ok after 300 -> error end,
  708:     ?line process_flag(trap_exit,OldFlag),
  709:     ?line test_server:timetrap_cancel(Dog),
  710:     ok.
  711: 
  712: monitor_demonitor(suite) ->
  713:     [];
  714: monitor_demonitor(doc) ->
  715:     ["Check monitor and demonitor of drivers"];
  716: monitor_demonitor(Config) when is_list(Config) ->
  717:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  718:     ?line Path = ?config(data_dir, Config),
  719:     ?line erl_ddll:try_load(Path, echo_drv, []),
  720:     ?line Ref = erl_ddll:monitor(driver,{echo_drv,unloaded}),
  721:     ?line Self = self(),
  722:     ?line [{Self,1}] = erl_ddll:info(echo_drv,awaiting_unload),
  723:     ?line true = erl_ddll:demonitor(Ref),
  724:     ?line [] = erl_ddll:info(echo_drv,awaiting_unload),
  725:     ?line erl_ddll:try_unload(echo_drv,[]),
  726:     ?line ok = receive _ -> error after 300 -> ok end,
  727:     ?line test_server:timetrap_cancel(Dog),
  728:     ok.
  729: 
  730: monitor_demonitor_load(suite) ->
  731:     [];
  732: monitor_demonitor_load(doc) ->
  733:     ["Check monitor/demonitor of driver loading"];
  734: monitor_demonitor_load(Config) when is_list(Config) ->
  735:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  736:     ?line Path = ?config(data_dir, Config),
  737:     ?line {ok,loaded} = erl_ddll:try_load(Path, echo_drv, []),
  738:     ?line Port = open_port({spawn, echo_drv}, [eof]),
  739:     ?line Ref = erl_ddll:monitor(driver,{echo_drv,loaded}),
  740:     ?line ok = receive {'UP',Ref,driver,echo_drv,loaded} -> ok after 500 -> error end,
  741:     ?line {ok, pending_driver} = erl_ddll:try_unload(echo_drv,[]),
  742:     ?line Ref2 = erl_ddll:monitor(driver,{echo_drv,loaded}),
  743:     ?line ok = receive {'DOWN',Ref2,driver,echo_drv,load_cancelled} -> ok after 0 -> error end,
  744:     ?line {ok,already_loaded} = erl_ddll:try_load(Path, echo_drv, []),
  745:     ?line {ok, pending_driver} = 
  746: 	erl_ddll:try_load(Path, echo_drv, [{reload,pending_driver}]),
  747:     ?line Ref3 = erl_ddll:monitor(driver,{echo_drv,loaded}),
  748:     ?line Ref4 = erl_ddll:monitor(driver,{echo_drv,unloaded}),
  749:     ?line ok = receive _ -> error after 300 -> ok end,
  750:     ?line Self = self(),
  751:     ?line [{Self,1}] = erl_ddll:info(echo_drv,awaiting_load),
  752:     ?line true = erl_ddll:demonitor(Ref3),
  753:     ?line [] = erl_ddll:info(echo_drv,awaiting_load),
  754:     ?line erlang:port_close(Port),
  755:     ?line ok = receive {'DOWN',Ref4,driver,echo_drv,unloaded} -> ok after 300 -> error end,
  756:     ?line ok = receive _ -> error after 300 -> ok end,
  757:     ?line ok = unload_expect_fast(echo_drv,[]),
  758:     ?line test_server:timetrap_cancel(Dog),
  759:     ok.
  760: 
  761: new_interface(suite) ->
  762:     [];
  763: new_interface(doc) ->
  764:     ["Test the new load/unload/reload interface"];
  765: new_interface(Config) when is_list(Config) ->
  766:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  767:     ?line Path = ?config(data_dir, Config),
  768:     % Typical scenario
  769:     ?line ok = erl_ddll:load(Path, echo_drv),
  770:     ?line Port = open_port({spawn, echo_drv}, [eof]),
  771:     ?line ok = erl_ddll:unload(echo_drv),
  772:     ?line Port ! {self(), {command, "text"}},
  773:     ?line ok = receive 
  774: 		   {Port, {data, "text"}} -> ok;
  775: 		   _ -> error
  776: 	       after 
  777: 		   1000 -> error
  778: 	       end,
  779:     ?line Ref = erl_ddll:monitor(driver,{echo_drv,unloaded}),
  780:     ?line ok = receive X -> {error, X} after 300 -> ok end,
  781:     ?line erlang:port_close(Port),
  782:     ?line ok = receive {'DOWN', Ref, driver, echo_drv, unloaded} -> ok after 300 -> error end,
  783:     % More than one user
  784:     ?line ok = erl_ddll:load(Path, echo_drv),
  785:     ?line Ref2 = erl_ddll:monitor(driver,{echo_drv,unloaded}),
  786:     ?line ok = erl_ddll:load(Path, echo_drv),
  787:     ?line ok = erl_ddll:load(Path, echo_drv),
  788:     ?line Port2 = open_port({spawn, echo_drv}, [eof]),
  789:     ?line ok = erl_ddll:unload(echo_drv),
  790:     ?line Port2 ! {self(), {command, "text"}},
  791:     ?line ok = receive 
  792: 		   {Port2, {data, "text"}} -> ok;
  793: 		   _ -> error
  794: 	       after 
  795: 		   1000 -> error
  796: 	       end,
  797:     ?line ok = erl_ddll:unload(echo_drv),
  798:     ?line Port2 ! {self(), {command, "text"}},
  799:     ?line ok = receive 
  800: 		   {Port2, {data, "text"}} -> ok;
  801: 		   _ -> error
  802: 	       after 
  803: 		   1000 -> error
  804: 	       end,
  805:     ?line ok = erl_ddll:unload(echo_drv),
  806:     ?line Port2 ! {self(), {command, "text"}},
  807:     ?line ok = receive 
  808: 		   {Port2, {data, "text"}} -> ok;
  809: 		   _ -> error
  810: 	       after 
  811: 		   1000 -> error
  812: 	       end,
  813:     ?line ok = receive X2 -> {error, X2} after 300 -> ok end,
  814:     ?line ok = erl_ddll:load(Path, echo_drv),
  815:     ?line ok = receive {'UP', Ref2, driver, echo_drv, unload_cancelled} -> ok after 300 -> error end,
  816:     ?line Ref3 = erl_ddll:monitor(driver,{echo_drv,unloaded_only}),
  817:     ?line erlang:port_close(Port2),
  818:     ?line ok = receive X3 -> {error, X3} after 300 -> ok end,
  819:     ?line ok = erl_ddll:unload(echo_drv),
  820:     ?line ok = receive {'DOWN', Ref3, driver, echo_drv, unloaded} -> ok after 300 -> error end,
  821:     ?line test_server:timetrap_cancel(Dog),
  822:     ok.
  823:     
  824:     
  825: 
  826: 
  827: ddll_test(Config) when is_list(Config) ->
  828:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  829:     ?line Path = ?config(data_dir, Config),
  830: 
  831:     %?line {error,{already_started,ErlDdllPid}} = erl_ddll:start(),
  832:     %?line ErlDdllPid = whereis(ddll_server),
  833: 
  834:     %% Load the echo driver and verify that it was loaded.
  835:     {ok,L1,L2}=load_echo_driver(Path),
  836: 
  837:     %% Verify that the driver works.
  838: 
  839:      ?line Port = open_port({spawn, echo_drv}, [eof]),
  840:      ?line {hej, "hopp",4711,123445567436543653} = 
  841:  	erlang:port_call(Port,{hej, "hopp",4711,123445567436543653}),
  842:      ?line {hej, "hopp",4711,123445567436543653} = 
  843:  	erlang:port_call(Port,47,{hej, "hopp",4711,123445567436543653}),
  844:      ?line Port ! {self(), {command, "text"}},
  845:      ?line 1 = receive 
  846:  		  {Port, {data, "text"}} -> 1;
  847:  		  _Other -> 2
  848:  	      after 
  849:  		  1000 -> 2
  850:  	      end,
  851:      ?line Port ! {self(), close},
  852:      ?line receive {Port, closed} -> ok end,
  853: 
  854: %%     %% Unload the driver and verify that it was unloaded.
  855:      ok = unload_echo_driver(L1,L2),
  856: 
  857: %%     %?line {error, {already_started, _}} = erl_ddll:start(),
  858: 
  859:     ?line test_server:timetrap_cancel(Dog),
  860:     ok.
  861: 
  862: %% Tests errors having to do with bad drivers.
  863: 
  864: errors(Config) when is_list(Config) ->
  865:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  866:     ?line Path = ?config(data_dir, Config),
  867: 
  868:     ?line {ok, L1} = erl_ddll:loaded_drivers(),
  869: 
  870:     ?line {error, {open_error, _}} = erl_ddll:load_driver(Path, bad_name),
  871:     ?line {error, driver_init_failed} = erl_ddll:load_driver(Path, initfail_drv),
  872:     ?line {error, bad_driver_name} = erl_ddll:load_driver(Path, wrongname_drv),
  873: 
  874:     %% We assume that there is a statically linked driver named "ddll":
  875:     ?line {error, linked_in_driver} = erl_ddll:unload_driver(efile),
  876:     ?line {error, not_loaded} = erl_ddll:unload_driver("__pucko_driver__"),
  877: 	
  878:     case os:type() of
  879: 	{unix, _} ->
  880: 	    ?line {error, no_driver_init} =
  881: 		erl_ddll:load_driver(Path, noinit_drv);
  882: 	_ ->
  883: 	    ok
  884:     end,
  885: 
  886:     ?line {ok, L1} = erl_ddll:loaded_drivers(),
  887: 
  888:     ?line test_server:timetrap_cancel(Dog),
  889:     ok.
  890: 
  891: reference_count(doc) ->
  892:     ["Check that drivers are unloaded when their reference count ",
  893:      "reaches zero, and that they cannot be unloaded while ",
  894:      "they are still referenced."];
  895: reference_count(Config) when is_list(Config) ->
  896:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  897:     ?line Path = ?config(data_dir, Config),
  898: 
  899:     %% Spawn a process that loads the driver (and holds a reference
  900:     %% to it).
  901:     Pid1=spawn_link(?MODULE, echo_loader, [Path, self()]),
  902:     receive
  903: 	{Pid1, echo_loaded} -> ok
  904:     after 2000 -> test_server:fail("echo_loader failed to start.")
  905:     end,
  906: 
  907:     Pid1 ! {self(), die},
  908:     ?line test_server:sleep(200),   % Give time to unload.
  909:     % Verify that the driver was automaticly unloaded when the
  910:     % process died.
  911:     ?line {error, not_loaded}=erl_ddll:unload_driver(echo_drv),
  912:     
  913:     ?line test_server:timetrap_cancel(Dog),
  914:     ok.
  915: 
  916: % Loads the echo driver, send msg to started, sits and waits to
  917: % get a signal to die, then unloads the driver and terminates.
  918: echo_loader(Path, Starter) ->
  919:     ?line {ok, L1, L2}=load_echo_driver(Path),
  920:     ?line Starter ! {self(), echo_loaded},
  921:     receive
  922: 	{Starter, die} ->
  923: 	    ?line unload_echo_driver(L1,L2)
  924:     end.
  925: 
  926: % Loads the echo driver, send msg to started, sits and waits to
  927: % get a signal to die, then unloads the driver and terminates.
  928: nice_echo_loader(Path, Starter) ->
  929:     ?line {ok, L1, L2}=load_nice_echo_driver(Path),
  930:     ?line Starter ! {self(), echo_loaded},
  931:     receive
  932: 	{Starter, die} ->
  933: 	    ?line unload_echo_driver(L1,L2)
  934:     end.
  935: 
  936: 
  937: kill_port(doc) ->
  938:     ["Test that a port that uses a driver is killed when the ",
  939:      "process that loaded the driver dies."];
  940: kill_port(Config) when is_list(Config) ->
  941:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  942:     ?line Path = ?config(data_dir, Config),
  943: 
  944:     %% Spawn a process that loads the driver (and holds a reference
  945:     %% to it).
  946:     ?line Pid1=spawn(?MODULE, echo_loader, [Path, self()]),
  947:     ?line receive
  948: 	      {Pid1, echo_loaded} ->
  949: 		  ok
  950: 	  after 3000 ->
  951: 		  ?line exit(Pid1, kill),
  952: 		  ?line test_server:fail("echo_loader failed to start.")
  953: 	  end,
  954: 
  955:     % Spawn off a port that uses the driver.
  956:     ?line Port = open_port({spawn, echo_drv}, [eof]),
  957: 
  958:     % Kill the process / unload the driver.
  959:     ?line process_flag(trap_exit, true),
  960:     ?line exit(Pid1, kill),
  961:     ?line test_server:sleep(200),    % Give some time to unload.
  962:     ?line {error, not_loaded} = erl_ddll:unload_driver(echo_drv),
  963: 
  964:     % See if the port is killed.
  965:     receive
  966: 	{'EXIT', Port, Reason} ->
  967: 	    io:format("Port exited with reason ~w", [Reason])
  968:     after 5000 ->
  969: 	    ?line test_server:fail("Echo port did not terminate.")
  970:     end,
  971: 
  972:     %% Cleanup and exit.
  973:     ?line test_server:timetrap_cancel(Dog),
  974:     ok.
  975: 
  976: dont_kill_port(doc) ->
  977:     ["Test that a port that uses a driver is not killed when the ",
  978:      "process that loaded the driver dies and it's nicely opened."];
  979: dont_kill_port(Config) when is_list(Config) ->
  980:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
  981:     ?line Path = ?config(data_dir, Config),
  982: 
  983:     %% Spawn a process that loads the driver (and holds a reference
  984:     %% to it).
  985:     ?line Pid1=spawn(?MODULE, nice_echo_loader, [Path, self()]),
  986:     ?line receive
  987: 	      {Pid1, echo_loaded} ->
  988: 		  ok
  989: 	  after 3000 ->
  990: 		  ?line exit(Pid1, kill),
  991: 		  ?line test_server:fail("echo_loader failed to start.")
  992: 	  end,
  993: 
  994:     % Spawn off a port that uses the driver.
  995:     ?line Port = open_port({spawn, echo_drv}, [eof]),
  996: 
  997:     % Kill the process / unload the driver.
  998:     ?line process_flag(trap_exit, true),
  999:     ?line exit(Pid1, kill),
 1000:     ?line test_server:sleep(200),    % Give some time to unload.
 1001:     ?line {hej, "hopp",4711,123445567436543653} = 
 1002: 	erlang:port_call(Port,{hej, "hopp",4711,123445567436543653}),
 1003:     ?line [] = erl_ddll:info(echo_drv,processes),
 1004:     %% unload should work with no owner
 1005:     ?line ok = erl_ddll:unload_driver(echo_drv), %Kill ports while at it
 1006: 
 1007:     % See if the port is killed.
 1008:     receive
 1009: 	{'EXIT', Port, Reason} ->
 1010: 	    io:format("Port exited with reason ~w", [Reason])
 1011:     after 5000 ->
 1012: 	    ?line test_server:fail("Echo port did not terminate.")
 1013:     end,
 1014: 
 1015:     %% Cleanup and exit.
 1016:     ?line test_server:timetrap_cancel(Dog),
 1017:     ok.
 1018: 
 1019: properties(doc) -> ["Test that a process that loaded a driver ",
 1020: 		    "is the only process that can unload it."];
 1021: properties(Config) when is_list(Config) ->
 1022:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
 1023:     ?line Path = ?config(data_dir, Config),
 1024: 
 1025:     % Let another process load the echo driver.
 1026:     Pid=spawn_link(?MODULE, echo_loader, [Path, self()]),
 1027:     receive
 1028: 	{Pid, echo_loaded} -> ok
 1029:     after 2000 -> test_server:fail("echo_loader failed to start.")
 1030:     end,
 1031: 
 1032:     % Try to unload the driver from this process (the wrong one).
 1033:     ?line {error, _} = erl_ddll:unload_driver(echo_drv),
 1034:     ?line {ok, Drivers} = erl_ddll:loaded_drivers(),
 1035:     ?line case lists:member("echo_drv", Drivers) of
 1036: 	      true ->
 1037: 		  ok;
 1038: 	      false ->
 1039: 		  test_server:fail("Unload from wrong process "
 1040: 				   "succeeded.")
 1041: 	  end,
 1042: 
 1043:     % Unload the driver and terminate dummy process.
 1044:     ?line Pid ! {self(), die},
 1045:     ?line test_server:sleep(200),   % Give time to unload.
 1046:     ?line test_server:timetrap_cancel(Dog),
 1047:     ok.
 1048: 
 1049: load_and_unload(doc) -> ["Load two drivers and unload them in load order."];
 1050: load_and_unload(Config) when is_list(Config) ->
 1051:     ?line Dog = test_server:timetrap(test_server:seconds(60)),
 1052:     ?line Path = ?config(data_dir, Config),
 1053:     ?line {ok, Loaded_drivers1} = erl_ddll:loaded_drivers(),
 1054:     ?line ok = erl_ddll:load_driver(Path, echo_drv),
 1055:     ?line ok = erl_ddll:load_driver(Path, dummy_drv),
 1056:     ?line ok = erl_ddll:unload_driver(echo_drv),
 1057:     ?line ok = erl_ddll:unload_driver(dummy_drv),
 1058:     ?line {ok, Loaded_drivers2} = erl_ddll:loaded_drivers(),
 1059:     ?line Set1 = ordsets:from_list(Loaded_drivers1),
 1060:     ?line Set2 = ordsets:from_list(Loaded_drivers2),
 1061:     ?line io:format("~p == ~p\n", [Loaded_drivers1, Loaded_drivers2]),
 1062:     ?line [] = ordsets:to_list(ordsets:subtract(Set2, Set1)),
 1063: 
 1064:     ?line test_server:timetrap_cancel(Dog),
 1065:     ok.    
 1066: 
 1067: lock_driver(suite) ->
 1068:     [];
 1069: lock_driver(doc) ->
 1070:     ["Check multiple calls to driver_lock_driver"];
 1071: lock_driver(Config) when is_list(Config) ->
 1072:     ?line Dog = test_server:timetrap(test_server:seconds(10)),
 1073:     ?line Path = ?config(data_dir, Config),
 1074:     ?line {ok, _} = erl_ddll:try_load(Path, lock_drv, []),
 1075:     ?line Port1 = open_port({spawn, lock_drv}, [eof]),
 1076:     ?line Port2 = open_port({spawn, lock_drv}, [eof]),
 1077:     ?line true = erl_ddll:info(lock_drv,permanent),
 1078:     ?line erlang:port_close(Port1),
 1079:     ?line erlang:port_close(Port2),
 1080:     ?line test_server:timetrap_cancel(Dog),
 1081:     ok.
 1082:     
 1083: 
 1084: % Load and unload the echo_drv driver.
 1085: % Make sure that the driver doesn't exist before we load it,
 1086: % and that it exists before we unload it.
 1087: load_echo_driver(Path) ->
 1088:     ?line {ok, L1} = erl_ddll:loaded_drivers(),
 1089:     ?line ok = erl_ddll:load_driver(Path, echo_drv),
 1090:     ?line {ok, L2} = erl_ddll:loaded_drivers(),
 1091:     ?line ["echo_drv"] = ordsets:to_list(subtract(ordsets:from_list(L2), 
 1092: 						  ordsets:from_list(L1))),
 1093:     {ok,L1,L2}.
 1094: 
 1095: load_nice_echo_driver(Path) ->
 1096:     ?line {ok, L1} = erl_ddll:loaded_drivers(),
 1097:     ?line ok = erl_ddll:load(Path, echo_drv),
 1098:     ?line {ok, L2} = erl_ddll:loaded_drivers(),
 1099:     ?line ["echo_drv"] = ordsets:to_list(subtract(ordsets:from_list(L2), 
 1100: 						  ordsets:from_list(L1))),
 1101:     {ok,L1,L2}.
 1102: 
 1103: unload_echo_driver(L1,L2) ->
 1104:     ?line {ok, L2} = erl_ddll:loaded_drivers(),
 1105:     ?line ok = erl_ddll:unload_driver(echo_drv),
 1106:     ?line {ok, L3} = erl_ddll:loaded_drivers(),
 1107:     ?line [] = ordsets:to_list(subtract(ordsets:from_list(L3),
 1108: 					ordsets:from_list(L1))),
 1109:     ok.
 1110: 
 1111: unload_expect_fast(Driver,XFlags) ->
 1112:     {ok, pending_driver, Ref} = 
 1113: 	erl_ddll:try_unload(Driver,
 1114: 			    [{monitor,pending_driver}]++XFlags),
 1115:     receive
 1116: 	{'DOWN', Ref, driver, Driver, unloaded} ->
 1117: 	    case lists:member(atom_to_list(Driver),element(2,erl_ddll:loaded_drivers())) of
 1118: 		true ->
 1119: 		    {error, {still_there, Driver}};
 1120: 		false ->
 1121: 		    ok
 1122: 	    end
 1123:     after 1000 ->
 1124: 	    {error,{unable_to_unload, Driver}}
 1125:     end.