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.