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