diff options
Diffstat (limited to 'lib/kernel')
40 files changed, 1501 insertions, 204 deletions
diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml index 6b89711924..ee687511a3 100644 --- a/lib/kernel/doc/src/code.xml +++ b/lib/kernel/doc/src/code.xml @@ -229,10 +229,10 @@ <c>-code_path_choice Choice</c>. If the flag is set to <c>relaxed</c>, the code server will instead choose a suitable directory depending on the actual file structure. If there exists a regular - application ebin directory,situation it will be choosen. But if it does - not exist, the ebin directory in the archive is choosen if it + application ebin directory,situation it will be chosen. But if it does + not exist, the ebin directory in the archive is chosen if it exists. If neither of them exists the original directory will be - choosen.</p> + chosen.</p> <p>The command line flag <c>-code_path_choice Choice</c> does also affect how <c>init</c> interprets the <c>boot script</c>. The diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 7db20e6343..772eff13cc 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -149,6 +149,12 @@ <datatype> <name name="mode"/> </datatype> + <datatype> + <name name="file_info_option"/> + </datatype> + <datatype> + <name name="sendfile_option"/> + </datatype> </datatypes> <funcs> @@ -409,7 +415,7 @@ <name>file_info(Filename) -> {ok, FileInfo} | {error, Reason}</name> <fsummary>Get information about a file (deprecated)</fsummary> <desc> - <p>This function is obsolete. Use <c>read_file_info/1</c> + <p>This function is obsolete. Use <c>read_file_info/1,2</c> instead.</p> </desc> </func> @@ -536,7 +542,7 @@ <desc> <p>Makes a hard link from <c><anno>Existing</anno></c> to <c><anno>New</anno></c>, on - platforms that support links (Unix). This function returns + platforms that support links (Unix and Windows). This function returns <c>ok</c> if the link was successfully created, or <c>{error, <anno>Reason</anno>}</c>. On platforms that do not support links, <c>{error,enotsup}</c> is returned.</p> @@ -563,11 +569,12 @@ <name name="make_symlink" arity="2"/> <fsummary>Make a symbolic link to a file or directory</fsummary> <desc> - <p>This function creates a symbolic link <c><anno>Name2</anno></c> to - the file or directory <c><anno>Name1</anno></c>, on platforms that - support - symbolic links (most Unix systems). <c><anno>Name1</anno></c> need not - exist. This function returns <c>ok</c> if the link was + <p>This function creates a symbolic link <c><anno>New</anno></c> to + the file or directory <c><anno>Existing</anno></c>, on platforms that + support symbolic links (most Unix systems and Windows beginning with + Vista). + <c><anno>Existing</anno></c> need not exist. + This function returns <c>ok</c> if the link was successfully created, or <c>{error, <anno>Reason</anno>}</c>. On platforms that do not support symbolic links, <c>{error, enotsup}</c> @@ -577,11 +584,11 @@ <tag><c>eacces</c></tag> <item> <p>Missing read or write permissions for the parent directories - of <c><anno>Name1</anno></c> or <c><anno>Name2</anno></c>.</p> + of <c><anno>Existing</anno></c> or <c><anno>New</anno></c>.</p> </item> <tag><c>eexist</c></tag> <item> - <p><c><anno>Name2</anno></c> already exists.</p> + <p><c><anno>New</anno></c> already exists.</p> </item> <tag><c>enotsup</c></tag> <item> @@ -1185,6 +1192,7 @@ </func> <func> <name name="read_file_info" arity="1"/> + <name name="read_file_info" arity="2"/> <fsummary>Get information about a file</fsummary> <desc> <p>Retrieves information about a file. Returns @@ -1196,6 +1204,20 @@ from which the function is called:</p> <code type="none"> -include_lib("kernel/include/file.hrl").</code> + <p>The time type returned in <c>atime</c>, <c>mtime</c> and <c>ctime</c> + is dependent on the time type set in <c>Opts :: {time, Type}</c>. + Type <c>local</c> will return local time, <c>universal</c> will + return universal time and <c>posix</c> will return seconds since + or before unix time epoch which is 1970-01-01 00:00 UTC. + Default is <c>{time, local}</c>. + </p> + <note> + <p> + Since file times is stored in posix time on most OS it is + faster to query file information with the <c>posix</c> option. + </p> + </note> + <p>The record <c>file_info</c> contains the following fields.</p> <taglist> <tag><c>size = integer()</c></tag> @@ -1210,15 +1232,15 @@ <item> <p>The current system access to the file.</p> </item> - <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso></c></tag> + <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso> | integer() </c></tag> <item> - <p>The last (local) time the file was read.</p> + <p>The last time the file was read.</p> </item> - <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso></c></tag> + <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso> | integer() </c></tag> <item> - <p>The last (local) time the file was written.</p> + <p>The last time the file was written.</p> </item> - <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso></c></tag> + <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso> | integer() </c></tag> <item> <p>The interpretation of this time field depends on the operating system. On Unix, it is the last time @@ -1374,9 +1396,11 @@ </func> <func> <name name="read_link_info" arity="1"/> + <name name="read_link_info" arity="2"/> <fsummary>Get information about a link or file</fsummary> <desc> - <p>This function works like <c>read_file_info/1</c>, except that + <p>This function works like + <seealso marker="#read_file_info/2">read_file_info/1,2</seealso> except that if <c><anno>Name</anno></c> is a symbolic link, information about the link will be returned in the <c>file_info</c> record and the <c>type</c> field of the record will be set to @@ -1574,6 +1598,48 @@ </desc> </func> <func> + <name name="sendfile" arity="2"/> + <fsummary>send a file to a socket</fsummary> + <desc> + <p>Sends the file <c>Filename</c> to <c>Socket</c>. + Returns <c>{ok, BytesSent}</c> if successful, + otherwise <c>{error, Reason}</c>.</p> + </desc> + </func> + <func> + <name name="sendfile" arity="5"/> + <fsummary>send a file to a socket</fsummary> + <desc> + <p>Sends <c>Bytes</c> from the file + referenced by <c>RawFile</c> beginning at <c>Offset</c> to + <c>Socket</c>. + Returns <c>{ok, BytesSent}</c> if successful, + otherwise <c>{error, Reason}</c>. If <c>Bytes</c> is set to + 0 all data after the given <c>Offset</c> is sent.</p> + <p>The file used must be opened using the raw flag, and the process + calling sendfile must be the controlling process of the socket. + See <seealso marker="gen_tcp#controlling_process-2">gen_tcp:controlling_process/2</seealso></p> + <p>If the OS used does not support sendfile, an Erlang fallback + using file:read and gen_tcp:send is used.</p> + <p>The option list can contain the following options: + <taglist> + <tag><c>chunk_size</c></tag> + <item>The chunk size used by the erlang fallback to send + data. If using the fallback, this should be set to a value + which comfortably fits in the systems memory. Default is 20 MB.</item> + </taglist> + </p> + <p>On operating systems with thread support, it is recommended to use + async threads. See the command line flag + <c>+A</c> in <seealso marker="erts:erl">erl(1)</seealso>. If it is not + possible to use async threads for sendfile, it is recommended to use + a relatively small value for the send buffer on the socket. Otherwise + the Erlang VM might loose some of its soft realtime guarantees. + Which size to use depends on the OS/hardware and the requirements + of the application.</p> + </desc> + </func> + <func> <name name="write" arity="2"/> <fsummary>Write to a file</fsummary> <desc> @@ -1645,6 +1711,7 @@ </func> <func> <name name="write_file_info" arity="2"/> + <name name="write_file_info" arity="3"/> <fsummary>Change information about a file</fsummary> <desc> <p>Change file information. Returns <c>ok</c> if successful, @@ -1655,18 +1722,25 @@ from which the function is called:</p> <code type="none"> -include_lib("kernel/include/file.hrl").</code> + <p>The time type set in <c>atime</c>, <c>mtime</c> and <c>ctime</c> + is dependent on the time type set in <c>Opts :: {time, Type}</c>. + Type <c>local</c> will interpret the time set as local, <c>universal</c> will + interpret it as universal time and <c>posix</c> must be seconds since + or before unix time epoch which is 1970-01-01 00:00 UTC. + Default is <c>{time, local}</c>. + </p> <p>The following fields are used from the record, if they are given.</p> <taglist> - <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso></c></tag> + <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso> | integer()</c></tag> <item> - <p>The last (local) time the file was read.</p> + <p>The last time the file was read.</p> </item> - <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso></c></tag> + <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso> | integer()</c></tag> <item> - <p>The last (local) time the file was written.</p> + <p>The last time the file was written.</p> </item> - <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso></c></tag> + <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso> | integer()</c></tag> <item> <p>On Unix, any value give for this field will be ignored (the "ctime" for the file will be set to the current diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml index 418bfae4b8..579b7f1f74 100644 --- a/lib/kernel/doc/src/gen_sctp.xml +++ b/lib/kernel/doc/src/gen_sctp.xml @@ -270,7 +270,7 @@ it is bound to.</p> <p>For type <c>seqpacket</c> sockets (the default) <c><anno>IsServer</anno></c> must be <c>true</c> or <c>false</c>. - In the contrast to TCP, in SCTP there is no listening queue length. + In contrast to TCP, in SCTP there is no listening queue length. If <c><anno>IsServer</anno></c> is <c>true</c> the socket accepts new associations, i.e. it will become an SCTP server socket.</p> <p>For type <c>stream</c> sockets <anno>Backlog</anno> defines diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index fad5af85bb..1a05b4ba99 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -573,6 +573,10 @@ fe80::204:acff:fe17:bf38 is longer than the max allowed length, the packet is considered invalid. The same happens if the packet header is too big for the socket receive buffer.</p> + <p>For line oriented protocols (<c>line</c>,<c>http*</c>), + option <c>packet_size</c> also guarantees that lines up to the + indicated length are accepted and not considered invalid due + to internal buffer limitations.</p> </item> <tag><c>{read_packets, Integer}</c>(UDP sockets)</tag> <item> diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index ec57b03bd9..9121186631 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -30,6 +30,241 @@ </header> <p>This document describes the changes made to the Kernel application.</p> +<section><title>Kernel 2.15</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> Calls to <c>global:whereis_name/1</c> have been + substituted for calls to + <c>global:safe_whereis_name/1</c> since the latter is not + safe at all.</p> + <p>The reason for not doing this earlier is that setting + a global lock masked out a bug concerning the restart of + supervised children. The bug has now been fixed by a + modification of <c>global:whereis_name/1</c>. (Thanks to + Ulf Wiger for code contribution.)</p> + <p>A minor race conditions in <c>gen_fsm:start*</c> has + been fixed: if one of these functions returned <c>{error, + Reason}</c> or ignore, the name could still be registered + (either locally or in <c>global</c>. (This is the same + modification as was done for gen_server in OTP-7669.)</p> + <p>The undocumented function + <c>global:safe_whereis_name/1</c> has been removed. </p> + <p> + Own Id: OTP-9212 Aux Id: seq7117, OTP-4174 </p> + </item> + <item> + <p> + Honor option <c>packet_size</c> for http packet parsing + by both TCP socket and <c>erlang:decode_packet</c>. This + gives the ability to accept HTTP headers larger than the + default setting, but also avoid DoS attacks by accepting + lines only up to whatever length you wish to allow. For + consistency, packet type <c>line</c> also honor option + <c>packet_size</c>. (Thanks to Steve Vinoski)</p> + <p> + Own Id: OTP-9389</p> + </item> + <item> + <p> <c>disk_log:reopen/2,3</c> and + <c>disk_log:breopen/3</c> could return the error reason + from <c>file:rename/2</c> rather than the reason + <c>{file_error, Filename, Reason}</c>. This bug has been + fixed. </p> <p> The message <c>{disk_log, Node, {error, + disk_log_stopped}}</c> which according the documentation + is sent upon failure to truncate or reopen a disk log was + sometimes turned into a reply. This bug has been fixed. + </p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9508</p> + </item> + <item> + <p> + Environment variable 'shutdown_timeout' is added to + kernel application. Earlier, application_controller would + hang forever if an application top supervisor did not + terminate upon a shutdown request. If this new + environment variable is set to a positive integer T, then + application controller will now give up after T + milliseconds and instead brutally kill the application. + For backwards compatibility, the default value for + shutdown_timeout is 'infinity'.</p> + <p> + Own Id: OTP-9540</p> + </item> + <item> + <p> + Add '-callback' attributes in stdlib's behaviours</p> + <p> + Replace the behaviour_info(callbacks) export in stdlib's + behaviours with -callback' attributes for all the + callbacks. Update the documentation with information on + the callback attribute Automatically generate + 'behaviour_info' function from '-callback' attributes</p> + <p> + 'behaviour_info(callbacks)' is a special function that is + defined in a module which describes a behaviour and + returns a list of its callbacks.</p> + <p> + This function is now automatically generated using the + '-callback' specs. An error is returned by lint if user + defines both '-callback' attributes and the + behaviour_info/1 function. If no type info is needed for + a callback use a generic spec for it. Add '-callback' + attribute to language syntax</p> + <p> + Behaviours may define specs for their callbacks using the + familiar spec syntax, replacing the '-spec' keyword with + '-callback'. Simple lint checks are performed to ensure + that no callbacks are defined twice and all types + referred are declared.</p> + <p> + These attributes can be then used by tools to provide + documentation to the behaviour or find discrepancies in + the callback definitions in the callback module.</p> + <p> + Add callback specs into 'application' module in kernel + Add callback specs to tftp module following internet + documentation Add callback specs to inets_service module + following possibly deprecated comments</p> + <p> + Own Id: OTP-9621</p> + </item> + <item> + <p> + make tab completion work in remote shells (Thanks to Mats + Cronqvist)</p> + <p> + Own Id: OTP-9673</p> + </item> + <item> + <p> + Add missing parenthesis in heart doc.</p> + <p> + Add missing spaces in the Reference Manual distributed + section.</p> + <p> + In the HTML version of the doc those spaces are necessary + to separate those words.</p> + <p> + Own Id: OTP-9693</p> + </item> + <item> + <p> + Fixes net_kernel:get_net_ticktime() doc</p> + <p> + Adds missing description when `ignored' is returned. + (Thanks to Ricardo Catalinas Jim�nez )</p> + <p> + Own Id: OTP-9713</p> + </item> + <item> + <p> While <c>disk_log</c> eagerly collects logged terms + for better performance, collecting too much data may + choke the system and cause huge binaries to be written. + In order to remedy the situation a (small) limit on the + amount of data that is collected before writing to disk + has been introduced. </p> + <p> + Own Id: OTP-9764</p> + </item> + <item> + <p> + <list> <item><p>Correct callback spec in application + module</p></item> <item><p>Refine warning about callback + specs with extra ranges</p></item> <item><p>Cleanup + autoimport compiler directives</p></item> <item><p>Fix + Dialyzer's warnings in typer</p></item> <item><p>Fix + Dialyzer's warning for its own code</p></item> + <item><p>Fix bug in Dialyzer's behaviours + analysis</p></item> <item><p>Fix crash in + Dialyzer</p></item> <item><p>Variable substitution was + not generalizing any unknown variables.</p></item> + </list></p> + <p> + Own Id: OTP-9776</p> + </item> + <item> + <p> + Fix a crash when file:change_time/2,3 are called with + invalid dates</p> + <p> + Calling file:change_time/2,3 with an invalid date tuple + (e.g file:change_time("file.txt", {undefined, + undefined})) will cause file_server_2 to crash. + error_logger will shutdown and the whole VM will stop. + Change behavior to validate given dates on system + boundaries. (i.e before issuing a server call).(Thanks to + Ahmed Omar)</p> + <p> + Own Id: OTP-9785</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> An option list argument can now be passed to + <c>file:read_file_info/2, file:read_link_info/2</c> and + <c>file:write_file_info/3</c> and set time type + information in the call. Valid options are <c>{time, + local}, {time, universal}</c> and <c>{time, posix}</c>. + In the case of <c>posix</c> time no conversions are made + which makes the operation a bit faster. </p> + <p> + Own Id: OTP-7687</p> + </item> + <item> + <p><c>file:list_dir/1,2</c> will now fill an buffer + entire with filenames from the efile driver before + sending it to an erlang process. This will speed up this + file operation in most cases.</p> + <p> + Own Id: OTP-9023</p> + </item> + <item> + <p>gen_sctp:open/0-2 may now return + {error,eprotonosupport} if SCTP is not supported</p> + <p>gen_sctp:peeloff/1 has been implemented and creates a + one-to-one socket which also are supported now</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-9239</p> + </item> + <item> + <p> + Sendfile has been added to the file module's API. + sendfile/2 is used to read data from a file and send it + to a tcp socket using a zero copying mechanism if + available on that OS.</p> + <p> + Thanks to Tuncer Ayaz and Steve Vinovski for original + implementation</p> + <p> + Own Id: OTP-9240</p> + </item> + <item> + <p> + Tuple funs (a two-element tuple with a module name and a + function) are now officially deprecated and will be + removed in R16. Use '<c>fun M:F/A</c>' instead. To make + you aware that your system uses tuple funs, the very + first time a tuple fun is applied, a warning will be sent + to the error logger.</p> + <p> + Own Id: OTP-9649</p> + </item> + </list> + </section> + +</section> + <section><title>Kernel 2.14.5</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/kernel/include/dist.hrl b/lib/kernel/include/dist.hrl index aea1ab81ba..5b52f6f294 100644 --- a/lib/kernel/include/dist.hrl +++ b/lib/kernel/include/dist.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/kernel/include/dist_util.hrl b/lib/kernel/include/dist_util.hrl index f2b0598532..c3a7f97418 100644 --- a/lib/kernel/include/dist_util.hrl +++ b/lib/kernel/include/dist_util.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/kernel/include/file.hrl b/lib/kernel/include/file.hrl index 3889bce393..bf97173122 100644 --- a/lib/kernel/include/file.hrl +++ b/lib/kernel/include/file.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,10 +25,11 @@ {size :: non_neg_integer(), % Size of file in bytes. type :: 'device' | 'directory' | 'other' | 'regular' | 'symlink', access :: 'read' | 'write' | 'read_write' | 'none', - atime :: file:date_time(), % The local time the file was last read: - % {{Year, Mon, Day}, {Hour, Min, Sec}}. - mtime :: file:date_time(), % The local time the file was last written. - ctime :: file:date_time(), % The interpretation of this time field + atime :: file:date_time() | integer(), % The local time the file was last read: + % {{Year, Mon, Day}, {Hour, Min, Sec}}. + % atime, ctime, mtime may also be unix epochs() + mtime :: file:date_time() | integer(), % The local time the file was last written. + ctime :: file:date_time() | integer(), % The interpretation of this time field % is dependent on operating system. % On Unix it is the last time the file % or the inode was changed. On Windows, diff --git a/lib/kernel/include/net_address.hrl b/lib/kernel/include/net_address.hrl index 5342076507..9b9ea42931 100644 --- a/lib/kernel/include/net_address.hrl +++ b/lib/kernel/include/net_address.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile index 02be6b5036..54f21eb2b8 100644 --- a/lib/kernel/src/Makefile +++ b/lib/kernel/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2010. All Rights Reserved. +# Copyright Ericsson AB 1996-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl index caac4d926c..c299fb085c 100644 --- a/lib/kernel/src/application.erl +++ b/lib/kernel/src/application.erl @@ -59,7 +59,7 @@ -callback start(StartType :: normal | {takeover, node()} | {failover, node()}, StartArgs :: term()) -> - {ok, pid()} | {ok, pid(), State :: term()} | {error, Reason :: term}. + {'ok', pid()} | {'ok', pid(), State :: term()} | {'error', Reason :: term()}. -callback stop(State :: term()) -> term(). diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index 882e9625fe..b7fda69ce0 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -324,15 +324,7 @@ start_link(Flags) -> %%----------------------------------------------------------------- do_start(Flags) -> - %% The following module_info/1 calls are here to ensure - %% that these modules are loaded prior to their use elsewhere in - %% the code_server. - %% Otherwise a deadlock may occur when the code_server is starting. - code_server = code_server:module_info(module), - packages = packages:module_info(module), - catch hipe_unified_loader:load_hipe_modules(), - Modules2 = [gb_sets, gb_trees, ets, os, binary, unicode, filename, lists], - lists:foreach(fun (M) -> M = M:module_info(module) end, Modules2), + load_code_server_prerequisites(), Mode = get_mode(Flags), case init:get_argument(root) of @@ -360,6 +352,25 @@ do_start(Flags) -> {error, crash} end. +%% Make sure that all modules that the code_server process calls +%% (directly or indirectly) are loaded. Otherwise the code_server +%% process will deadlock. + +load_code_server_prerequisites() -> + %% Please keep the alphabetical order. + Needed = [binary, + ets, + filename, + gb_sets, + gb_trees, + hipe_unified_loader, + lists, + os, + packages, + unicode], + [M = M:module_info(module) || M <- Needed], + ok. + do_stick_dirs() -> do_s(compiler), do_s(stdlib), diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index 32a12e2b52..5d4f2eb70c 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -1317,15 +1317,21 @@ int_list([H|T]) when is_integer(H) -> int_list(T); int_list([_|_]) -> false; int_list([]) -> true. +load_file(Mod0, {From,_}=Caller, St0) -> + Mod = to_atom(Mod0), + case pending_on_load(Mod, From, St0) of + no -> load_file_1(Mod, Caller, St0); + {yes,St} -> {noreply,St} + end. -load_file(Mod, Caller, #state{path=Path,cache=no_cache}=St) -> +load_file_1(Mod, Caller, #state{path=Path,cache=no_cache}=St) -> case mod_to_bin(Path, Mod) of error -> {reply,{error,nofile},St}; {Mod,Binary,File} -> try_load_module(File, Mod, Binary, Caller, St) end; -load_file(Mod, Caller, #state{cache=Cache}=St0) -> +load_file_1(Mod, Caller, #state{cache=Cache}=St0) -> Key = {obj,Mod}, case ets:lookup(Cache, Key) of [] -> diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl index d6bc23be6d..fb9415d440 100644 --- a/lib/kernel/src/disk_log.erl +++ b/lib/kernel/src/disk_log.erl @@ -64,7 +64,7 @@ %%-define(PROFILE(C), C). -define(PROFILE(C), void). --compile({inline,[{log_loop,4},{log_end_sync,2},{replies,2},{rflat,1}]}). +-compile({inline,[{log_loop,5},{log_end_sync,2},{replies,2},{rflat,1}]}). %%%---------------------------------------------------------------------- %%% Contract type specifications @@ -685,7 +685,7 @@ handle({From, {log, B}}, S) -> L when L#log.mode =:= read_only -> reply(From, {error, {read_only_mode, L#log.name}}, S); L when L#log.status =:= ok, L#log.format =:= internal -> - log_loop(S, From, [B], []); + log_loop(S, From, [B], [], iolist_size(B)); L when L#log.status =:= ok, L#log.format =:= external -> reply(From, {error, {format_external, L#log.name}}, S); L when L#log.status =:= {blocked, false} -> @@ -700,7 +700,7 @@ handle({From, {blog, B}}, S) -> L when L#log.mode =:= read_only -> reply(From, {error, {read_only_mode, L#log.name}}, S); L when L#log.status =:= ok -> - log_loop(S, From, [B], []); + log_loop(S, From, [B], [], iolist_size(B)); L when L#log.status =:= {blocked, false} -> reply(From, {error, {blocked_log, L#log.name}}, S); L when L#log.blocked_by =:= From -> @@ -714,7 +714,7 @@ handle({alog, B}, S) -> notify_owners({read_only,B}), loop(S); L when L#log.status =:= ok, L#log.format =:= internal -> - log_loop(S, [], [B], []); + log_loop(S, [], [B], [], iolist_size(B)); L when L#log.status =:= ok -> notify_owners({format_external, B}), loop(S); @@ -730,7 +730,7 @@ handle({balog, B}, S) -> notify_owners({read_only,B}), loop(S); L when L#log.status =:= ok -> - log_loop(S, [], [B], []); + log_loop(S, [], [B], [], iolist_size(B)); L when L#log.status =:= {blocked, false} -> notify_owners({blocked_log, B}), loop(S); @@ -1029,38 +1029,42 @@ handle(_, S) -> loop(S). sync_loop(From, S) -> - log_loop(S, [], [], From). + log_loop(S, [], [], From, 0). + +-define(MAX_LOOK_AHEAD, 64*1024). %% Inlined. -log_loop(S, Pids, _Bins, _Sync) when S#state.cache_error =/= ok -> +log_loop(S, Pids, _Bins, _Sync, _Sz) when S#state.cache_error =/= ok -> loop(cache_error(S, Pids)); -log_loop(S, Pids, Bins, Sync) when S#state.messages =:= [] -> +log_loop(#state{messages = []}=S, Pids, Bins, Sync, Sz) + when Sz > ?MAX_LOOK_AHEAD -> + loop(log_end(S, Pids, Bins, Sync)); +log_loop(#state{messages = []}=S, Pids, Bins, Sync, Sz) -> receive Message -> - log_loop(Message, Pids, Bins, Sync, S, get(log)) + log_loop(Message, Pids, Bins, Sync, Sz, S, get(log)) after 0 -> loop(log_end(S, Pids, Bins, Sync)) end; -log_loop(S, Pids, Bins, Sync) -> +log_loop(S, Pids, Bins, Sync, Sz) -> [M | Ms] = S#state.messages, S1 = S#state{messages = Ms}, - log_loop(M, Pids, Bins, Sync, S1, get(log)). + log_loop(M, Pids, Bins, Sync, Sz, S1, get(log)). %% Items logged after the last sync request found are sync:ed as well. -log_loop({alog,B}, Pids, Bins, Sync, S, L) when L#log.format =:= internal -> +log_loop({alog,B}, Pids, Bins, Sync, Sz, S, #log{format = internal}) -> %% {alog, _} allowed for the internal format only. - log_loop(S, Pids, [B | Bins], Sync); -log_loop({balog, B}, Pids, Bins, Sync, S, _L) -> - log_loop(S, Pids, [B | Bins], Sync); -log_loop({From, {log, B}}, Pids, Bins, Sync, S, L) - when L#log.format =:= internal -> + log_loop(S, Pids, [B | Bins], Sync, Sz+iolist_size(B)); +log_loop({balog, B}, Pids, Bins, Sync, Sz, S, _L) -> + log_loop(S, Pids, [B | Bins], Sync, Sz+iolist_size(B)); +log_loop({From, {log, B}}, Pids, Bins, Sync, Sz, S, #log{format = internal}) -> %% {log, _} allowed for the internal format only. - log_loop(S, [From | Pids], [B | Bins], Sync); -log_loop({From, {blog, B}}, Pids, Bins, Sync, S, _L) -> - log_loop(S, [From | Pids], [B | Bins], Sync); -log_loop({From, sync}, Pids, Bins, Sync, S, _L) -> - log_loop(S, Pids, Bins, [From | Sync]); -log_loop(Message, Pids, Bins, Sync, S, _L) -> + log_loop(S, [From | Pids], [B | Bins], Sync, Sz+iolist_size(B)); +log_loop({From, {blog, B}}, Pids, Bins, Sync, Sz, S, _L) -> + log_loop(S, [From | Pids], [B | Bins], Sync, Sz+iolist_size(B)); +log_loop({From, sync}, Pids, Bins, Sync, Sz, S, _L) -> + log_loop(S, Pids, Bins, [From | Sync], Sz); +log_loop(Message, Pids, Bins, Sync, _Sz, S, _L) -> NS = log_end(S, Pids, Bins, Sync), handle(Message, NS). diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 706c60caaf..4028dd4f0b 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -28,9 +28,11 @@ %% File system and metadata. -export([get_cwd/0, get_cwd/1, set_cwd/1, delete/1, rename/2, make_dir/1, del_dir/1, list_dir/1, - read_file_info/1, write_file_info/2, + read_file_info/1, read_file_info/2, + write_file_info/2, write_file_info/3, altname/1, - read_link_info/1, read_link/1, + read_link_info/1, read_link_info/2, + read_link/1, make_link/2, make_symlink/2, read_file/1, write_file/2, write_file/3]). %% Specialized @@ -51,6 +53,9 @@ -export([pid2name/1]). +%% Sendfile functions +-export([sendfile/2,sendfile/5]). + %%% Obsolete exported functions -export([raw_read_file_info/1, raw_write_file_info/2]). @@ -103,6 +108,10 @@ -type date_time() :: calendar:datetime(). -type posix_file_advise() :: 'normal' | 'sequential' | 'random' | 'no_reuse' | 'will_need' | 'dont_need'. +-type sendfile_option() :: {chunk_size, non_neg_integer()}. +-type file_info_option() :: {'time', 'local'} | {'time', 'universal'} + | {'time', 'posix'}. + %%%----------------------------------------------------------------- %%% General functions @@ -211,6 +220,15 @@ del_dir(Name) -> read_file_info(Name) -> check_and_call(read_file_info, [file_name(Name)]). +-spec read_file_info(Filename, Opts) -> {ok, FileInfo} | {error, Reason} when + Filename :: name(), + Opts :: [file_info_option()], + FileInfo :: file_info(), + Reason :: posix() | badarg. + +read_file_info(Name, Opts) when is_list(Opts) -> + check_and_call(read_file_info, [file_name(Name), Opts]). + -spec altname(Name :: name()) -> any(). altname(Name) -> @@ -224,6 +242,16 @@ altname(Name) -> read_link_info(Name) -> check_and_call(read_link_info, [file_name(Name)]). +-spec read_link_info(Name, Opts) -> {ok, FileInfo} | {error, Reason} when + Name :: name(), + Opts :: [file_info_option()], + FileInfo :: file_info(), + Reason :: posix() | badarg. + +read_link_info(Name, Opts) when is_list(Opts) -> + check_and_call(read_link_info, [file_name(Name),Opts]). + + -spec read_link(Name) -> {ok, Filename} | {error, Reason} when Name :: name(), Filename :: filename(), @@ -240,6 +268,15 @@ read_link(Name) -> write_file_info(Name, Info = #file_info{}) -> check_and_call(write_file_info, [file_name(Name), Info]). +-spec write_file_info(Filename, FileInfo, Opts) -> ok | {error, Reason} when + Filename :: name(), + Opts :: [file_info_option()], + FileInfo :: file_info(), + Reason :: posix() | badarg. + +write_file_info(Name, Info = #file_info{}, Opts) when is_list(Opts) -> + check_and_call(write_file_info, [file_name(Name), Info, Opts]). + -spec list_dir(Dir) -> {ok, Filenames} | {error, Reason} when Dir :: name(), Filenames :: [filename()], @@ -264,9 +301,9 @@ read_file(Name) -> make_link(Old, New) -> check_and_call(make_link, [file_name(Old), file_name(New)]). --spec make_symlink(Name1, Name2) -> ok | {error, Reason} when - Name1 :: name(), - Name2 :: name(), +-spec make_symlink(Existing, New) -> ok | {error, Reason} when + Existing :: name(), + New :: name(), Reason :: posix() | badarg. make_symlink(Old, New) -> @@ -1100,8 +1137,9 @@ change_group(Name, GroupId) Mtime :: date_time(), Reason :: posix() | badarg. -change_time(Name, Time) - when is_tuple(Time) -> +change_time(Name, {{Y, M, D}, {H, Min, Sec}}=Time) + when is_integer(Y), is_integer(M), is_integer(D), + is_integer(H), is_integer(Min), is_integer(Sec)-> write_file_info(Name, #file_info{mtime=Time}). -spec change_time(Filename, Atime, Mtime) -> ok | {error, Reason} when @@ -1110,10 +1148,150 @@ change_time(Name, Time) Mtime :: date_time(), Reason :: posix() | badarg. -change_time(Name, Atime, Mtime) - when is_tuple(Atime), is_tuple(Mtime) -> +change_time(Name, {{AY, AM, AD}, {AH, AMin, ASec}}=Atime, + {{MY, MM, MD}, {MH, MMin, MSec}}=Mtime) + when is_integer(AY), is_integer(AM), is_integer(AD), + is_integer(AH), is_integer(AMin), is_integer(ASec), + is_integer(MY), is_integer(MM), is_integer(MD), + is_integer(MH), is_integer(MMin), is_integer(MSec)-> write_file_info(Name, #file_info{atime=Atime, mtime=Mtime}). +%% +%% Send data using sendfile +%% + +-define(MAX_CHUNK_SIZE, (1 bsl 20)*20). %% 20 MB, has to fit in primary memory + +-spec sendfile(RawFile, Socket, Offset, Bytes, Opts) -> + {'ok', non_neg_integer()} | {'error', inet:posix() | + closed | badarg | not_owner} when + RawFile :: file:fd(), + Socket :: inet:socket(), + Offset :: non_neg_integer(), + Bytes :: non_neg_integer(), + Opts :: [sendfile_option()]. +sendfile(File, _Sock, _Offet, _Bytes, _Opts) when is_pid(File) -> + {error, badarg}; +sendfile(File, Sock, Offset, Bytes, []) -> + sendfile(File, Sock, Offset, Bytes, ?MAX_CHUNK_SIZE, [], [], + false, false, false); +sendfile(File, Sock, Offset, Bytes, Opts) -> + ChunkSize0 = proplists:get_value(chunk_size, Opts, ?MAX_CHUNK_SIZE), + ChunkSize = if ChunkSize0 > ?MAX_CHUNK_SIZE -> + ?MAX_CHUNK_SIZE; + true -> ChunkSize0 + end, + %% Support for headers, trailers and options has been removed because the + %% Darwin and BSD API for using it does not play nice with + %% non-blocking sockets. See unix_efile.c for more info. + sendfile(File, Sock, Offset, Bytes, ChunkSize, [], [], + false,false,false). + +%% sendfile/2 +-spec sendfile(Filename, Socket) -> + {'ok', non_neg_integer()} | {'error', inet:posix() | + closed | badarg | not_owner} + when Filename :: file:name(), + Socket :: inet:socket(). +sendfile(Filename, Sock) -> + case file:open(Filename, [read, raw, binary]) of + {error, Reason} -> + {error, Reason}; + {ok, Fd} -> + Res = sendfile(Fd, Sock, 0, 0, []), + file:close(Fd), + Res + end. + +%% Internal sendfile functions +sendfile(#file_descriptor{ module = Mod } = Fd, Sock, Offset, Bytes, + ChunkSize, Headers, Trailers, Nodiskio, MNowait, Sync) + when is_port(Sock) -> + case Mod:sendfile(Fd, Sock, Offset, Bytes, ChunkSize, Headers, Trailers, + Nodiskio, MNowait, Sync) of + {error, enotsup} -> + sendfile_fallback(Fd, Sock, Offset, Bytes, ChunkSize, + Headers, Trailers); + Else -> + Else + end; +sendfile(_,_,_,_,_,_,_,_,_,_) -> + {error, badarg}. + +%%% +%% Sendfile Fallback +%%% +sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, + Headers, Trailers) + when Headers == []; is_integer(Headers) -> + case sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) of + {ok, BytesSent} when is_list(Trailers), + Trailers =/= [], + is_integer(Headers) -> + sendfile_send(Sock, Trailers, BytesSent+Headers); + {ok, BytesSent} when is_list(Trailers), Trailers =/= [] -> + sendfile_send(Sock, Trailers, BytesSent); + {ok, BytesSent} when is_integer(Headers) -> + {ok, BytesSent + Headers}; + Else -> + Else + end; +sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, Headers, Trailers) -> + case sendfile_send(Sock, Headers, 0) of + {ok, BytesSent} -> + sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize, BytesSent, + Trailers); + Else -> + Else + end. + + +sendfile_fallback(File, Sock, Offset, Bytes, ChunkSize) -> + {ok, CurrPos} = file:position(File, {cur, 0}), + {ok, _NewPos} = file:position(File, {bof, Offset}), + Res = sendfile_fallback_int(File, Sock, Bytes, ChunkSize, 0), + file:position(File, {bof, CurrPos}), + Res. + + +sendfile_fallback_int(File, Sock, Bytes, ChunkSize, BytesSent) + when Bytes > BytesSent; Bytes == 0 -> + Size = if Bytes == 0 -> + ChunkSize; + (Bytes - BytesSent + ChunkSize) > 0 -> + Bytes - BytesSent; + true -> + ChunkSize + end, + case file:read(File, Size) of + {ok, Data} -> + case sendfile_send(Sock, Data, BytesSent) of + {ok,NewBytesSent} -> + sendfile_fallback_int( + File, Sock, Bytes, ChunkSize, + NewBytesSent); + Error -> + Error + end; + eof -> + {ok, BytesSent}; + Error -> + Error + end; +sendfile_fallback_int(_File, _Sock, BytesSent, _ChunkSize, BytesSent) -> + {ok, BytesSent}. + +sendfile_send(Sock, Data, Old) -> + Len = iolist_size(Data), + case gen_tcp:send(Sock, Data) of + ok -> + {ok, Len+Old}; + Else -> + Else + end. + + + %%%----------------------------------------------------------------- %%% Helpers diff --git a/lib/kernel/src/file_server.erl b/lib/kernel/src/file_server.erl index 64c61ba3ac..fc6cd823c9 100644 --- a/lib/kernel/src/file_server.erl +++ b/lib/kernel/src/file_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2010. All Rights Reserved. +%% Copyright Ericsson AB 2000-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -147,15 +147,24 @@ handle_call({get_cwd, Name}, _From, Handle) -> handle_call({read_file_info, Name}, _From, Handle) -> {reply, ?PRIM_FILE:read_file_info(Handle, Name), Handle}; +handle_call({read_file_info, Name, Opts}, _From, Handle) -> + {reply, ?PRIM_FILE:read_file_info(Handle, Name, Opts), Handle}; + handle_call({altname, Name}, _From, Handle) -> {reply, ?PRIM_FILE:altname(Handle, Name), Handle}; handle_call({write_file_info, Name, Info}, _From, Handle) -> {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info), Handle}; +handle_call({write_file_info, Name, Info, Opts}, _From, Handle) -> + {reply, ?PRIM_FILE:write_file_info(Handle, Name, Info, Opts), Handle}; + handle_call({read_link_info, Name}, _From, Handle) -> {reply, ?PRIM_FILE:read_link_info(Handle, Name), Handle}; +handle_call({read_link_info, Name, Opts}, _From, Handle) -> + {reply, ?PRIM_FILE:read_link_info(Handle, Name, Opts), Handle}; + handle_call({read_link, Name}, _From, Handle) -> {reply, ?PRIM_FILE:read_link(Handle, Name), Handle}; diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index 77ca26b845..d8954f0cf7 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -314,7 +314,7 @@ eof_or_abort(S, AssocId, Action) -> -spec send(Socket, SndRcvInfo, Data) -> ok | {error, Reason} when Socket :: sctp_socket(), SndRcvInfo :: #sctp_sndrcvinfo{}, - Data :: binary | iolist(), + Data :: binary() | iolist(), Reason :: term(). %% Full-featured send. Rarely needed. @@ -331,7 +331,7 @@ send(S, SRI, Data) -> Socket :: sctp_socket(), Assoc :: #sctp_assoc_change{} | assoc_id(), Stream :: integer(), - Data :: binary | iolist(), + Data :: binary() | iolist(), Reason :: term(). send(S, #sctp_assoc_change{assoc_id=AssocId}, Stream, Data) diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl index 8ab18c01b4..4d6c7f5f1d 100644 --- a/lib/kernel/src/gen_tcp.erl +++ b/lib/kernel/src/gen_tcp.erl @@ -27,6 +27,7 @@ -export([fdopen/2]). -include("inet_int.hrl"). +-include("file.hrl"). -type option() :: {active, true | false | once} | @@ -302,7 +303,7 @@ unrecv(S, Data) when is_port(S) -> Mod:unrecv(S, Data); Error -> Error - end. + end. %% %% Set controlling process @@ -354,3 +355,4 @@ mod([_|Opts], Address) -> mod(Opts, Address); mod([], Address) -> mod(Address). + diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl index 1d3eb926ca..8b3aa0286d 100644 --- a/lib/kernel/src/hipe_unified_loader.erl +++ b/lib/kernel/src/hipe_unified_loader.erl @@ -36,7 +36,6 @@ -export([chunk_name/1, %% Only the code and code_server modules may call the entries below! - load_hipe_modules/0, load_native_code/2, post_beam_load/1, load_module/3, @@ -78,16 +77,6 @@ chunk_name(Architecture) -> %%======================================================================== --spec load_hipe_modules() -> 'ok'. -%% @doc -%% Ensures HiPE's loader modules are loaded. -%% Called from code.erl at start-up. - -load_hipe_modules() -> - ok. - -%%======================================================================== - -spec load_native_code(Mod, binary()) -> 'no_native' | {'module', Mod} when is_subtype(Mod, atom()). %% @doc diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index b60c68e3a1..49f64a9236 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -40,6 +40,10 @@ -export([tcp_controlling_process/2, udp_controlling_process/2, tcp_close/1, udp_close/1]). + +%% used by sendfile +-export([lock_socket/2]). + %% used by socks5 -export([setsockname/2, setpeername/2]). @@ -1353,3 +1357,14 @@ stop_timer(Timer) -> end; T -> T end. + + +lock_socket(S,Val) -> + case erlang:port_info(S, connected) of + {connected, Pid} when Pid =/= self() -> + {error, not_owner}; + undefined -> + {error, einval}; + _ -> + prim_inet:ignorefd(S,Val) + end. diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index f8984b13fe..cf893c73eb 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -85,6 +85,8 @@ -define(INET_REQ_GETIFADDRS, 25). -define(INET_REQ_ACCEPT, 26). -define(INET_REQ_LISTEN, 27). +-define(INET_REQ_IGNOREFD, 28). + %% TCP requests %%-define(TCP_REQ_ACCEPT, 40). MOVED %%-define(TCP_REQ_LISTEN, 41). MERGED diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl index e33b4830ab..8f2ca28f56 100644 --- a/lib/kernel/src/user_drv.erl +++ b/lib/kernel/src/user_drv.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/kernel/src/user_sup.erl b/lib/kernel/src/user_sup.erl index 35b7ff0cfe..cb50d9491d 100644 --- a/lib/kernel/src/user_sup.erl +++ b/lib/kernel/src/user_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -45,7 +45,7 @@ init([]) -> Pid = start_slave(Master), {ok, Pid, Pid}; {M, F, A} -> - case start_user({M, F}, A) of + case start_user(M, F, A) of {ok, Pid} -> {ok, Pid, Pid}; Error -> @@ -95,8 +95,8 @@ terminate(_Reason, UserPid) -> %% is guaranteed that the user is started. %%----------------------------------------------------------------- -start_user(Func,A) -> - apply(Func, A), +start_user(Mod, Func, A) -> + apply(Mod, Func, A), wait_for_user_p(100). wait_for_user_p(0) -> diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index 82bc3fc6d1..5dcaad3f5e 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -74,7 +74,8 @@ MODULES= \ wrap_log_reader_SUITE \ cleanup \ zlib_SUITE \ - loose_node + loose_node \ + sendfile_SUITE APP_FILES = \ appinc.app \ diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 10ab3e4370..99b0cd2ffb 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -30,9 +30,9 @@ load_cached/1, start_node_with_cache/1, add_and_rehash/1, where_is_file_cached/1, where_is_file_no_cache/1, purge_stacktrace/1, mult_lib_roots/1, bad_erl_libs/1, - code_archive/1, code_archive2/1, on_load/1, - big_boot_embedded/1, - on_load_embedded/1, on_load_errors/1, native_early_modules/1]). + code_archive/1, code_archive2/1, on_load/1, on_load_binary/1, + on_load_embedded/1, on_load_errors/1, big_boot_embedded/1, + native_early_modules/1]). -export([init_per_testcase/2, end_per_testcase/2, init_per_suite/1, end_per_suite/1, @@ -55,8 +55,8 @@ all() -> add_and_rehash, where_is_file_no_cache, where_is_file_cached, purge_stacktrace, mult_lib_roots, bad_erl_libs, code_archive, code_archive2, on_load, - on_load_embedded, big_boot_embedded, on_load_errors, - native_early_modules]. + on_load_binary, on_load_embedded, on_load_errors, + big_boot_embedded, native_early_modules]. groups() -> []. @@ -1286,6 +1286,45 @@ on_load_wait_for_all([Ref|T]) -> end; on_load_wait_for_all([]) -> ok. +on_load_binary(_) -> + Master = on_load_binary_test_case_process, + register(Master, self()), + + %% Construct, compile and pretty-print. + Mod = on_load_binary, + File = atom_to_list(Mod) ++ ".erl", + Forms = [{attribute,1,file,{File,1}}, + {attribute,1,module,Mod}, + {attribute,2,export,[{ok,0}]}, + {attribute,3,on_load,{init,0}}, + {function,5,init,0, + [{clause,5,[],[], + [{op,6,'!', + {atom,6,Master}, + {tuple,6,[{atom,6,Mod},{call,6,{atom,6,self},[]}]}}, + {'receive',7,[{clause,8,[{atom,8,go}],[],[{atom,8,ok}]}]}]}]}, + {function,11,ok,0,[{clause,11,[],[],[{atom,11,true}]}]}], + {ok,Mod,Bin} = compile:forms(Forms, [report]), + [io:put_chars(erl_pp:form(F)) || F <- Forms], + + {Pid1,Ref1} = spawn_monitor(fun() -> + code:load_binary(Mod, File, Bin), + true = on_load_binary:ok() + end), + receive {Mod,OnLoadPid} -> ok end, + {Pid2,Ref2} = spawn_monitor(fun() -> + true = on_load_binary:ok() + end), + erlang:yield(), + OnLoadPid ! go, + receive {'DOWN',Ref1,process,Pid1,Exit1} -> ok end, + receive {'DOWN',Ref2,process,Pid2,Exit2} -> ok end, + normal = Exit1, + normal = Exit2, + true = code:delete(on_load_binary), + false = code:purge(on_load_binary), + ok. + on_load_embedded(Config) when is_list(Config) -> try on_load_embedded_1(Config) diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl index 7599a89779..d0d52c5ea7 100644 --- a/lib/kernel/test/erl_prim_loader_SUITE.erl +++ b/lib/kernel/test/erl_prim_loader_SUITE.erl @@ -175,10 +175,10 @@ wait_really_started(Node, N) -> inet_disconnects(doc) -> ["Start a node using the 'inet' loading method, ", "then lose the connection."]; inet_disconnects(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "VxWorks: tested separately"}; - _ -> + case test_server:is_native(erl_boot_server) of + true -> + {skip,"erl_boot_server is native"}; + false -> ?line Name = erl_prim_test_inet_disconnects, ?line Host = host(), ?line Cookie = atom_to_list(erlang:get_cookie()), diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 77fc7e73f9..2b6af7e1fb 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -78,7 +78,7 @@ -export([altname/1]). --export([large_file/1]). +-export([large_file/1, large_write/1]). -export([read_line_1/1, read_line_2/1, read_line_3/1,read_line_4/1]). @@ -92,6 +92,8 @@ -export([bytes/2, iterate/3]). +%% System probe functions that might be handy to check from the shell +-export([disc_free/1, memsize/0]). -include_lib("test_server/include/test_server.hrl"). -include_lib("kernel/include/file.hrl"). @@ -106,7 +108,7 @@ all() -> {group, compression}, {group, links}, copy, delayed_write, read_ahead, segment_read, segment_write, ipread, pid2name, interleaved_read_write, otp_5814, - large_file, read_line_1, read_line_2, read_line_3, + large_file, large_write, read_line_1, read_line_2, read_line_3, read_line_4, standard_io]. groups() -> @@ -143,6 +145,13 @@ end_per_group(_GroupName, Config) -> init_per_suite(Config) when is_list(Config) -> + SaslConfig = case application:start(sasl) of + {error, {already_started, sasl}} -> + []; + ok -> + [{sasl,started}] + end, + ok = application:start(os_mon), case os:type() of {win32, _} -> Priv = ?config(priv_dir, Config), @@ -154,9 +163,9 @@ init_per_suite(Config) when is_list(Config) -> {ok, _} -> [] end, - ?FILE_INIT(HasAccessTime++Config); + ?FILE_INIT(HasAccessTime++Config++SaslConfig); _ -> - ?FILE_INIT(Config) + ?FILE_INIT(Config++SaslConfig) end. end_per_suite(Config) when is_list(Config) -> @@ -166,6 +175,13 @@ end_per_suite(Config) when is_list(Config) -> _ -> ok end, + application:stop(os_mon), + case proplists:get_value(sasl, Config) of + started -> + application:stop(sasl); + _Else -> + ok + end, ?FILE_FINI(Config). init_per_testcase(_Func, Config) -> @@ -394,6 +410,7 @@ make_del_dir(Config) when is_list(Config) -> %% Don't worry ;-) the parent directory should never be empty, right? ?line case ?FILE_MODULE:del_dir('..') of {error, eexist} -> ok; + {error, eacces} -> ok; %OpenBSD {error, einval} -> ok %FreeBSD end, ?line {error, enoent} = ?FILE_MODULE:del_dir(""), @@ -3144,12 +3161,12 @@ ipread_int(Dir, ModeList) -> {fun (Bin) when is_binary(Bin) -> Bin; (List) when is_list(List) -> list_to_binary(List) end, - {erlang, size}}; + fun erlang:byte_size/1}; false -> {fun (Bin) when is_binary(Bin) -> binary_to_list(Bin); (List) when is_list(List) -> List end, - {erlang, length}} + fun erlang:length/1} end, ?line Pos = 4711, ?line Data = Conv("THE QUICK BROWN FOX JUMPS OVER A LAZY DOG"), @@ -3287,50 +3304,13 @@ large_file(suite) -> large_file(doc) -> ["Tests positioning in large files (> 4G)"]; large_file(Config) when is_list(Config) -> - case {os:type(),os:version()} of - {{win32,nt},_} -> - do_large_file(Config); - {{unix,sunos},{A,B,C}} - when A == 5, B == 5, C >= 1; A == 5, B >= 6; A >= 6 -> - do_large_file(Config); - {{unix,Unix},_} when Unix =/= sunos -> - N = unix_free(Config), - io:format("Free: ~w KByte~n", [N]), - if N < 5 * (1 bsl 20) -> - %% Less than 5 GByte free - {skipped,"Less than 5 GByte free"}; - true -> - do_large_file(Config) - end; - _ -> - {skipped,"Only supported on Win32, Unix or SunOS >= 5.5.1"} - end. + run_large_file_test(Config, + fun(Name) -> do_large_file(Name) end, + "_large_file"). -unix_free(Config) -> - Cmd = ["df -k '",?config(priv_dir, Config),"'"], - DF0 = os:cmd(Cmd), - io:format("$ ~s~n~s", [Cmd,DF0]), - [$\n|DF1] = lists:dropwhile(fun ($\n) -> false; (_) -> true end, DF0), - {ok,[N],_} = io_lib:fread(" ~*s ~d", DF1), - N. +do_large_file(Name) -> + ?line Watchdog = ?t:timetrap(?t:minutes(20)), -do_large_file(Config) -> - ?line Watchdog = ?t:timetrap(?t:minutes(5)), - %% - ?line Name = filename:join(?config(priv_dir, Config), - ?MODULE_STRING ++ "_large_file"), - ?line Tester = self(), - Deleter = - spawn( - fun() -> - Mref = erlang:monitor(process, Tester), - receive - {'DOWN',Mref,_,_,_} -> ok; - {Tester,done} -> ok - end, - ?FILE_MODULE:delete(Name) - end), - %% ?line S = "1234567890", L = length(S), R = lists:reverse(S), @@ -3366,15 +3346,36 @@ do_large_file(Config) -> ?line {ok,R} = ?FILE_MODULE:read(F1, L+1), ?line ok = ?FILE_MODULE:close(F1), %% - ?line Mref = erlang:monitor(process, Deleter), - ?line Deleter ! {Tester,done}, - ?line receive {'DOWN',Mref,_,_,_} -> ok end, - %% ?line ?t:timetrap_cancel(Watchdog), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +large_write(Config) when is_list(Config) -> + run_large_file_test(Config, + fun(Name) -> do_large_write(Name) end, + "_large_write"). + +do_large_write(Name) -> + Memsize = memsize(), + io:format("Memsize = ~w Bytes~n", [Memsize]), + case {erlang:system_info(wordsize),Memsize} of + {4,_} -> + {skip,"Needs a 64-bit emulator"}; + {8,N} when N < 6 bsl 30 -> + {skip, + "This machine has < 6 GB memory: " + ++integer_to_list(N)}; + {8,_} -> + Size = 4*1024*1024*1024+1, + Bin = <<0:Size/unit:8>>, + ok = file:write_file(Name, Bin), + {ok,#file_info{size=Size}} = file:read_file_info(Name), + ok + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + response_analysis(Module, Function, Arguments) -> @@ -3950,3 +3951,67 @@ flush(Msgs) -> after 0 -> lists:reverse(Msgs) end. + +%%% +%%% Support for testing large files. +%%% + +run_large_file_test(Config, Run, Name) -> + case {os:type(),os:version()} of + {{win32,nt},_} -> + do_run_large_file_test(Config, Run, Name); + {{unix,sunos},OsVersion} when OsVersion < {5,5,1} -> + {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"}; + {{unix,_},_} -> + N = disc_free(?config(priv_dir, Config)), + io:format("Free disk: ~w KByte~n", [N]), + if N < 5 * (1 bsl 20) -> + %% Less than 5 GByte free + {skip,"Less than 5 GByte free"}; + true -> + do_run_large_file_test(Config, Run, Name) + end; + _ -> + {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"} + end. + + +do_run_large_file_test(Config, Run, Name0) -> + Name = filename:join(?config(priv_dir, Config), + ?MODULE_STRING ++ Name0), + + %% Set up a process that will delete this file. + Tester = self(), + Deleter = + spawn( + fun() -> + Mref = erlang:monitor(process, Tester), + receive + {'DOWN',Mref,_,_,_} -> ok; + {Tester,done} -> ok + end, + ?FILE_MODULE:delete(Name) + end), + + %% Run the test case. + Res = Run(Name), + + %% Delete file and finish deleter process. + Mref = erlang:monitor(process, Deleter), + Deleter ! {Tester,done}, + receive {'DOWN',Mref,_,_,_} -> ok end, + + Res. + +disc_free(Path) -> + Data = disksup:get_disk_data(), + {_,Tot,Perc} = hd(lists:filter( + fun({P,_Size,_Full}) -> + lists:prefix(filename:nativename(P), + filename:nativename(Path)) + end, lists:reverse(lists:sort(Data)))), + round(Tot * (1-(Perc/100))). + +memsize() -> + {Tot,_Used,_} = memsup:get_memory_data(), + Tot. diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index 300152ddce..8f490b6643 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -48,7 +48,9 @@ init_per_suite(_Config) -> {ok,Socket} -> gen_sctp:close(Socket), []; - {error,eprotonosupport} -> + {error,Error} + when Error =:= eprotonosupport; + Error =:= esocktnosupport -> {skip,"SCTP not supported on this machine"} end. diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index cbaec2d6dd..a7af00c12a 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -22,7 +22,7 @@ %% are not tested here, because they are tested indirectly in this and %% and other test suites. --include_lib("test_server/include/test_server.hrl"). +-include_lib("common_test/include/ct.hrl"). -include_lib("kernel/include/inet.hrl"). -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, @@ -46,6 +46,8 @@ groups() -> {t_connect, [], [t_connect_timeout, t_connect_bad]}, {t_recv, [], [t_recv_timeout, t_recv_eof]}]. + + init_per_suite(Config) -> Config. @@ -55,9 +57,8 @@ end_per_suite(_Config) -> init_per_group(_GroupName, Config) -> Config. -end_per_group(_GroupName, Config) -> - Config. - +end_per_group(_,_Config) -> + ok. init_per_testcase(_Func, Config) -> Dog = test_server:timetrap(test_server:seconds(60)), @@ -237,7 +238,6 @@ implicit_inet6(S, Addr) -> ?line ok = gen_tcp:close(S1). - %%% Utilities %% Calls M:F/length(A), which should return a timeout error, and complete diff --git a/lib/kernel/test/gen_tcp_echo_SUITE.erl b/lib/kernel/test/gen_tcp_echo_SUITE.erl index fffaaf4c45..5bbaeb02ad 100644 --- a/lib/kernel/test/gen_tcp_echo_SUITE.erl +++ b/lib/kernel/test/gen_tcp_echo_SUITE.erl @@ -167,8 +167,12 @@ echo_test_1(SockOpts, EchoFun, Config0) -> [{type, {cdr, little}}|Config]), ?line case lists:keymember(packet_size, 1, SockOpts) of false -> - ?line echo_packet([{packet, line}|SockOpts], - EchoFun, Config); + % This is cheating, we should test that packet_size + % also works for line and http. + echo_packet([{packet, line}|SockOpts], EchoFun, Config), + echo_packet([{packet, http}|SockOpts], EchoFun, Config), + echo_packet([{packet, http_bin}|SockOpts], EchoFun, Config); + true -> ok end, ?line echo_packet([{packet, tpkt}|SockOpts], EchoFun, Config), @@ -183,9 +187,6 @@ echo_test_1(SockOpts, EchoFun, Config0) -> [{type, {asn1, short, LongTag}}|Config]), ?line echo_packet([{packet, asn1}|SockOpts], EchoFun, [{type, {asn1, long, LongTag}}|Config]), - - ?line echo_packet([{packet, http}|SockOpts], EchoFun, Config), - ?line echo_packet([{packet, http_bin}|SockOpts], EchoFun, Config), ok. echo_packet(SockOpts, EchoFun, Opts) -> diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index b1ef8826d5..3da4b07c05 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -40,7 +40,8 @@ accept_timeouts_in_order3/1,accept_timeouts_mixed/1, killing_acceptor/1,killing_multi_acceptors/1,killing_multi_acceptors2/1, several_accepts_in_one_go/1,active_once_closed/1, send_timeout/1, send_timeout_active/1, - otp_7731/1, zombie_sockets/1, otp_7816/1, otp_8102/1]). + otp_7731/1, zombie_sockets/1, otp_7816/1, otp_8102/1, + otp_9389/1]). %% Internal exports. -export([sender/3, not_owner/1, passive_sockets_server/2, priority_server/1, @@ -72,7 +73,7 @@ all() -> killing_acceptor, killing_multi_acceptors, killing_multi_acceptors2, several_accepts_in_one_go, active_once_closed, send_timeout, send_timeout_active, otp_7731, - zombie_sockets, otp_7816, otp_8102]. + zombie_sockets, otp_7816, otp_8102, otp_9389]. groups() -> []. @@ -1030,6 +1031,7 @@ busy_send_loop(Server, Client, N) -> {Server,send} -> ?line busy_send_2(Server, Client, N+1) after 10000 -> + %% If this happens, see busy_send_srv ?t:fail({timeout,{server,not_send,flush([])}}) end end. @@ -1049,7 +1051,9 @@ busy_send_2(Server, Client, _N) -> busy_send_srv(L, Master, Msg) -> %% Server - %% + %% Sometimes this accept does not return, do not really know why + %% but is causes the timeout error in busy_send_loop to be + %% triggered. Only happens on OS X Leopard?!? {ok,Socket} = gen_tcp:accept(L), busy_send_srv_loop(Socket, Master, Msg). @@ -2479,4 +2483,63 @@ otp_8102_do(LSocket, PortNum, {Bin,PType}) -> io:format("Got error msg, ok.\n",[]), gen_tcp:close(SSocket), gen_tcp:close(RSocket). - + +otp_9389(doc) -> ["Verify packet_size handles long HTTP header lines"]; +otp_9389(suite) -> []; +otp_9389(Config) when is_list(Config) -> + ?line {ok, LS} = gen_tcp:listen(0, []), + ?line {ok, {_, PortNum}} = inet:sockname(LS), + io:format("Listening on ~w with port number ~p\n", [LS, PortNum]), + OrigLinkHdr = "/" ++ string:chars($S, 8192), + _Server = spawn_link( + fun() -> + ?line {ok, S} = gen_tcp:accept(LS), + ?line ok = inet:setopts(S, [{packet_size, 16384}]), + ?line ok = otp_9389_loop(S, OrigLinkHdr), + ?line ok = gen_tcp:close(S) + end), + ?line {ok, S} = gen_tcp:connect("localhost", PortNum, + [binary, {active, false}]), + Req = "GET / HTTP/1.1\r\n" + ++ "Host: localhost\r\n" + ++ "Link: " ++ OrigLinkHdr ++ "\r\n\r\n", + ?line ok = gen_tcp:send(S, Req), + ?line ok = inet:setopts(S, [{packet, http}]), + ?line {ok, {http_response, {1,1}, 200, "OK"}} = gen_tcp:recv(S, 0), + ?line ok = inet:setopts(S, [{packet, httph}, {packet_size, 16384}]), + ?line {ok, {http_header, _, 'Content-Length', _, "0"}} = gen_tcp:recv(S, 0), + ?line {ok, {http_header, _, "Link", _, LinkHdr}} = gen_tcp:recv(S, 0), + ?line true = (LinkHdr == OrigLinkHdr), + ok = gen_tcp:close(S), + ok = gen_tcp:close(LS), + ok. + +otp_9389_loop(S, OrigLinkHdr) -> + ?line ok = inet:setopts(S, [{active,once},{packet,http}]), + receive + {http, S, {http_request, 'GET', _, _}} -> + ?line ok = otp_9389_loop(S, OrigLinkHdr, undefined) + after + 3000 -> + ?line error({timeout,request_line}) + end. +otp_9389_loop(S, OrigLinkHdr, ok) -> + ?line Resp = "HTTP/1.1 200 OK\r\nContent-length: 0\r\n" ++ + "Link: " ++ OrigLinkHdr ++ "\r\n\r\n", + ?line ok = gen_tcp:send(S, Resp); +otp_9389_loop(S, OrigLinkHdr, State) -> + ?line ok = inet:setopts(S, [{active,once}, {packet,httph}]), + receive + {http, S, http_eoh} -> + ?line otp_9389_loop(S, OrigLinkHdr, ok); + {http, S, {http_header, _, "Link", _, LinkHdr}} -> + ?line LinkHdr = OrigLinkHdr, + ?line otp_9389_loop(S, OrigLinkHdr, State); + {http, S, {http_header, _, _Hdr, _, _Val}} -> + ?line otp_9389_loop(S, OrigLinkHdr, State); + {http, S, {http_error, Err}} -> + ?line error({error, Err}) + after + 3000 -> + ?line error({timeout,header}) + end. diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index aaa20b7398..7241b093d0 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -97,8 +97,12 @@ t_gethostbyaddr() -> required(v4). t_gethostbyaddr(doc) -> "Test the inet:gethostbyaddr/1 function."; t_gethostbyaddr(Config) when is_list(Config) -> - ?line {Name,FullName,IPStr,IP,Aliases,_,_} = + ?line {Name,FullName,IPStr,{A,B,C,D}=IP,Aliases,_,_} = ct:get_config(test_host_ipv4_only), + ?line Rname = integer_to_list(D) ++ "." ++ + integer_to_list(C) ++ "." ++ + integer_to_list(B) ++ "." ++ + integer_to_list(A) ++ ".in-addr.arpa", ?line {ok,HEnt} = inet:gethostbyaddr(IPStr), ?line {ok,HEnt} = inet:gethostbyaddr(IP), ?line {error,Error} = inet:gethostbyaddr(Name), @@ -116,7 +120,7 @@ t_gethostbyaddr(Config) when is_list(Config) -> ok; _ -> ?line check_elems([{HEnt#hostent.h_name,[Name,FullName]}, - {HEnt#hostent.h_aliases,[[],Aliases]}]) + {HEnt#hostent.h_aliases,[[],Aliases,[Rname]]}]) end, ?line {_DName, _DFullName, DIPStr, DIP, _, _, _} = diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl index 15b0ed5718..f3ba28e4f9 100644 --- a/lib/kernel/test/inet_res_SUITE.erl +++ b/lib/kernel/test/inet_res_SUITE.erl @@ -88,7 +88,7 @@ init_per_testcase(Func, Config) -> inet_db:ins_alt_ns(IP, Port); _ -> ok end, - Dog = test_server:timetrap(test_server:seconds(10)), + Dog = test_server:timetrap(test_server:seconds(20)), [{nameserver,NsSpec},{res_lookup,Lookup},{watchdog,Dog}|Config] catch SkipReason -> @@ -303,7 +303,7 @@ basic(Config) when is_list(Config) -> {ok,Msg2} = inet_dns:decode(Bin2), %% %% lookup - [IP] = inet_res:lookup(Name, in, a, [{nameservers,[NS]}]), + [IP] = inet_res:lookup(Name, in, a, [{nameservers,[NS]},verbose]), %% %% gethostbyname {ok,#hostent{h_addr_list=[IP]}} = inet_res:gethostbyname(Name), @@ -410,7 +410,7 @@ edns0(Config) when is_list(Config) -> false = inet_db:res_option(edns), % ASSERT true = inet_db:res_option(udp_payload_size) >= 1280, % ASSERT %% These will fall back to TCP - MXs = lists:sort(inet_res:lookup(Domain, in, mx, [{nameservers,[NS]}])), + MXs = lists:sort(inet_res:lookup(Domain, in, mx, [{nameservers,[NS]},verbose])), %% {ok,#hostent{h_addr_list=As}} = inet_res:getbyname(Domain++".", mx), MXs = lists:sort(As), diff --git a/lib/kernel/test/inet_res_SUITE_data/run-named b/lib/kernel/test/inet_res_SUITE_data/run-named index 39e7b1d5aa..211d2c7af7 100755 --- a/lib/kernel/test/inet_res_SUITE_data/run-named +++ b/lib/kernel/test/inet_res_SUITE_data/run-named @@ -2,7 +2,7 @@ ## ## %CopyrightBegin% ## -## Copyright Ericsson AB 2009-2011. All Rights Reserved. +## Copyright Ericsson AB 2009-2012. All Rights Reserved. ## ## The contents of this file are subject to the Erlang Public License, ## Version 1.1, (the "License"); you may not use this file except in @@ -47,7 +47,6 @@ CONF_FILE=named.conf INC_FILE=named_inc.conf PID_FILE=named.pid LOG_FILE=named.log -EXIT_FILE=named.exit error () { r=$? @@ -150,7 +149,6 @@ cat >>"$CONF_FILE" <<-CONF_FILE ( cd "$SRCDIR" && ls -1 ) | while read f; do cp -fp "$SRCDIR/$f" . done -rm -f "$EXIT_FILE" # Start nameserver echo "Cwd: `pwd`" @@ -158,19 +156,20 @@ echo "Nameserver: $NAMED_VER" echo "Port: $2" echo "ZoneDir: $3" echo "Command: $NAMED $NAMED_FG -c $CONF_FILE" -($NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null; \ - echo "$?" >"$EXIT_FILE")& +$NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null & NAMED_PID=$! -trap "kill -TERM $NAMED_PID >/dev/null 2>&1; wait $NAMED_PID >/dev/null 2>&1" \ +echo "Pid: $NAMED_PID" +trap "kill $NAMED_PID >/dev/null 2>&1; wait $NAMED_PID >/dev/null 2>&1" \ 0 1 2 3 15 -sleep 2 # Give name server time to load its zone files -if [ -f "$EXIT_FILE" ]; then - ERROR="`cat "$EXIT_FILE"`" - (exit "$ERROR")& error "$NAMED returned $ERROR on start" -else + +sleep 5 # Give name server time to load its zone files + +if ps -p $NAMED_PID >/dev/null 2>&1 || ps p $NAMED_PID >/dev/null 2>&1; then echo "Running: Enter \`\`quit'' to terminate nameserver[$NAMED_PID]..." while read LINE; do test :"$LINE" = :'quit' && break done + echo "Closing: Terminating nameserver..." +else + error "$NAMED failed to start" fi -echo "Closing: Terminating nameserver..." diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl index b08b12c978..ae3410d13f 100644 --- a/lib/kernel/test/os_SUITE.erl +++ b/lib/kernel/test/os_SUITE.erl @@ -117,9 +117,21 @@ space_in_name(Config) when is_list(Config) -> ?line ok = file:change_mode(Echo, 8#777), % Make it executable on Unix. %% Run the echo program. - - ?line comp("", os:cmd("\"" ++ Echo ++ "\"")), - ?line comp("a::b::c", os:cmd("\"" ++ Echo ++ "\" a b c")), + %% Quoting on windows depends on if the full path of the executable + %% contains special characters. Paths when running common_tests always + %% include @, why Windows would always fail if we do not double the + %% quotes (this is the behaviour of cmd.exe, not Erlang's idea). + Quote = case os:type() of + {win32,_} -> + case (Echo -- "&<>()@^|") =:= Echo of + true -> "\""; + false -> "\"\"" + end; + _ -> + "\"" + end, + ?line comp("", os:cmd(Quote ++ Echo ++ Quote)), + ?line comp("a::b::c", os:cmd(Quote ++ Echo ++ Quote ++ " a b c")), ?t:sleep(5), ?line [] = receive_all(), ok. diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index 00eda6292f..3e2202922c 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -32,7 +32,10 @@ file_info_basic_directory_a/1, file_info_basic_directory_b/1, file_info_bad_a/1, file_info_bad_b/1, file_info_times_a/1, file_info_times_b/1, - file_write_file_info_a/1, file_write_file_info_b/1]). + file_write_file_info_a/1, file_write_file_info_b/1, + file_read_file_info_opts/1, file_write_file_info_opts/1, + file_write_read_file_info_opts/1 + ]). -export([rename_a/1, rename_b/1, access/1, truncate/1, datasync/1, sync/1, read_write/1, pread_write/1, append/1, exclusive/1]). @@ -49,6 +52,10 @@ list_dir_limit/1]). -export([advise/1]). +-export([large_write/1]). + +%% System probe functions that might be handy to check from the shell +-export([unix_free/1]). -include_lib("test_server/include/test_server.hrl"). -include_lib("kernel/include/file.hrl"). @@ -80,7 +87,7 @@ groups() -> cur_dir_1a, cur_dir_1b]}, {files, [], [{group, open}, {group, pos}, {group, file_info}, - truncate, sync, datasync, advise]}, + truncate, sync, datasync, advise, large_write]}, {open, [], [open1, modes, close, access, read_write, pread_write, append, exclusive]}, @@ -90,7 +97,10 @@ groups() -> file_info_basic_directory_a, file_info_basic_directory_b, file_info_bad_a, file_info_bad_b, file_info_times_a, file_info_times_b, - file_write_file_info_a, file_write_file_info_b]}, + file_write_file_info_a, file_write_file_info_b, + file_read_file_info_opts, file_write_file_info_opts, + file_write_read_file_info_opts + ]}, {errors, [], [e_delete, e_rename, e_make_dir, e_del_dir]}, {compression, [], @@ -284,6 +294,7 @@ make_del_dir(Config, Handle, Suffix) -> %% Don't worry ;-) the parent directory should never be empty, right? ?line case ?PRIM_FILE_call(del_dir, Handle, [".."]) of {error, eexist} -> ok; + {error, eacces} -> ok; %OpenBSD {error, einval} -> ok %FreeBSD end, ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]), @@ -1074,6 +1085,104 @@ file_write_file_info(Config, Handle, Suffix) -> ?line test_server:timetrap_cancel(Dog), ok. +%% Test the write_file_info/3 function. + +file_write_file_info_opts(suite) -> []; +file_write_file_info_opts(doc) -> []; +file_write_file_info_opts(Config) when is_list(Config) -> + {ok, Handle} = ?PRIM_FILE:start(), + Dog = test_server:timetrap(test_server:seconds(10)), + RootDir = get_good_directory(Config), + test_server:format("RootDir = ~p", [RootDir]), + + Name = filename:join(RootDir, atom_to_list(?MODULE) ++"_write_file_info_opts"), + ok = ?PRIM_FILE:write_file(Name, "hello_opts"), + + lists:foreach(fun + ({FI, Opts}) -> + ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, FI, Opts]) + end, [ + {#file_info{ mode=8#600, atime = Time, mtime = Time, ctime = Time}, Opts} || + Opts <- [[{time, posix}]], + Time <- [ 0,1,-1,100,-100,1000,-1000,10000,-10000 ] + ]), + + % REM: determine date range dependent on time_t = Uint32 | Sint32 | Sint64 + % Determine time_t on os:type()? + lists:foreach(fun + ({FI, Opts}) -> + ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, FI, Opts]) + end, [ + {#file_info{ mode=8#400, atime = Time, mtime = Time, ctime = Time}, Opts} || + Opts <- [[{time, universal}],[{time, local}]], + Time <- [ + {{1970,1,1},{0,0,0}}, + {{1970,1,1},{0,0,1}}, + {{1969,12,31},{23,59,59}}, + {{1908,2,3},{23,59,59}}, + {{2012,2,3},{23,59,59}}, + {{2037,2,3},{23,59,59}}, + erlang:localtime() + ]]), + ok = ?PRIM_FILE:stop(Handle), + test_server:timetrap_cancel(Dog), + ok. + +file_read_file_info_opts(suite) -> []; +file_read_file_info_opts(doc) -> []; +file_read_file_info_opts(Config) when is_list(Config) -> + {ok, Handle} = ?PRIM_FILE:start(), + Dog = test_server:timetrap(test_server:seconds(10)), + RootDir = get_good_directory(Config), + test_server:format("RootDir = ~p", [RootDir]), + + Name = filename:join(RootDir, atom_to_list(?MODULE) ++"_read_file_info_opts"), + ok = ?PRIM_FILE:write_file(Name, "hello_opts"), + + lists:foreach(fun + (Opts) -> + {ok,_} = ?PRIM_FILE_call(read_file_info, Handle, [Name, Opts]) + end, [[{time, Type}] || Type <- [local, universal, posix]]), + ok = ?PRIM_FILE:stop(Handle), + test_server:timetrap_cancel(Dog), + ok. + +%% Test the write and read back *_file_info/3 functions. + +file_write_read_file_info_opts(suite) -> []; +file_write_read_file_info_opts(doc) -> []; +file_write_read_file_info_opts(Config) when is_list(Config) -> + {ok, Handle} = ?PRIM_FILE:start(), + Dog = test_server:timetrap(test_server:seconds(10)), + RootDir = get_good_directory(Config), + test_server:format("RootDir = ~p", [RootDir]), + + Name = filename:join(RootDir, atom_to_list(?MODULE) ++"_read_write_file_info_opts"), + ok = ?PRIM_FILE:write_file(Name, "hello_opts2"), + + ok = file_write_read_file_info_opts(Handle, Name, {{1989, 04, 28}, {19,30,22}}, [{time, local}]), + ok = file_write_read_file_info_opts(Handle, Name, {{1989, 04, 28}, {19,30,22}}, [{time, universal}]), + ok = file_write_read_file_info_opts(Handle, Name, {{1930, 04, 28}, {19,30,22}}, [{time, local}]), + ok = file_write_read_file_info_opts(Handle, Name, {{1930, 04, 28}, {19,30,22}}, [{time, universal}]), + ok = file_write_read_file_info_opts(Handle, Name, 1, [{time, posix}]), + ok = file_write_read_file_info_opts(Handle, Name, -1, [{time, posix}]), + ok = file_write_read_file_info_opts(Handle, Name, 300000, [{time, posix}]), + ok = file_write_read_file_info_opts(Handle, Name, -300000, [{time, posix}]), + ok = file_write_read_file_info_opts(Handle, Name, 0, [{time, posix}]), + + ok = ?PRIM_FILE:stop(Handle), + test_server:timetrap_cancel(Dog), + ok. + +file_write_read_file_info_opts(Handle, Name, Mtime, Opts) -> + {ok, FI} = ?PRIM_FILE_call(read_file_info, Handle, [Name, Opts]), + FI2 = FI#file_info{ mtime = Mtime }, + ok = ?PRIM_FILE_call(write_file_info, Handle, [Name, FI2, Opts]), + {ok, FI2} = ?PRIM_FILE_call(read_file_info, Handle, [Name, Opts]), + ok. + + + %% Returns a directory on a file system that has correct file times. get_good_directory(Config) -> @@ -1218,6 +1327,41 @@ advise(Config) when is_list(Config) -> ?line test_server:timetrap_cancel(Dog), ok. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +large_write(Config) when is_list(Config) -> + run_large_file_test(Config, + fun(Name) -> do_large_write(Name) end, + "_large_write"). + +do_large_write(Name) -> + Dog = test_server:timetrap(test_server:minutes(60)), + ChunkSize = (256 bsl 20) + 1, % 256 M + 1 + Chunks = 16, % times 16 -> 4 G + 16 + Base = 100, + Interleave = lists:seq(Base+1, Base+Chunks), + Chunk = <<0:ChunkSize/unit:8>>, + Data = zip_data(lists:duplicate(Chunks, Chunk), Interleave), + Size = Chunks * ChunkSize + Chunks, % 4 G + 32 + Wordsize = erlang:system_info(wordsize), + case prim_file:write_file(Name, Data) of + ok when Wordsize =:= 8 -> + {ok,#file_info{size=Size}} = file:read_file_info(Name), + {ok,Fd} = prim_file:open(Name, [read]), + check_large_write(Dog, Fd, ChunkSize, 0, Interleave); + {error,einval} when Wordsize =:= 4 -> + ok + end. + +check_large_write(Dog, Fd, ChunkSize, Pos, [X|Interleave]) -> + Pos1 = Pos + ChunkSize, + {ok,Pos1} = prim_file:position(Fd, {cur,ChunkSize}), + {ok,[X]} = prim_file:read(Fd, 1), + check_large_write(Dog, Fd, ChunkSize, Pos1+1, Interleave); +check_large_write(Dog, Fd, _, _, []) -> + eof = prim_file:read(Fd, 1), + test_server:timetrap_cancel(Dog), + ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1940,3 +2084,70 @@ list_dir_limit_cleanup(Dir, Handle, N, Cnt) -> ?PRIM_FILE:delete(Handle, filename:join(Dir, Name)), list_dir_limit_cleanup(Dir, Handle, N, Cnt+1). +%%% +%%% Support for testing large files. +%%% + +run_large_file_test(Config, Run, Name) -> + case {os:type(),os:version()} of + {{win32,nt},_} -> + do_run_large_file_test(Config, Run, Name); + {{unix,sunos},OsVersion} when OsVersion < {5,5,1} -> + {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"}; + {{unix,_},_} -> + N = unix_free(?config(priv_dir, Config)), + io:format("Free disk: ~w KByte~n", [N]), + if N < 5 bsl 20 -> + %% Less than 5 GByte free + {skip,"Less than 5 GByte free disk"}; + true -> + do_run_large_file_test(Config, Run, Name) + end; + _ -> + {skip,"Only supported on Win32, Unix or SunOS >= 5.5.1"} + end. + + +do_run_large_file_test(Config, Run, Name0) -> + Name = filename:join(?config(priv_dir, Config), + ?MODULE_STRING ++ Name0), + + %% Set up a process that will delete this file. + Tester = self(), + Deleter = + spawn( + fun() -> + Mref = erlang:monitor(process, Tester), + receive + {'DOWN',Mref,_,_,_} -> ok; + {Tester,done} -> ok + end, + prim_file:delete(Name) + end), + + %% Run the test case. + Res = Run(Name), + + %% Delete file and finish deleter process. + Mref = erlang:monitor(process, Deleter), + Deleter ! {Tester,done}, + receive {'DOWN',Mref,_,_,_} -> ok end, + + Res. + +unix_free(Path) -> + Cmd = ["df -k '",Path,"'"], + DF0 = os:cmd(Cmd), + io:format("$ ~s~n~s", [Cmd,DF0]), + Lines = re:split(DF0, "\n", [trim,{return,list}]), + Last = lists:last(Lines), + RE = "^[^\\s]*\\s+\\d+\\s+\\d+\\s+(\\d+)", + {match,[Avail]} = re:run(Last, RE, [{capture,all_but_first,list}]), + list_to_integer(Avail). + +zip_data([A|As], [B|Bs]) -> + [[A,B]|zip_data(As, Bs)]; +zip_data([], Bs) -> + Bs; +zip_data(As, []) -> + As. diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl new file mode 100644 index 0000000000..6d0848ee05 --- /dev/null +++ b/lib/kernel/test/sendfile_SUITE.erl @@ -0,0 +1,355 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2011-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(sendfile_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("kernel/include/file.hrl"). + +-compile(export_all). + +all() -> + [t_sendfile_small + ,t_sendfile_big + ,t_sendfile_partial + ,t_sendfile_offset + ,t_sendfile_sendafter + ,t_sendfile_recvafter + ,t_sendfile_sendduring + ,t_sendfile_recvduring + ,t_sendfile_closeduring + ,t_sendfile_crashduring + ]. + +init_per_suite(Config) -> + Priv = ?config(priv_dir, Config), + SFilename = filename:join(Priv, "sendfile_small.html"), + {ok, DS} = file:open(SFilename,[write,raw]), + file:write(DS,"yo baby yo"), + file:sync(DS), + file:close(DS), + BFilename = filename:join(Priv, "sendfile_big.html"), + {ok, DB} = file:open(BFilename,[write,raw]), + [file:write(DB,[<<0:(10*8*1024*1024)>>]) || _I <- lists:seq(1,51)], + file:sync(DB), + file:close(DB), + [{small_file, SFilename}, + {file_opts,[raw,binary]}, + {big_file, BFilename}|Config]. + +end_per_suite(Config) -> + file:delete(proplists:get_value(big_file, Config)). + +init_per_testcase(TC,Config) when TC == t_sendfile_recvduring; + TC == t_sendfile_sendduring -> + Filename = proplists:get_value(small_file, Config), + + Send = fun(Sock) -> + {_Size, Data} = sendfile_file_info(Filename), + {ok,D} = file:open(Filename, [raw,binary,read]), + prim_file:sendfile(D, Sock, 0, 0, 0, + [],[],false,false,false), + Data + end, + + %% Check if sendfile is supported on this platform + case catch sendfile_send(Send) of + ok -> + Config; + Error -> + ct:log("Error: ~p",[Error]), + {skip,"Not supported"} + end; +init_per_testcase(_Tc,Config) -> + Config. + + +t_sendfile_small(Config) when is_list(Config) -> + Filename = proplists:get_value(small_file, Config), + + Send = fun(Sock) -> + {Size, Data} = sendfile_file_info(Filename), + {ok, Size} = file:sendfile(Filename, Sock), + Data + end, + + ok = sendfile_send(Send). + +t_sendfile_big(Config) when is_list(Config) -> + Filename = proplists:get_value(big_file, Config), + + Send = fun(Sock) -> + {ok, #file_info{size = Size}} = + file:read_file_info(Filename), + {ok, Size} = file:sendfile(Filename, Sock), + Size + end, + + ok = sendfile_send({127,0,0,1}, Send, 0). + +t_sendfile_partial(Config) -> + Filename = proplists:get_value(small_file, Config), + FileOpts = proplists:get_value(file_opts, Config, []), + + SendSingle = fun(Sock) -> + {_Size, <<Data:5/binary,_/binary>>} = + sendfile_file_info(Filename), + {ok,D} = file:open(Filename,[read|FileOpts]), + {ok,5} = file:sendfile(D,Sock,0,5,[]), + file:close(D), + Data + end, + ok = sendfile_send(SendSingle), + + {_Size, <<FData:5/binary,SData:3/binary,_/binary>>} = + sendfile_file_info(Filename), + {ok,D} = file:open(Filename,[read|FileOpts]), + {ok, <<FData/binary>>} = file:read(D,5), + FSend = fun(Sock) -> + {ok,5} = file:sendfile(D,Sock,0,5,[]), + FData + end, + + ok = sendfile_send(FSend), + + SSend = fun(Sock) -> + {ok,3} = file:sendfile(D,Sock,5,3,[]), + SData + end, + + ok = sendfile_send(SSend), + + {ok, <<SData/binary>>} = file:read(D,3), + + file:close(D). + +t_sendfile_offset(Config) -> + Filename = proplists:get_value(small_file, Config), + FileOpts = proplists:get_value(file_opts, Config, []), + + Send = fun(Sock) -> + {_Size, <<_:5/binary,Data:3/binary,_/binary>> = AllData} = + sendfile_file_info(Filename), + {ok,D} = file:open(Filename,[read|FileOpts]), + {ok,3} = file:sendfile(D,Sock,5,3,[]), + {ok, AllData} = file:read(D,100), + file:close(D), + Data + end, + ok = sendfile_send(Send). + + +t_sendfile_sendafter(Config) -> + Filename = proplists:get_value(small_file, Config), + + Send = fun(Sock) -> + {Size, Data} = sendfile_file_info(Filename), + {ok, Size} = file:sendfile(Filename, Sock), + ok = gen_tcp:send(Sock, <<2>>), + <<Data/binary,2>> + end, + + ok = sendfile_send(Send). + +t_sendfile_recvafter(Config) -> + Filename = proplists:get_value(small_file, Config), + + Send = fun(Sock) -> + {Size, Data} = sendfile_file_info(Filename), + {ok, Size} = file:sendfile(Filename, Sock), + ok = gen_tcp:send(Sock, <<1>>), + {ok,<<1>>} = gen_tcp:recv(Sock, 1), + <<Data/binary,1>> + end, + + ok = sendfile_send(Send). + +t_sendfile_sendduring(Config) -> + Filename = proplists:get_value(big_file, Config), + + Send = fun(Sock) -> + {ok, #file_info{size = Size}} = + file:read_file_info(Filename), + spawn_link(fun() -> + timer:sleep(50), + ok = gen_tcp:send(Sock, <<2>>) + end), + {ok, Size} = file:sendfile(Filename, Sock), + Size+1 + end, + + ok = sendfile_send({127,0,0,1}, Send, 0). + +t_sendfile_recvduring(Config) -> + Filename = proplists:get_value(big_file, Config), + + Send = fun(Sock) -> + {ok, #file_info{size = Size}} = + file:read_file_info(Filename), + spawn_link(fun() -> + timer:sleep(50), + ok = gen_tcp:send(Sock, <<1>>), + {ok,<<1>>} = gen_tcp:recv(Sock, 1) + end), + {ok, Size} = file:sendfile(Filename, Sock), + timer:sleep(1000), + Size+1 + end, + + ok = sendfile_send({127,0,0,1}, Send, 0). + +t_sendfile_closeduring(Config) -> + Filename = proplists:get_value(big_file, Config), + + Send = fun(Sock,SFServPid) -> + spawn_link(fun() -> + timer:sleep(50), + SFServPid ! stop + end), + case erlang:system_info(thread_pool_size) of + 0 -> + {error, closed} = file:sendfile(Filename, Sock); + _Else -> + %% This can return how much has been sent or + %% {error,closed} depending on OS. + %% How much is sent impossible to know as + %% the socket was closed mid sendfile + case file:sendfile(Filename, Sock) of + {error, closed} -> + ok; + {ok, Size} when is_integer(Size) -> + ok + end + end, + -1 + end, + + ok = sendfile_send({127,0,0,1}, Send, 0). + +t_sendfile_crashduring(Config) -> + Filename = proplists:get_value(big_file, Config), + + error_logger:add_report_handler(?MODULE,[self()]), + + Send = fun(Sock) -> + spawn_link(fun() -> + timer:sleep(50), + exit(die) + end), + {error, closed} = file:sendfile(Filename, Sock), + -1 + end, + process_flag(trap_exit,true), + spawn_link(fun() -> + ok = sendfile_send({127,0,0,1}, Send, 0) + end), + receive + {stolen,Reason} -> + process_flag(trap_exit,false), + ct:fail(Reason) + after 200 -> + receive + {'EXIT',_,Reason} -> + process_flag(trap_exit,false), + die = Reason + end + end. + +%% Generic sendfile server code +sendfile_send(Send) -> + sendfile_send({127,0,0,1},Send). +sendfile_send(Host, Send) -> + sendfile_send(Host, Send, []). +sendfile_send(Host, Send, Orig) -> + SFServer = spawn_link(?MODULE, sendfile_server, [self(), Orig]), + receive + {server, Port} -> + {ok, Sock} = gen_tcp:connect(Host, Port, + [binary,{packet,0}, + {active,false}]), + Data = case proplists:get_value(arity,erlang:fun_info(Send)) of + 1 -> + Send(Sock); + 2 -> + Send(Sock, SFServer) + end, + ok = gen_tcp:close(Sock), + receive + {ok, Bin} -> + Data = Bin, + ok + end + end. + +sendfile_server(ClientPid, Orig) -> + {ok, LSock} = gen_tcp:listen(0, [binary, {packet, 0}, + {active, true}, + {reuseaddr, true}]), + {ok, Port} = inet:port(LSock), + ClientPid ! {server, Port}, + {ok, Sock} = gen_tcp:accept(LSock), + {ok, Bin} = sendfile_do_recv(Sock, Orig), + ClientPid ! {ok, Bin}, + gen_tcp:send(Sock, <<1>>). + +-define(SENDFILE_TIMEOUT, 10000). +sendfile_do_recv(Sock, Bs) -> + receive + stop when Bs /= 0,is_integer(Bs) -> + gen_tcp:close(Sock), + {ok, -1}; + {tcp, Sock, B} -> + case binary:match(B,<<1>>) of + nomatch when is_list(Bs) -> + sendfile_do_recv(Sock, [B|Bs]); + nomatch when is_integer(Bs) -> + sendfile_do_recv(Sock, byte_size(B) + Bs); + _ when is_list(Bs) -> + ct:log("Stopped due to a 1"), + {ok, iolist_to_binary(lists:reverse([B|Bs]))}; + _ when is_integer(Bs) -> + ct:log("Stopped due to a 1"), + {ok, byte_size(B) + Bs} + end; + {tcp_closed, Sock} when is_list(Bs) -> + ct:log("Stopped due to close"), + {ok, iolist_to_binary(lists:reverse(Bs))}; + {tcp_closed, Sock} when is_integer(Bs) -> + ct:log("Stopped due to close"), + {ok, Bs} + after ?SENDFILE_TIMEOUT -> + ct:log("Sendfile timeout"), + timeout + end. + +sendfile_file_info(File) -> + {ok, #file_info{size = Size}} = file:read_file_info(File), + {ok, Data} = file:read_file(File), + {Size, Data}. + + +%% Error handler + +init([Proc]) -> {ok,Proc}. + +handle_event({error,noproc,{emulator,Format,Args}}, Proc) -> + Proc ! {stolen,lists:flatten(io_lib:format(Format,Args))}, + {ok,Proc}; +handle_event(_, Proc) -> + {ok,Proc}. diff --git a/lib/kernel/test/seq_trace_SUITE_data/echo_drv.c b/lib/kernel/test/seq_trace_SUITE_data/echo_drv.c index dcbb3348d8..aa182b0877 100644 --- a/lib/kernel/test/seq_trace_SUITE_data/echo_drv.c +++ b/lib/kernel/test/seq_trace_SUITE_data/echo_drv.c @@ -3,7 +3,7 @@ static ErlDrvPort erlang_port; static ErlDrvData echo_start(ErlDrvPort, char *); -static void echo_stop(ErlDrvData), echo_read(ErlDrvData, char*, int); +static void echo_stop(ErlDrvData), echo_read(ErlDrvData, char*, ErlDrvSizeT); static ErlDrvEntry echo_driver_entry = { NULL, @@ -13,7 +13,22 @@ static ErlDrvEntry echo_driver_entry = { NULL, NULL, "echo_drv", - NULL + NULL, + NULL, /* handle */ + NULL, /* control */ + NULL, /* timeout */ + NULL, /* outputv */ + NULL, /* ready_async */ + NULL, + NULL, + NULL, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + 0, + NULL, + NULL, + NULL, }; DRIVER_INIT(echo_drv) @@ -31,7 +46,7 @@ static ErlDrvData echo_start(ErlDrvPort port,char *buf) return (ErlDrvData)port; } -static void echo_read(ErlDrvData data, char *buf, int count) +static void echo_read(ErlDrvData data, char *buf, ErlDrvSizeT count) { driver_output(erlang_port, buf, count); } diff --git a/lib/kernel/test/wrap_log_reader_SUITE.erl b/lib/kernel/test/wrap_log_reader_SUITE.erl index ffc8def626..96dc3e6d33 100644 --- a/lib/kernel/test/wrap_log_reader_SUITE.erl +++ b/lib/kernel/test/wrap_log_reader_SUITE.erl @@ -561,4 +561,4 @@ rec(M, Where) -> end. pps() -> - {erlang:ports(), lists:filter({erlang, is_process_alive}, processes())}. + {erlang:ports(), lists:filter(fun erlang:is_process_alive/1, processes())}. diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index 76c62ece67..76d3003ff4 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 2.15 +KERNEL_VSN = 2.15.1 |