diff options
Diffstat (limited to 'lib/kernel')
39 files changed, 1148 insertions, 504 deletions
diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile index de3ca1e176..ec5d1f09e4 100644 --- a/lib/kernel/doc/src/Makefile +++ b/lib/kernel/doc/src/Makefile @@ -76,8 +76,8 @@ BOOK_FILES = book.xml XML_FILES = \ $(BOOK_FILES) $(XML_CHAPTER_FILES) \ - $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_REF4_FILES) \ - $(XML_REF6_FILES) $(XML_APPLICATION_FILES) + $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_REF4_FILES)\ + $(XML_REF6_FILES) $(XML_APPLICATION_FILES) # ---------------------------------------------------- diff --git a/lib/kernel/doc/src/app.xml b/lib/kernel/doc/src/app.xml index 7c9d6eecec..8575d94048 100644 --- a/lib/kernel/doc/src/app.xml +++ b/lib/kernel/doc/src/app.xml @@ -61,7 +61,8 @@ {applications, Apps}, {env, Env}, {mod, Start}, - {start_phases, Phases}]}. + {start_phases, Phases}, + {runtime_dependencies, RTDeps}]}. Value Default ----- ------- @@ -77,8 +78,10 @@ Apps [App] [] Env [{Par,Val}] [] Start {Module,StartArgs} [] Phases [{Phase,PhaseArgs}] undefined +RTDeps [ApplicationVersion] [] Module = Name = App = Par = Phase = atom() - Val = StartArgs = PhaseArgs = term()</code> + Val = StartArgs = PhaseArgs = term() + ApplicationVersion = string()</code> <p><c>Application</c> is the name of the application.</p> <p>For the application controller, all keys are optional. The respective default values are used for any omitted keys.</p> @@ -87,6 +90,8 @@ Phases [{Phase,PhaseArgs}] undefined <c>description</c>, <c>vsn</c>, <c>modules</c>, <c>registered</c> and <c>applications</c>. The other keys are ignored by <c>systools</c>.</p> + <warning><p>The <c>RTDeps</c> type was introduced in OTP 17.0 and + might be subject to changes during the OTP 17 release.</p></warning> <taglist> <tag><c>description</c></tag> <item> @@ -185,6 +190,33 @@ Phases [{Phase,PhaseArgs}] undefined start phases must be a subset of the set of phases defined for the primary application. Refer to <em>OTP Design Principles</em> for more information.</p> </item> + <tag><marker id="runtime_dependencies"><c>runtime_dependencies</c></marker></tag> + <item><p>A list of application versions that the application + depends on. An example of such an application version is + <c>"kernel-3.0"</c>. Application versions specified as runtime + dependencies are minimum requirements. That is, a larger + application version than the one specified in the + dependency satisfies the requirement. For information on + how to compare application versions see + <seealso marker="doc/system_principles:versions">the + documentation of versions in the system principles + guide</seealso>. Note that that the application version + specifies a source code version. An additional indirect + requirement is that installed binary application of + the specified version has been built so that it is + compatible with the rest of the system.</p> + <p>Some dependencies might only be required in specific runtime + scenarios. In the case such optional dependencies exist, these are + specified and documented in the corresponding "App" documentation + of the specific application.</p> + <warning><p>The <c>runtime_dependencies</c> key was introduced in + OTP 17.0. The type of its value might be subject to changes during + the OTP 17 release.</p></warning> + <warning><p>All runtime dependencies specified in OTP applications + during the OTP 17 release may not be completely correct. This + is actively being worked on. Declared runtime dependencies in OTP + applications are expected to be correct in OTP 18.</p></warning> + </item> </taglist> </section> diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml index 29eaf348a9..7664fda4db 100644 --- a/lib/kernel/doc/src/application.xml +++ b/lib/kernel/doc/src/application.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2013</year> + <year>1996</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -239,10 +239,19 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> <desc> <p>Sets the value of the configuration parameter <c><anno>Par</anno></c> for <c><anno>Application</anno></c>.</p> - <p><c>set_env/3</c> uses the standard <c>gen_server</c> timeout - value (5000 ms). A <c><anno>Timeout</anno></c> argument can be provided + <p><c>set_env/4</c> uses the standard <c>gen_server</c> timeout + value (5000 ms). The <c>timeout</c> option can be provided if another timeout value is useful, for example, in situations where the application controller is heavily loaded.</p> + <p>If <c>set_env/4</c> is called before the application is loaded, + the application environment values specified in the <c>Application.app</c> + file will override the ones previously set. This is also true for application + reloads.</p> + <p>The <c>persistent</c> option can be set to <c>true</c> + when there is a need to guarantee parameters set with <c>set_env/4</c> + will not be overridden by the ones defined in the application resource + file on load. This means persistent values will stick after the application + is loaded and also on application reload.</p> <warning> <p>Use this function only if you know what you are doing, that is, on your own applications. It is very application @@ -406,9 +415,11 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> <p>Removes the configuration parameter <c><anno>Par</anno></c> and its value for <c><anno>Application</anno></c>.</p> <p><c>unset_env/2</c> uses the standard <c>gen_server</c> - timeout value (5000 ms). A <c><anno>Timeout</anno></c> argument can be + timeout value (5000 ms). The <c>timeout</c> option can be provided if another timeout value is useful, for example, in situations where the application controller is heavily loaded.</p> + <p><c>unset_env/3</c> also allows the persistent option to be passed + (see <c>set_env/4</c> above).</p> <warning> <p>Use this function only if you know what you are doing, that is, on your own applications. It is very application @@ -448,8 +459,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> <name>Module:start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}</name> <fsummary>Start an application</fsummary> <type> - <v>StartType = normal | {takeover,Node} | {failover,Node}</v> - <v> Node = node()</v> + <v>StartType = <seealso marker="#type-start_type">start_type()</seealso></v> <v>StartArgs = term()</v> <v>Pid = pid()</v> <v>State = term()</v> diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 0a4dd3ba47..8dae34431b 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2013</year> + <year>1996</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -37,54 +37,48 @@ the file operations. See the command line flag <c>+A</c> in <seealso marker="erts:erl">erl(1)</seealso>.</p> - <p>The Erlang VM supports file names in Unicode to a limited - extent. Depending on how the VM is started (with the parameter - <c>+fnu</c> or <c>+fnl</c>), file names given can contain - characters > 255 and the VM system will convert file names - back and forth to the native file name encoding.</p> + <p>With regard to file name encoding, the Erlang VM can operate in + two modes. The current mode can be queried using the <seealso + marker="#native_name_encoding">native_name_encoding/0</seealso> + function. It returns either <c>latin1</c> or <c>utf8</c>.</p> - <p>The default behavior for Unicode character translation depends - on to what extent the underlying OS/filesystem enforces consistent - naming. On OSes where all file names are ensured to be in one or - another encoding, Unicode is the default (currently this holds for - Windows and MacOSX). On OSes with completely transparent file - naming (i.e. all Unixes except MacOSX), ISO-latin-1 file naming is - the default. The reason for the ISO-latin-1 default is that - file names are not guaranteed to be possible to interpret according to - the Unicode encoding expected (i.e. UTF-8), and file names that - cannot be decoded will only be accessible by using "raw - file names", in other word file names given as binaries.</p> - - <p>As file names are traditionally not binaries in Erlang, - applications that need to handle raw file names need to be - converted, why the Unicode mode for file names is not default on - systems having completely transparent file naming.</p> + <p>In the <c>latin1</c> mode, the Erlang VM does not change the + encoding of file names. In the <c>utf8</c> mode, file names can + contain Unicode characters greater than 255 and the VM will + convert file names back and forth to the native file name encoding + (usually UTF-8, but UTF-16 on Windows).</p> - <p>Raw file names is a new feature in OTP R14B01, which allows the - user to supply completely uninterpreted file names to the - underlying OS/filesystem. They are supplied as binaries, where it - is up to the user to supply a correct encoding for the - environment. The function <c>file:native_name_encoding()</c> can - be used to check what encoding the VM is working in. If the - function returns <c>latin1</c> file names are not in any way - converted to Unicode, if it is <c>utf8</c>, raw file names should - be encoded as UTF-8 if they are to follow the convention of the VM - (and usually the convention of the OS as well). Using raw - file names is useful if you have a filesystem with inconsistent - file naming, where some files are named in UTF-8 encoding while - others are not. A file:list_dir on such mixed file name systems - when the VM is in Unicode file name mode might return file names as - raw binaries as they cannot be interpreted as Unicode - file names. Raw file names can also be used to give UTF-8 encoded - file names even though the VM is not started in Unicode file name - translation mode.</p> + <p>The default mode depends on the operating system. Windows and + MacOS X enforce consistent file name encoding and therefore the + VM uses the <c>utf8</c> mode.</p> + + <p>On operating systems with transparent naming (i.e. all Unix + systems except MacOS X), the default will be <c>utf8</c> if the + terminal supports UTF-8, otherwise <c>latin1</c>. The default may + be overridden using the <c>+fnl</c> (to force <c>latin1</c> mode) + or <c>+fnu</c> (to force <c>utf8</c> mode) when starting <seealso + marker="erts:erl">erl</seealso>.</p> + + <p>On operating systems with transparent naming, files could be + inconsistently named, i.e. some files are encoded in UTF-8 while + others are encoded in (for example) iso-latin1. To be able to + handle file systems with inconsistent naming when running in the + <c>utf8</c> mode, the concept of "raw file names" has been + introduced.</p> + + <p>A raw file name is a file name given as a binary. The Erlang VM + will perform no translation of a file name given as a binary on + systems with transparent naming.</p> + + <p>When running in the <c>utf8</c> mode, the + <c>file:list_dir/1</c> and <c>file:read_link/1</c> functions will + never return raw file names. Use the <seealso + marker="#list_dir_all">list_dir_all/1</seealso> and <seealso + marker="#read_link_all">read_link_all/1</seealso> functions to + return all file names including raw file names.</p> + + <p>Also see <seealso marker="stdlib:unicode_usage#notes-about-raw-filenames">Notes about raw file names</seealso>.</p> - <p>Note that on Windows, <c>file:native_name_encoding()</c> - returns <c>utf8</c> per default, which is the format for raw - file names even on Windows, although the underlying OS specific - code works in a limited version of little endian UTF16. As far as - the Erlang programmer is concerned, Windows native Unicode format - is UTF-8...</p> </description> <datatypes> @@ -535,8 +529,8 @@ <name name="list_dir_all" arity="1"/> <fsummary>List all files in a directory</fsummary> <desc> - <p>Lists all the files in a directory, including files with - "raw" names. + <p><marker id="list_dir_all"/>Lists all the files in a directory, + including files with "raw" names. Returns <c>{ok, <anno>Filenames</anno>}</c> if successful. Otherwise, it returns <c>{error, <anno>Reason</anno>}</c>. <c><anno>Filenames</anno></c> is a list of @@ -648,16 +642,24 @@ <item> <p>Symbolic links are not supported on this platform.</p> </item> + <tag><c>eperm</c></tag> + <item> + <p>User does not have privileges to create symbolic links + (<c>SeCreateSymbolicLinkPrivilege</c> on Windows).</p> + </item> </taglist> </desc> </func> <func> <name name="native_name_encoding" arity="0"/> - <fsummary>Return the VM's configured filename encoding.</fsummary> + <fsummary>Return the VM's configured filename encoding</fsummary> <desc> - <p>This function returns the configured default file name encoding to use for raw file names. Generally an application supplying file names raw (as binaries), should obey the character encoding returned by this function.</p> - <p>By default, the VM uses ISO-latin-1 file name encoding on filesystems and/or OSes that use completely transparent file naming. This includes all Unix versions except MacOSX, where the vfs layer enforces UTF-8 file naming. By giving the experimental option <c>+fnu</c> when starting Erlang, UTF-8 translation of file names can be turned on even for those systems. If Unicode file name translation is in effect, the system behaves as usual as long as file names conform to the encoding, but will return file names that are not properly encoded in UTF-8 as raw file names (i.e. binaries).</p> - <p>On Windows, this function also returns <c>utf8</c> by default. The OS uses a pure Unicode naming scheme and file names are always possible to interpret as valid Unicode. The fact that the underlying Windows OS actually encodes file names using little endian UTF-16 can be ignored by the Erlang programmer. Windows and MacOSX are the only operating systems where the VM operates in Unicode file name mode by default.</p> + <p><marker id="native_name_encoding"/>This function returns + the file name encoding mode. If it is <c>latin1</c>, the + system does no translation of file names. If it is + <c>utf8</c>, file names will be converted back and forth to + the native file name encoding (usually UTF-8, but UTF-16 on + Windows).</p> </desc> </func> <func> @@ -1450,7 +1452,8 @@ <name name="read_link" arity="1"/> <fsummary>See what a link is pointing to</fsummary> <desc> - <p>This function returns <c>{ok, <anno>Filename</anno>}</c> if + <p><marker id="read_link_all"/>This function returns + <c>{ok, <anno>Filename</anno>}</c> if <c><anno>Name</anno></c> refers to a symbolic link that is not a "raw" file name, or <c>{error, <anno>Reason</anno>}</c> otherwise. @@ -1632,6 +1635,11 @@ <desc> <p>Sets the current working directory of the file server to <c><anno>Dir</anno></c>. Returns <c>ok</c> if successful.</p> + <p>The functions in the <c>file</c> module usually treat binaries + as raw filenames, i.e. they are passed as is even when the encoding + of the binary does not agree with <c>file:native_name_encoding()</c>. + This function however expects binaries to be encoded according to the + value returned by <c>file:native_name_encoding()</c>.</p> <p>Typical error reasons are:</p> <taglist> <tag><c>enoent</c></tag> @@ -1656,8 +1664,8 @@ <tag><c>no_translation</c></tag> <item> <p><c><anno>Dir</anno></c> is a <c>binary()</c> with - characters coded in ISO-latin-1 and the VM was started - with the parameter <c>+fnue</c>.</p> + characters coded in ISO-latin-1 and the VM is operating + with unicode file name encoding.</p> </item> </taglist> <warning> @@ -1746,16 +1754,16 @@ <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> + <tag><c>use_threads</c></tag> + <item>Instruct the emulator to use the async thread pool for the + sendfile system call. This could be usefull if the OS you are running + on does not properly support non-blocking sendfile calls. Do note that + using async threads potentially makes your system volnerable to slow + client attacks. If set to true and no async threads are available, + the sendfile call will return <c>{error,einval}</c>. + Introduced in Erlang/OTP 17.0. Default is false.</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> diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index 4a48a5c3d8..50e1cc290c 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -361,7 +361,7 @@ fe80::204:acff:fe17:bf38 </item> <tag><c>send_dvi</c></tag> <item> - <p>Average packet size deviation in bytes received sent from the socket.</p> + <p>Average packet size deviation in bytes sent from the socket.</p> </item> <tag><c>send_max</c></tag> <item> diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml index 49a93d2c70..00c6bc33d6 100644 --- a/lib/kernel/doc/src/kernel_app.xml +++ b/lib/kernel/doc/src/kernel_app.xml @@ -4,7 +4,7 @@ <appref> <header> <copyright> - <year>1996</year><year>2013</year> + <year>1996</year><year>2014</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -35,7 +35,7 @@ Erlang/OTP consists of Kernel and STDLIB. The Kernel application contains the following services:</p> <list type="bulleted"> - <item>application controller, see <c>application(3)</c></item> + <item>application controller, see <seealso marker="application">application(3)</seealso></item> <item><c>code</c></item> <item><c>disk_log</c></item> <item><c>dist_ac</c>, distributed application controller</item> @@ -66,8 +66,8 @@ <section> <title>Configuration</title> <p>The following configuration parameters are defined for the Kernel - application. See <c>app(3)</c> for more information about - configuration parameters.</p> + application. See <seealso marker="app">app(4)</seealso> for more + information about configuration parameters.</p> <taglist> <tag><c>browser_cmd = string() | {M,F,A}</c></tag> <item> @@ -93,7 +93,8 @@ <item><c>Time = integer()>0</c></item> <item><c>Nodes = [node() | {node(),...,node()}]</c></item> </list> - <p>The parameter is described in <c>application(3)</c>, function + <p>The parameter is described in + <seealso marker="application">application(3)</seealso>, function <c>load/2</c>.</p> </item> <tag><c>dist_auto_connect = Value</c></tag> @@ -105,11 +106,13 @@ <taglist> <tag><c>never</c></tag> <item>Connections are never automatically established, they - must be explicitly connected. See <c>net_kernel(3)</c>.</item> + must be explicitly connected. See + <seealso marker="net_kernel">net_kernel(3)</seealso>.</item> <tag><c>once</c></tag> <item>Connections will be established automatically, but only once per node. If a node goes down, it must thereafter be - explicitly connected. See <c>net_kernel(3)</c>.</item> + explicitly connected. See + <seealso marker="net_kernel">net_kernel(3)</seealso>.</item> </taglist> </item> <tag><c>permissions = [Perm]</c></tag> @@ -121,7 +124,8 @@ <item><c>ApplName = atom()</c></item> <item><c>Bool = boolean()</c></item> </list> - <p>Permissions are described in <c>application(3)</c>, function + <p>Permissions are described in + <seealso marker="application">application(3)</seealso>, function <c>permit/2</c>.</p> </item> <tag><c>error_logger = Value</c></tag> @@ -149,7 +153,8 @@ </item> <tag><c>global_groups = [GroupTuple]</c></tag> <item> - <p>Defines global groups, see <c>global_group(3)</c>.</p> + <p>Defines global groups, see + <seealso marker="global_group">global_group(3)</seealso>.</p> <list type="bulleted"> <item><c>GroupTuple = {GroupName, [Node]} | {GroupName, PublishType, [Node]}</c></item> <item><c>GroupName = atom()</c></item> @@ -160,18 +165,19 @@ <tag><c>inet_default_connect_options = [{Opt, Val}]</c></tag> <item> <p>Specifies default options for <c>connect</c> sockets, - see <c>inet(3)</c>.</p> + see <seealso marker="inet">inet(3)</seealso>.</p> </item> <tag><c>inet_default_listen_options = [{Opt, Val}]</c></tag> <item> <p>Specifies default options for <c>listen</c> (and - <c>accept</c>) sockets, see <c>inet(3)</c>.</p> + <c>accept</c>) sockets, see <seealso marker="inet">inet(3)</seealso>.</p> </item> <tag><c>{inet_dist_use_interface, ip_address()}</c></tag> <item> <p>If the host of an Erlang node has several network interfaces, this parameter specifies which one to listen on. See - <c>inet(3)</c> for the type definition of <c>ip_address()</c>.</p> + <seealso marker="inet">inet(3)</seealso> for the type definition + of <c>ip_address()</c>.</p> </item> <tag><c>{inet_dist_listen_min, First}</c></tag> <item> @@ -276,7 +282,8 @@ MaxT = TickTime + TickTime / 4</code> <tag><c>start_boot_server = true | false</c></tag> <item> <p>Starts the <c>boot_server</c> if the parameter is <c>true</c> - (see <c>erl_boot_server(3)</c>). This parameter should be + (see <seealso marker="erl_boot_server">erl_boot_server(3)</seealso>). + This parameter should be set to <c>true</c> in an embedded system which uses this service.</p> <p>The default value is <c>false</c>.</p> @@ -296,13 +303,15 @@ MaxT = TickTime + TickTime / 4</code> <tag><c>start_disk_log = true | false</c></tag> <item> <p>Starts the <c>disk_log_server</c> if the parameter is - <c>true</c> (see <c>disk_log(3)</c>). This parameter should be + <c>true</c> (see <seealso marker="disk_log">disk_log(3)</seealso>). + This parameter should be set to true in an embedded system which uses this service.</p> <p>The default value is <c>false</c>.</p> </item> <tag><c>start_pg2 = true | false</c></tag> <item> - <p>Starts the <c>pg2</c> server (see <c>pg2(3)</c>) if + <p>Starts the <c>pg2</c> server (see + <seealso marker="pg2">pg2(3)</seealso>) if the parameter is <c>true</c>. This parameter should be set to <c>true</c> in an embedded system which uses this service.</p> <p>The default value is <c>false</c>.</p> @@ -310,7 +319,8 @@ MaxT = TickTime + TickTime / 4</code> <tag><c>start_timer = true | false</c></tag> <item> <p>Starts the <c>timer_server</c> if the parameter is - <c>true</c> (see <c>timer(3)</c>). This parameter should be + <c>true</c> (see <seealso marker="stdlib:timer">timer(3)</seealso>). + This parameter should be set to <c>true</c> in an embedded system which uses this service.</p> <p>The default value is <c>false</c>.</p> @@ -351,6 +361,7 @@ MaxT = TickTime + TickTime / 4</code> <seealso marker="pg2">pg2(3)</seealso>, <seealso marker="rpc">rpc(3)</seealso>, <seealso marker="seq_trace">seq_trace(3)</seealso>, + <seealso marker="stdlib:timer">timer(3)</seealso>, <seealso marker="user">user(3)</seealso></p> </section> </appref> diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index b2e89ea850..c6538b7d05 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -30,6 +30,203 @@ </header> <p>This document describes the changes made to the Kernel application.</p> +<section><title>Kernel 3.0</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fixed a deadlock possibility in terminate application</p> + <p> + Own Id: OTP-11171</p> + </item> + <item> + <p> + Fixed bug where sendfile would return the wrong error + code for a remotely closed socket if the socket was in + passive mode. (Thanks to Vincent Siliakus for reporting + the bug.)</p> + <p> + Own Id: OTP-11614</p> + </item> + <item> + <p> + The new option <c>persistent</c> is added to + <c>application:set_env/4</c> and + <c>application:unset_env/3</c>. An environment key set + with the <c>persistent</c> option will not be overridden + by the ones configured in the application resource file + on load. This means persistent values will stick after + the application is loaded and also on application reload. + (Thanks to José Valim)</p> + <p> + Own Id: OTP-11708</p> + </item> + <item> + <p> + The spec for file:set_cwd/1 is modified to also accept + binaries as arguments. This has always been allowed in + the code, but it was not reflected in the spec since + binaries are mostly used for raw file names. Raw file + names are names that are not encoded according to + file:native_name_encoding(), and these are not allowed in + file:set_cwd/1. The spec is now, however, more allowing + in order to avoid unnecessary dialyzer warnings. Raw file + names will still fail in runtime with reason + 'no_translation'. (Thanks to José Valim)</p> + <p> + Own Id: OTP-11787</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + heart:set_cmd/1 is updated to allow unicode code points > + 255 in the given heart command</p> + <p> + Own Id: OTP-10843</p> + </item> + <item> + <p> Dialyzer's <c>unmatched_return</c> warnings have been + corrected. </p> + <p> + Own Id: OTP-10908</p> + </item> + <item> + <p> + Make erlang:open_port/2 spawn and spawn_executable handle + unicode.</p> + <p> + Own Id: OTP-11105</p> + </item> + <item> + <p> + Erlang/OTP has been ported to the realtime operating + system OSE. The port supports both smp and non-smp + emulator. For details around the port and how to started + see the User's Guide in the <seealso + marker="ose:ose_intro">ose</seealso> application. </p> + <p> + Note that not all parts of Erlang/OTP has been ported. </p> + <p> + Notable things that work are: non-smp and smp emulators, + OSE signal interaction, crypto, asn1, run_erl/to_erl, + tcp, epmd, distribution and most if not all non-os + specific functionality of Erlang.</p> + <p> + Notable things that does not work are: udp/sctp, os_mon, + erl_interface, binding of schedulers.</p> + <p> + Own Id: OTP-11334</p> + </item> + <item> + <p> + Add the {active,N} socket option for TCP, UDP, and SCTP, + where N is an integer in the range -32768..32767, to + allow a caller to specify the number of data messages to + be delivered to the controlling process. Once the + socket's delivered message count either reaches 0 or is + explicitly set to 0 with inet:setopts/2 or by including + {active,0} as an option when the socket is created, the + socket transitions to passive ({active, false}) mode and + the socket's controlling process receives a message to + inform it of the transition. TCP sockets receive + {tcp_passive,Socket}, UDP sockets receive + {udp_passive,Socket} and SCTP sockets receive + {sctp_passive,Socket}. </p> + <p> + The socket's delivered message counter defaults to 0, but + it can be set using {active,N} via any gen_tcp, gen_udp, + or gen_sctp function that takes socket options as + arguments, or via inet:setopts/2. New N values are added + to the socket's current counter value, and negative + numbers can be used to reduce the counter value. + Specifying a number that would cause the socket's counter + value to go above 32767 causes an einval error. If a + negative number is specified such that the counter value + would become negative, the socket's counter value is set + to 0 and the socket transitions to passive mode. If the + counter value is already 0 and inet:setopts(Socket, + [{active,0}]) is specified, the counter value remains at + 0 but the appropriate passive mode transition message is + generated for the socket.</p> + <p> + Thanks to Steve Vinoski</p> + <p> + Own Id: OTP-11368</p> + </item> + <item> + <p> + A call to either the <c>garbage_collect/1</c> BIF or the + <c>check_process_code/2</c> BIF may trigger garbage + collection of another processes than the process calling + the BIF. The previous implementations performed these + kinds of garbage collections without considering the + internal state of the process being garbage collected. In + order to be able to more easily and more efficiently + implement yielding native code, these types of garbage + collections have been rewritten. A garbage collection + like this is now triggered by an asynchronous request + signal, the actual garbage collection is performed by the + process being garbage collected itself, and finalized by + a reply signal to the process issuing the request. Using + this approach processes can disable garbage collection + and yield without having to set up the heap in a state + that can be garbage collected.</p> + <p> + The <seealso + marker="erts:erlang#garbage_collect/2"><c>garbage_collect/2</c></seealso>, + and <seealso + marker="erts:erlang#check_process_code/3"><c>check_process_code/3</c></seealso> + BIFs have been introduced. Both taking an option list as + last argument. Using these, one can issue asynchronous + requests.</p> + <p> + <c>code:purge/1</c> and <c>code:soft_purge/1</c> have + been rewritten to utilize asynchronous + <c>check_process_code</c> requests in order to + parallelize work.</p> + <p> + Characteristics impact: A call to the + <c>garbage_collect/1</c> BIF or the + <c>check_process_code/2</c> BIF will normally take longer + time to complete while the system as a whole wont be as + much negatively effected by the operation as before. A + call to <c>code:purge/1</c> and <c>code:soft_purge/1</c> + may complete faster or slower depending on the state of + the system while the system as a whole wont be as much + negatively effected by the operation as before.</p> + <p> + Own Id: OTP-11388 Aux Id: OTP-11535, OTP-11648 </p> + </item> + <item> + <p> + Add sync option to file:open/2.</p> + <p> + The sync option adds the POSIX O_SYNC flag to the open + system call on platforms that support the flag or its + equivalent, e.g., FILE_FLAG_WRITE_THROUGH on Windows. For + platforms that don't support it, file:open/2 returns + {error, enotsup} if the sync option is passed in. Thank + to Steve Vinoski and Joseph Blomstedt</p> + <p> + Own Id: OTP-11498</p> + </item> + <item> + <p> The contract of <c>inet:ntoa/1</c> has been + corrected. </p> <p> Thanks to Max Treskin. </p> + <p> + Own Id: OTP-11730</p> + </item> + </list> + </section> + +</section> + <section><title>Kernel 2.16.4</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/kernel/doc/src/ref_man.xml b/lib/kernel/doc/src/ref_man.xml index c1b9eac9d7..bd25d1e78d 100644 --- a/lib/kernel/doc/src/ref_man.xml +++ b/lib/kernel/doc/src/ref_man.xml @@ -13,12 +13,12 @@ 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. - + </legalnotice> <title>Kernel Reference Manual</title> @@ -65,4 +65,3 @@ <xi:include href="app.xml"/> <xi:include href="config.xml"/> </application> - diff --git a/lib/kernel/doc/src/ref_man.xml.src b/lib/kernel/doc/src/ref_man.xml.src new file mode 100644 index 0000000000..bd25d1e78d --- /dev/null +++ b/lib/kernel/doc/src/ref_man.xml.src @@ -0,0 +1,67 @@ +<?xml version="1.0" encoding="utf-8" ?> +<!DOCTYPE application SYSTEM "application.dtd"> + +<application xmlns:xi="http://www.w3.org/2001/XInclude"> + <header> + <copyright> + <year>1996</year><year>2013</year> + <holder>Ericsson AB. All Rights Reserved.</holder> + </copyright> + <legalnotice> + 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. + + </legalnotice> + + <title>Kernel Reference Manual</title> + <prepared></prepared> + <docno></docno> + <date></date> + <rev></rev> + </header> + <description> + <p>The <em>Kernel</em> application has all the code necessary to run + the Erlang runtime system itself: file servers and code servers + and so on.</p> + </description> + <xi:include href="kernel_app.xml"/> + <xi:include href="application.xml"/> + <xi:include href="auth.xml"/> + <xi:include href="code.xml"/> + <xi:include href="disk_log.xml"/> + <xi:include href="erl_boot_server.xml"/> + <xi:include href="erl_ddll.xml"/> + <xi:include href="erl_prim_loader_stub.xml"/> + <xi:include href="erlang_stub.xml"/> + <xi:include href="error_handler.xml"/> + <xi:include href="error_logger.xml"/> + <xi:include href="file.xml"/> + <xi:include href="gen_tcp.xml"/> + <xi:include href="gen_udp.xml"/> + <xi:include href="gen_sctp.xml"/> + <xi:include href="global.xml"/> + <xi:include href="global_group.xml"/> + <xi:include href="heart.xml"/> + <xi:include href="inet.xml"/> + <xi:include href="inet_res.xml"/> + <xi:include href="init_stub.xml"/> + <xi:include href="net_adm.xml"/> + <xi:include href="net_kernel.xml"/> + <xi:include href="os.xml"/> + <xi:include href="pg2.xml"/> + <xi:include href="rpc.xml"/> + <xi:include href="seq_trace.xml"/> + <xi:include href="user.xml"/> + <xi:include href="wrap_log_reader.xml"/> + <xi:include href="zlib_stub.xml"/> + <xi:include href="app.xml"/> + <xi:include href="config.xml"/> +</application> diff --git a/lib/kernel/include/dist.hrl b/lib/kernel/include/dist.hrl index e32c112e63..77556d1303 100644 --- a/lib/kernel/include/dist.hrl +++ b/lib/kernel/include/dist.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2013. All Rights Reserved. +%% Copyright Ericsson AB 1999-2014. 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 @@ -37,3 +37,4 @@ -define(DFLAG_DIST_HDR_ATOM_CACHE,16#2000). -define(DFLAG_SMALL_ATOM_TAGS, 16#4000). -define(DFLAG_UTF8_ATOMS, 16#10000). +-define(DFLAG_MAP_TAG, 16#20000). diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl index 4e8ba1b78a..c4bef5188a 100644 --- a/lib/kernel/src/application.erl +++ b/lib/kernel/src/application.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -30,6 +30,8 @@ -export([get_application/0, get_application/1, info/0]). -export([start_type/0]). +-export_type([start_type/0]). + %%%----------------------------------------------------------------- -type start_type() :: 'normal' @@ -58,8 +60,7 @@ %%------------------------------------------------------------------ --callback start(StartType :: normal | {takeover, node()} | {failover, node()}, - StartArgs :: term()) -> +-callback start(StartType :: start_type(), StartArgs :: term()) -> {'ok', pid()} | {'ok', pid(), State :: term()} | {'error', Reason :: term()}. -callback stop(State :: term()) -> @@ -132,7 +133,7 @@ ensure_all_started(Application, Type) -> {ok, Started} -> {ok, lists:reverse(Started)}; {error, Reason, Started} -> - [stop(App) || App <- Started], + _ = [stop(App) || App <- Started], {error, Reason} end. @@ -285,16 +286,18 @@ info() -> set_env(Application, Key, Val) -> application_controller:set_env(Application, Key, Val). --spec set_env(Application, Par, Val, Timeout) -> 'ok' when +-spec set_env(Application, Par, Val, Opts) -> 'ok' when Application :: atom(), Par :: atom(), Val :: term(), - Timeout :: timeout(). + Opts :: [{timeout, timeout()} | {persistent, boolean()}]. set_env(Application, Key, Val, infinity) -> - application_controller:set_env(Application, Key, Val, infinity); + set_env(Application, Key, Val, [{timeout, infinity}]); set_env(Application, Key, Val, Timeout) when is_integer(Timeout), Timeout>=0 -> - application_controller:set_env(Application, Key, Val, Timeout). + set_env(Application, Key, Val, [{timeout, Timeout}]); +set_env(Application, Key, Val, Opts) when is_list(Opts) -> + application_controller:set_env(Application, Key, Val, Opts). -spec unset_env(Application, Par) -> 'ok' when Application :: atom(), @@ -303,15 +306,17 @@ set_env(Application, Key, Val, Timeout) when is_integer(Timeout), Timeout>=0 -> unset_env(Application, Key) -> application_controller:unset_env(Application, Key). --spec unset_env(Application, Par, Timeout) -> 'ok' when +-spec unset_env(Application, Par, Opts) -> 'ok' when Application :: atom(), Par :: atom(), - Timeout :: timeout(). + Opts :: [{timeout, timeout()} | {persistent, boolean()}]. unset_env(Application, Key, infinity) -> - application_controller:unset_env(Application, Key, infinity); + unset_env(Application, Key, [{timeout, infinity}]); unset_env(Application, Key, Timeout) when is_integer(Timeout), Timeout>=0 -> - application_controller:unset_env(Application, Key, Timeout). + unset_env(Application, Key, [{timeout, Timeout}]); +unset_env(Application, Key, Opts) when is_list(Opts) -> + application_controller:unset_env(Application, Key, Opts). -spec get_env(Par) -> 'undefined' | {'ok', Val} when Par :: atom(), diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl index 1a4473593a..daad45b6c2 100644 --- a/lib/kernel/src/application_controller.erl +++ b/lib/kernel/src/application_controller.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -461,14 +461,16 @@ permit_application(ApplName, Flag) -> set_env(AppName, Key, Val) -> - gen_server:call(?AC, {set_env, AppName, Key, Val}). -set_env(AppName, Key, Val, Timeout) -> - gen_server:call(?AC, {set_env, AppName, Key, Val}, Timeout). + gen_server:call(?AC, {set_env, AppName, Key, Val, []}). +set_env(AppName, Key, Val, Opts) -> + Timeout = proplists:get_value(timeout, Opts, 5000), + gen_server:call(?AC, {set_env, AppName, Key, Val, Opts}, Timeout). unset_env(AppName, Key) -> - gen_server:call(?AC, {unset_env, AppName, Key}). -unset_env(AppName, Key, Timeout) -> - gen_server:call(?AC, {unset_env, AppName, Key}, Timeout). + gen_server:call(?AC, {unset_env, AppName, Key, []}). +unset_env(AppName, Key, Opts) -> + Timeout = proplists:get_value(timeout, Opts, 5000), + gen_server:call(?AC, {unset_env, AppName, Key, Opts}, Timeout). %%%----------------------------------------------------------------- %%% call-back functions from gen_server @@ -609,8 +611,8 @@ check_para([Else | _ParaList], AppName) -> | {'change_application_data', _, _} | {'permit_application', atom() | {'application',atom(),_},_} | {'start_application', _, _} - | {'unset_env', _, _} - | {'set_env', _, _, _}. + | {'unset_env', _, _, _} + | {'set_env', _, _, _, _}. -spec handle_call(calls(), {pid(), term()}, state()) -> {'noreply', state()} | {'reply', term(), state()}. @@ -827,12 +829,12 @@ handle_call({change_application_data, Applications, Config}, _From, S) -> {reply, Error, S}; {'EXIT', R} -> {reply, {error, R}, S}; - NewAppls -> + {NewAppls, NewConfig} -> lists:foreach(fun(Appl) -> ets:insert(ac_tab, {{loaded, Appl#appl.name}, Appl}) end, NewAppls), - {reply, ok, S#state{conf_data = Config}} + {reply, ok, S#state{conf_data = NewConfig}} end; handle_call(prep_config_change, _From, S) -> @@ -858,13 +860,25 @@ handle_call(which_applications, _From, S) -> end, S#state.running), {reply, Reply, S}; -handle_call({set_env, AppName, Key, Val}, _From, S) -> +handle_call({set_env, AppName, Key, Val, Opts}, _From, S) -> ets:insert(ac_tab, {{env, AppName, Key}, Val}), - {reply, ok, S}; + case proplists:get_value(persistent, Opts, false) of + true -> + Fun = fun(Env) -> lists:keystore(Key, 1, Env, {Key, Val}) end, + {reply, ok, S#state{conf_data = change_app_env(S#state.conf_data, AppName, Fun)}}; + false -> + {reply, ok, S} + end; -handle_call({unset_env, AppName, Key}, _From, S) -> +handle_call({unset_env, AppName, Key, Opts}, _From, S) -> ets:delete(ac_tab, {env, AppName, Key}), - {reply, ok, S}; + case proplists:get_value(persistent, Opts, false) of + true -> + Fun = fun(Env) -> lists:keydelete(Key, 1, Env) end, + {reply, ok, S#state{conf_data = change_app_env(S#state.conf_data, AppName, Fun)}}; + false -> + {reply, ok, S} + end; handle_call({control_application, AppName}, {Pid, _Tag}, S) -> Control = S#state.control, @@ -1536,18 +1550,19 @@ do_change_apps(Applications, Config, OldAppls) -> end, Errors), - map(fun(Appl) -> - AppName = Appl#appl.name, - case is_loaded_app(AppName, Applications) of - {true, Application} -> - do_change_appl(make_appl(Application), - Appl, SysConfig); + {map(fun(Appl) -> + AppName = Appl#appl.name, + case is_loaded_app(AppName, Applications) of + {true, Application} -> + do_change_appl(make_appl(Application), + Appl, SysConfig); - %% ignored removed apps - handled elsewhere - false -> - Appl - end - end, OldAppls). + %% ignored removed apps - handled elsewhere + false -> + Appl + end + end, OldAppls), + SysConfig}. is_loaded_app(AppName, [{application, AppName, App} | _]) -> {true, {application, AppName, App}}; @@ -1640,6 +1655,16 @@ merge_env([{App, AppEnv1} | T], Env2, Res) -> merge_env([], Env2, Res) -> Env2 ++ Res. +%% Changes the environment for the given application +%% If there is no application, an empty one is created +change_app_env(Env, App, Fun) -> + case get_env_key(App, Env) of + {value, AppEnv, RestEnv} -> + [{App, Fun(AppEnv)} | RestEnv]; + _ -> + [{App, Fun([])} | Env] + end. + %% Merges envs for an application. Env2 overrides Env1 merge_app_env(Env1, Env2) -> merge_app_env(Env1, Env2, []). diff --git a/lib/kernel/src/application_master.erl b/lib/kernel/src/application_master.erl index 68f78c6eb8..bc15b5a7de 100644 --- a/lib/kernel/src/application_master.erl +++ b/lib/kernel/src/application_master.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -27,7 +27,7 @@ -include("application_master.hrl"). --record(state, {child, appl_data, children = [], procs = 0, gleader}). +-record(state, {child, appl_data, children = [], procs = 0, gleader, req=[]}). %%----------------------------------------------------------------- %% Func: start_link/1 @@ -205,22 +205,25 @@ terminate_loop(Child, State) -> %%----------------------------------------------------------------- %% The Application Master is linked to *all* processes in the group -%% (application). +%% (application). %%----------------------------------------------------------------- handle_msg({get_child, Tag, From}, State) -> - From ! {Tag, get_child_i(State#state.child)}, - State; + get_child_i(State, Tag, From); handle_msg({stop, Tag, From}, State) -> catch terminate(normal, State), From ! {Tag, ok}, exit(normal); +handle_msg({child, Ref, GrandChild, Mod}, #state{req=Reqs0}=State) -> + {value, {_, Tag, From}, Reqs} = lists:keytake(Ref, 1, Reqs0), + From ! {Tag, {GrandChild, Mod}}, + State#state{req=Reqs}; handle_msg(_, State) -> State. - -terminate(Reason, State) -> - terminate_child(State#state.child, State), - kill_children(State#state.children), +terminate(Reason, State = #state{child=Child, children=Children, req=Reqs}) -> + _ = [From ! {Tag, error} || {_, Tag, From} <- Reqs], + terminate_child(Child, State), + kill_children(Children), exit(Reason). @@ -342,8 +345,8 @@ start_supervisor(Type, M, A) -> loop_it(Parent, Child, Mod, AppState) -> receive - {Parent, get_child} -> - Parent ! {self(), Child, Mod}, + {Parent, get_child, Ref} -> + Parent ! {child, Ref, Child, Mod}, loop_it(Parent, Child, Mod, AppState); {Parent, terminate} -> NewAppState = prep_stop(Mod, AppState), @@ -382,10 +385,15 @@ prep_stop(Mod, AppState) -> NewAppState end. -get_child_i(Child) -> - Child ! {self(), get_child}, - receive - {Child, GrandChild, Mod} -> {GrandChild, Mod} +get_child_i(#state{child=Child, req=Reqs}=State, Tag, From) -> + Ref = erlang:make_ref(), + case erlang:is_process_alive(Child) of + true -> + Child ! {self(), get_child, Ref}, + State#state{req=[{Ref, Tag, From}|Reqs]}; + false -> + From ! {Tag, error}, + State end. terminate_child_i(Child, State) -> diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index fc7ac08699..dd06affd70 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -63,7 +63,10 @@ init(Ref, Parent, [Root,Mode0]) -> process_flag(trap_exit, true), Db = ets:new(code, [private]), - foreach(fun (M) -> ets:insert(Db, {M,preloaded}) end, erlang:pre_loaded()), + foreach(fun (M) -> + %% Pre-loaded modules are always sticky. + ets:insert(Db, [{M,preloaded},{{sticky,M},true}]) + end, erlang:pre_loaded()), ets:insert(Db, init:fetch_loaded()), Mode = @@ -988,7 +991,7 @@ try_archive_subdirs(_Archive, Base, []) -> %% the complete directory name. %% del_path(Name0,Path,NameDb) -> - case catch to_list(Name0)of + case catch filename:join([to_list(Name0)]) of {'EXIT',_} -> {{error,bad_name},Path}; Name -> @@ -1165,7 +1168,7 @@ stick_dir(Dir, Stick, St) -> true -> foreach(fun (M) -> ets:insert(Db, {{sticky,M},true}) end, Mods); false -> - foreach(fun (M) -> ets:delete(Db, {sticky,M}) end, Mods) + foreach(fun (M) -> do_unstick_mod(Db, M) end, Mods) end; Error -> Error @@ -1177,6 +1180,15 @@ stick_mod(M, Stick, St) -> true -> ets:insert(Db, {{sticky,M},true}); false -> + do_unstick_mod(Db, M) + end. + +do_unstick_mod(Db, M) -> + case ets:lookup(Db, M) of + [{M,preloaded}] -> + %% Never unstick pre-loaded modules. + true; + _ -> ets:delete(Db, {sticky,M}) end. diff --git a/lib/kernel/src/disk_log_server.erl b/lib/kernel/src/disk_log_server.erl index 684ea5b5db..45334912eb 100644 --- a/lib/kernel/src/disk_log_server.erl +++ b/lib/kernel/src/disk_log_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2013. All Rights Reserved. +%% Copyright Ericsson AB 1997-2014. 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 @@ -199,7 +199,7 @@ do_open({open, W, #arg{name = Name}=A}=Req, From, State) -> false when W =:= local -> case A#arg.distributed of {true, Nodes} -> - Fun = fun() -> open_distr_rpc(Nodes, A, From) end, + Fun = open_distr_rpc_fun(Nodes, A, From), _Pid = spawn(Fun), %% No pending reply is expected, but don't reply yet. {pending, State}; @@ -225,11 +225,15 @@ do_open({open, W, #arg{name = Name}=A}=Req, From, State) -> end end. +-spec open_distr_rpc_fun([node()], _, _) -> % XXX: underspecified + fun(() -> no_return()). + +open_distr_rpc_fun(Nodes, A, From) -> + fun() -> open_distr_rpc(Nodes, A, From) end. + %% Spawning a process is a means to avoid deadlock when %% disk_log_servers mutually open disk_logs. --spec open_distr_rpc([node()], _, _) -> no_return(). % XXX: underspecified - open_distr_rpc(Nodes, A, From) -> {AllReplies, BadNodes} = rpc:multicall(Nodes, ?MODULE, dist_open, [A]), {Ok, Bad} = cr(AllReplies, [], []), diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl index fc50ec6717..b127fe2e33 100644 --- a/lib/kernel/src/dist_util.erl +++ b/lib/kernel/src/dist_util.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2013. All Rights Reserved. +%% Copyright Ericsson AB 1999-2014. 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 @@ -116,7 +116,8 @@ make_this_flags(RequestType, OtherNode) -> ?DFLAG_UNICODE_IO bor ?DFLAG_DIST_HDR_ATOM_CACHE bor ?DFLAG_SMALL_ATOM_TAGS bor - ?DFLAG_UTF8_ATOMS). + ?DFLAG_UTF8_ATOMS bor + ?DFLAG_MAP_TAG). handshake_other_started(#hs_data{request_type=ReqType}=HSData0) -> {PreOtherFlags,Node,Version} = recv_name(HSData0), diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl index f7a815882b..ef605d0bfe 100644 --- a/lib/kernel/src/erts_debug.erl +++ b/lib/kernel/src/erts_debug.erl @@ -182,6 +182,11 @@ size(Tuple, Seen0, Sum0) when is_tuple(Tuple) -> Sum = Sum0 + 1 + tuple_size(Tuple), tuple_size(1, tuple_size(Tuple), Tuple, Seen, Sum) end; +size(Map, Seen0, Sum) when is_map(Map) -> + case remember_term(Map, Seen0) of + seen -> {Sum,Seen0}; + Seen -> map_size(Map, Seen, Sum) + end; size(Fun, Seen0, Sum) when is_function(Fun) -> case remember_term(Fun, Seen0) of seen -> {Sum,Seen0}; @@ -203,6 +208,12 @@ tuple_size(I, Sz, Tuple, Seen0, Sum0) -> {Sum,Seen} = size(element(I, Tuple), Seen0, Sum0), tuple_size(I+1, Sz, Tuple, Seen, Sum). +map_size(Map,Seen0,Sum0) -> + Kt = erts_internal:map_to_tuple_keys(Map), + Vs = maps:values(Map), + {Sum1,Seen1} = size(Kt,Seen0,Sum0), + fold_size(Vs,Seen1,Sum1+length(Vs)+3). + fun_size(Fun, Seen, Sum) -> case erlang:fun_info(Fun, type) of {type,external} -> @@ -210,14 +221,14 @@ fun_size(Fun, Seen, Sum) -> {type,local} -> Sz = erts_debug:flat_size(fun() -> ok end), {env,Env} = erlang:fun_info(Fun, env), - fun_size_1(Env, Seen, Sum+Sz+length(Env)) + fold_size(Env, Seen, Sum+Sz+length(Env)) end. -fun_size_1([H|T], Seen0, Sum0) -> +fold_size([H|T], Seen0, Sum0) -> {Sum,Seen} = size(H, Seen0, Sum0), - fun_size_1(T, Seen, Sum); -fun_size_1([], Seen, Sum) -> {Sum,Seen}. - + fold_size(T, Seen, Sum); +fold_size([], Seen, Sum) -> {Sum,Seen}. + remember_term(Term, Seen) -> case gb_trees:lookup(Term, Seen) of none -> gb_trees:insert(Term, [Term], Seen); diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index b5152018e0..20b703e084 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -111,7 +111,8 @@ -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 sendfile_option() :: {chunk_size, non_neg_integer()} + | {use_threads, boolean()}. -type file_info_option() :: {'time', 'local'} | {'time', 'universal'} | {'time', 'posix'}. %%% BIFs @@ -198,7 +199,8 @@ get_cwd(Drive) -> check_and_call(get_cwd, [file_name(Drive)]). -spec set_cwd(Dir) -> ok | {error, Reason} when - Dir :: name(), + Dir :: name() | EncodedBinary, + EncodedBinary :: binary(), Reason :: posix() | badarg | no_translation. set_cwd(Dirname) -> @@ -1229,8 +1231,7 @@ change_time(Name, {{AY, AM, AD}, {AH, AMin, ASec}}=Atime, 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, ?MAX_CHUNK_SIZE, [], [], []); sendfile(File, Sock, Offset, Bytes, Opts) -> ChunkSize0 = proplists:get_value(chunk_size, Opts, ?MAX_CHUNK_SIZE), ChunkSize = if ChunkSize0 > ?MAX_CHUNK_SIZE -> @@ -1240,8 +1241,7 @@ sendfile(File, Sock, Offset, Bytes, Opts) -> %% 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(File, Sock, Offset, Bytes, ChunkSize, [], [], Opts). %% sendfile/2 -spec sendfile(Filename, Socket) -> @@ -1261,17 +1261,17 @@ sendfile(Filename, Sock) -> %% Internal sendfile functions sendfile(#file_descriptor{ module = Mod } = Fd, Sock, Offset, Bytes, - ChunkSize, Headers, Trailers, Nodiskio, MNowait, Sync) + ChunkSize, Headers, Trailers, Opts) when is_port(Sock) -> case Mod:sendfile(Fd, Sock, Offset, Bytes, ChunkSize, Headers, Trailers, - Nodiskio, MNowait, Sync) of + Opts) of {error, enotsup} -> sendfile_fallback(Fd, Sock, Offset, Bytes, ChunkSize, Headers, Trailers); Else -> Else end; -sendfile(_,_,_,_,_,_,_,_,_,_) -> +sendfile(_,_,_,_,_,_,_,_) -> {error, badarg}. %%% diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl index ef878b8d0c..0a4edea452 100644 --- a/lib/kernel/src/global.erl +++ b/lib/kernel/src/global.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -1513,14 +1513,18 @@ delete_global_name(_Name, _Pid) -> -record(him, {node, locker, vsn, my_tag}). start_the_locker(DoTrace) -> - spawn_link(fun() -> init_the_locker(DoTrace) end). - -init_the_locker(DoTrace) -> - process_flag(trap_exit, true), % needed? - S0 = #multi{do_trace = DoTrace}, - S1 = update_locker_known({add, get_known()}, S0), - loop_the_locker(S1), - erlang:error(locker_exited). + spawn_link(init_the_locker_fun(DoTrace)). + +-spec init_the_locker_fun(boolean()) -> fun(() -> no_return()). + +init_the_locker_fun(DoTrace) -> + fun() -> + process_flag(trap_exit, true), % needed? + S0 = #multi{do_trace = DoTrace}, + S1 = update_locker_known({add, get_known()}, S0), + loop_the_locker(S1), + erlang:error(locker_exited) + end. loop_the_locker(S) -> ?trace({loop_the_locker,S}), diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl index e111cb800e..e5928c7b63 100644 --- a/lib/kernel/src/hipe_unified_loader.erl +++ b/lib/kernel/src/hipe_unified_loader.erl @@ -194,6 +194,13 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) -> CodeSize, CodeBinary, Refs, 0,[] % ColdSize, CRrefs ] = binary_to_term(Bin), + ?debug_msg("***** ErLLVM *****~nVersion: ~s~nCheckSum: ~w~nConstAlign: ~w~n" ++ + "ConstSize: ~w~nConstMap: ~w~nLabelMap: ~w~nExportMap ~w~nRefs ~w~n", + [Version, CheckSum, ConstAlign, ConstSize, ConstMap, LabelMap, ExportMap, + Refs]), + %% Write HiPE binary code to a file in the current directory in order to + %% debug by disassembling. + %% file:write_file("erl.o", CodeBinary, [binary]), %% Check that we are loading up-to-date code. version_check(Version, Mod), case hipe_bifs:check_crc(CheckSum) of @@ -203,6 +210,7 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) -> "please regenerate native code for this runtime system\n", [Mod]), bad_crc; true -> + put(closures_to_patch, []), %% Create data segment {ConstAddr,ConstMap2} = create_data_segment(ConstAlign, ConstSize, ConstMap), @@ -220,24 +228,33 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) -> {MFAs,Addresses} = exports(ExportMap, CodeAddress), %% Remove references to old versions of the module. ReferencesToPatch = get_refs_from(MFAs, []), + %% io:format("References to patch: ~w~n", [ReferencesToPatch]), ok = remove_refs_from(MFAs), %% Patch all dynamic references in the code. %% Function calls, Atoms, Constants, System calls ok = patch(Refs, CodeAddress, ConstMap2, Addresses, TrampolineMap), + %% Tell the system where the loaded funs are. %% (patches the BEAM code to redirect to native.) case Beam of [] -> + %% This module was previously loaded as BEAM code during system + %% start-up before the code server has started (-enable-native-libs + %% is active), so we must now patch the pre-existing entries in the + %% fun table with the native code addresses for all closures. + lists:foreach(fun({FE, DestAddress}) -> + hipe_bifs:set_native_address_in_fe(FE, DestAddress) + end, erase(closures_to_patch)), export_funs(Addresses), ok; BeamBinary when is_binary(BeamBinary) -> %% Find all closures in the code. + [] = erase(closures_to_patch), %Clean up, assertion. ClosurePatches = find_closure_patches(Refs), AddressesOfClosuresToPatch = calculate_addresses(ClosurePatches, CodeAddress, Addresses), export_funs(Addresses), - export_funs(Mod, BeamBinary, Addresses, AddressesOfClosuresToPatch), - ok + export_funs(Mod, BeamBinary, Addresses, AddressesOfClosuresToPatch) end, %% Redirect references to the old module to the new module's BEAM stub. patch_to_emu_step2(OldReferencesToPatch), @@ -245,6 +262,9 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) -> %% The call to export_funs/1 above updated the native addresses %% for the targets, so passing 'Addresses' is not needed. redirect(ReferencesToPatch), + %% Final clean up. + _ = erase(hipe_patch_closures), + _ = erase(hipe_assert_code_area), ?debug_msg("****************Loader Finished****************\n", []), {module,Mod} % for compatibility with code:load_file/1 end. @@ -562,12 +582,17 @@ patch_closure(DestMFA, Uniq, Index, Address, Addresses) -> case get(hipe_patch_closures) of false -> []; % This is taken care of when registering the module. - true -> % We are not loading a module patch these closures + true -> + %% We are replacing a previosly loaded BEAM module with native code, + %% so we must reference the pre-existing entries in the fun table + %% from the native code. We must delay actually patching the native + %% address into the fun entry to ensure that the native code cannot + %% be called until it has been completely fixed up. RemoteOrLocal = local, % closure code refs are local DestAddress = get_native_address(DestMFA, Addresses, RemoteOrLocal), BEAMAddress = hipe_bifs:fun_to_address(DestMFA), - FE = hipe_bifs:make_fe(DestAddress, mod(DestMFA), - {Uniq, Index, BEAMAddress}), + FE = hipe_bifs:get_fe(mod(DestMFA), {Uniq, Index, BEAMAddress}), + put(closures_to_patch, [{FE,DestAddress}|get(closures_to_patch)]), ?debug_msg("Patch FE(~w) to 0x~.16b->0x~.16b (emu:0x~.16b)\n", [DestMFA, FE, DestAddress, BEAMAddress]), ?ASSERT(assert_local_patch(Address)), diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 792593246a..41d422d7d4 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2013. All Rights Reserved. +%% Copyright Ericsson AB 1997-2014. 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 @@ -597,8 +597,7 @@ getservbyname(Name, Protocol) when is_atom(Name) -> Error -> Error end. --spec ntoa(IpAddress) -> - {ok, Address} | {error, einval} when +-spec ntoa(IpAddress) -> Address | {error, einval} when Address :: string(), IpAddress :: ip_address(). ntoa(Addr) -> diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl index 2461f3ff25..fdc244f959 100644 --- a/lib/kernel/src/inet_config.erl +++ b/lib/kernel/src/inet_config.erl @@ -197,6 +197,9 @@ do_load_resolv({win32,Type}, longnames) -> win32_load_from_registry(Type), inet_db:set_lookup([native]); +do_load_resolv({ose,_}, _) -> + inet_db:set_lookup([file]); + do_load_resolv(_, _) -> inet_db:set_lookup([native]). diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src index cb8c98ab06..5658c6b6cf 100644 --- a/lib/kernel/src/kernel.app.src +++ b/lib/kernel/src/kernel.app.src @@ -114,6 +114,7 @@ pg2]}, {applications, []}, {env, [{error_logger, tty}]}, - {mod, {kernel, []}} + {mod, {kernel, []}}, + {runtime_dependencies, ["erts-6.0", "stdlib-2.0", "sasl-2.4"]} ] }. diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src index b946c2d1af..f8f4cc1ec2 100644 --- a/lib/kernel/src/kernel.appup.src +++ b/lib/kernel/src/kernel.appup.src @@ -1,7 +1,7 @@ %% -*- erlang -*- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2013. All Rights Reserved. +%% Copyright Ericsson AB 1999-2014. 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 @@ -16,12 +16,10 @@ %% %% %CopyrightEnd% {"%VSN%", - %% Up from - max two major revisions back + %% Up from - max one major revision back [{<<"3\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R17 - {<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 - {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R15 - %% Down to - max two major revisions back + {<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R16 + %% Down to - max one major revision back [{<<"3\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R17 - {<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 - {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R15 + {<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R16 }. diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl index 9ffa9adeab..187fd0001b 100644 --- a/lib/kernel/src/os.erl +++ b/lib/kernel/src/os.erl @@ -67,7 +67,7 @@ unsetenv(_) -> %%% End of BIFs -spec type() -> {Osfamily, Osname} when - Osfamily :: unix | win32, + Osfamily :: unix | win32 | ose, Osname :: atom(). type() -> @@ -230,7 +230,9 @@ unix_cmd(Cmd) -> %% and the commands are read from standard input. We set the %% $1 parameter for easy identification of the resident shell. %% --define(SHELL, "/bin/sh -s unix:cmd 2>&1"). +-define(ROOT, "/"). +-define(ROOT_ANDROID, "/system"). +-define(SHELL, "bin/sh -s unix:cmd 2>&1"). -define(PORT_CREATOR_NAME, os_cmd_port_creator). %% @@ -280,7 +282,12 @@ start_port_srv(Request) -> end. start_port_srv_handle({Ref,Client}) -> - Reply = try open_port({spawn, ?SHELL},[stream]) of + Path = case lists:reverse(erlang:system_info(system_architecture)) of + % androideabi + "ibaediordna" ++ _ -> filename:join([?ROOT_ANDROID, ?SHELL]); + _ -> filename:join([?ROOT, ?SHELL]) + end, + Reply = try open_port({spawn, Path},[stream]) of Port when is_port(Port) -> (catch port_connect(Port, Client)), unlink(Port), diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl index 7dc51495f7..2300b7e901 100644 --- a/lib/kernel/src/rpc.erl +++ b/lib/kernel/src/rpc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -66,7 +66,7 @@ %%------------------------------------------------------------------------ --type state() :: gb_tree(). +-type state() :: gb_trees:tree(pid(), {pid(), reference()}). %%------------------------------------------------------------------------ diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl index 9ec8a15861..4901206c8e 100644 --- a/lib/kernel/test/application_SUITE.erl +++ b/lib/kernel/test/application_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2013. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -33,10 +33,10 @@ permit_false_start_local/1, permit_false_start_dist/1, script_start/1, nodedown_start/1, init2973/0, loop2973/0, loop5606/1]). --export([config_change/1, +-export([config_change/1, persistent_env/1, distr_changed_tc1/1, distr_changed_tc2/1, ensure_started/1, ensure_all_started/1, - shutdown_func/1, do_shutdown/1, shutdown_timeout/1]). + shutdown_func/1, do_shutdown/1, shutdown_timeout/1, shutdown_deadlock/1]). -define(TESTCASE, testcase_name). -define(testcase, ?config(?TESTCASE, Config)). @@ -53,7 +53,9 @@ all() -> load_use_cache, ensure_started, {group, reported_bugs}, start_phases, script_start, nodedown_start, permit_false_start_local, permit_false_start_dist, get_key, get_env, ensure_all_started, - {group, distr_changed}, config_change, shutdown_func, shutdown_timeout]. + {group, distr_changed}, config_change, shutdown_func, shutdown_timeout, + shutdown_deadlock, + persistent_env]. groups() -> [{reported_bugs, [], @@ -960,7 +962,7 @@ nodedown_start(Conf) when is_list(Conf) -> ensure_started(suite) -> []; ensure_started(doc) -> ["Test application:ensure_started/1."]; -ensure_started(Conf) -> +ensure_started(_Conf) -> {ok, Fd} = file:open("app1.app", [write]), w_app1(Fd), @@ -980,7 +982,7 @@ ensure_started(Conf) -> ensure_all_started(suite) -> []; ensure_all_started(doc) -> ["Test application:ensure_all_started/1-2."]; -ensure_all_started(Conf) -> +ensure_all_started(_Conf) -> {ok, Fd1} = file:open("app1.app", [write]), w_app1(Fd1), @@ -1074,10 +1076,13 @@ otp_1586(Conf) when is_list(Conf) -> {ok, Fd} = file:open(filename:join(Dir, "app5.app"), [write]), w_app5(Fd), file:close(Fd), - code:add_patha(Dir), - ok = application:load(app4()), - ok = application:unload(app4), - ok. + try + true = code:add_patha(Dir), + ok = application:load(app4()), + ok = application:unload(app4) + after + _ = code:del_path(Dir) + end. %%----------------------------------------------------------------- %% Ticket: OTP-2078 @@ -1947,14 +1952,22 @@ config_change(Conf) when is_list(Conf) -> %% Find out application data from boot script Boot = filename:join([code:root_dir(), "bin", "start.boot"]), {ok, Bin} = file:read_file(Boot), - Appls = get_appls(binary_to_term(Bin)), + Appls0 = get_appls(binary_to_term(Bin)), + + %% And add app1 in order to test OTP-11864 - included config files + %% not read for new (not already loaded) applications + Appls = [app1() | Appls0], %% Simulate contents of "sys.config" Config = [{stdlib, [{par1,sys},{par2,sys}]}, "t1", "t2.config", filename:join([DataDir, "subdir", "t3"]), - {stdlib, [{par6,sys}]}], + {stdlib, [{par6,sys}]}, + "t4.config"], + + %% Check that app1 is not loaded + false = lists:keymember(app1,1,application:loaded_applications()), %% Order application_controller to update configuration ok = application_controller:change_application_data(Appls, @@ -1969,6 +1982,13 @@ config_change(Conf) when is_list(Conf) -> {value, {par5,t3}} = lists:keysearch(par5, 1, Env), {value, {par6,sys}} = lists:keysearch(par6, 1, Env), + %% Check that app1 parameters are correctly set after loading + [] = application:get_all_env(app1), + application:load(app1()), + App1Env = application:get_all_env(app1), + {value, {par1,t4}} = lists:keysearch(par1, 1, App1Env), + application:unload(app1), + ok = file:set_cwd(CWD). %% This function is stolen from SASL module release_handler, OTP R10B @@ -1987,6 +2007,51 @@ get_appls([_ | T], Res) -> get_appls([], Res) -> Res. + +persistent_env(suite) -> + []; +persistent_env(doc) -> + ["Test set_env/4 and unset_env/3 with persistent true"]; +persistent_env(Conf) when is_list(Conf) -> + ok = application:set_env(appinc, own2, persist, [{persistent, true}]), + ok = application:set_env(appinc, key1, persist, [{persistent, true}]), + + %% own_env1 and own2 are set in appinc + ok = application:load(appinc()), + {ok, value1} = application:get_env(appinc, own_env1), + {ok, persist} = application:get_env(appinc, own2), + {ok, persist} = application:get_env(appinc, key1), + + %% Changing the environment after loaded reflects and should persist + ok = application:set_env(appinc, own_env1, persist, [{persistent, true}]), + {ok, persist} = application:get_env(appinc, own_env1), + {ok, persist} = application:get_env(appinc, own2), + {ok, persist} = application:get_env(appinc, key1), + + %% On reload, own_env1, own2 and key1 should all persist + ok = application:unload(appinc), + ok = application:load(appinc()), + {ok, persist} = application:get_env(appinc, own_env1), + {ok, persist} = application:get_env(appinc, own2), + {ok, persist} = application:get_env(appinc, key1), + + %% Unset own_env1 and key1, own2 should still persist + ok = application:unset_env(appinc, own_env1, [{persistent, true}]), + ok = application:unset_env(appinc, key1, [{persistent, true}]), + undefined = application:get_env(appinc, own_env1), + {ok, persist} = application:get_env(appinc, own2), + undefined = application:get_env(appinc, key1), + + %% own_env1 should be back to its application value on reload + ok = application:unload(appinc), + ok = application:load(appinc()), + {ok, value1} = application:get_env(appinc, own_env1), + {ok, persist} = application:get_env(appinc, own2), + undefined = application:get_env(appinc, key1), + + %% Clean up + ok = application:unload(appinc). + %%%----------------------------------------------------------------- %%% Tests the 'shutdown_func' kernel config parameter %%%----------------------------------------------------------------- @@ -2051,7 +2116,32 @@ shutdown_timeout(Config) when is_list(Config) -> end, ok. +%%%----------------------------------------------------------------- +%%% Provokes a (previous) application shutdown deadlock +%%%----------------------------------------------------------------- +shutdown_deadlock(Config) when is_list(Config) -> + DataDir = ?config(data_dir,Config), + code:add_path(filename:join([DataDir,deadlock])), + %% ok = rpc:call(Cp1, application, start, [sasl]), + ok = application:start(deadlock), + Tester = self(), + application:set_env(deadlock, fail_stop, Tester), + spawn(fun() -> Tester ! {stop, application:stop(deadlock)} end), + receive + {deadlock, Server} -> + spawn(fun() -> + Master = application_controller:get_master(deadlock), + Child = application_master:get_child(Master), + Tester ! {child, Child} + end), + timer:sleep(100), + erlang:display({self(), "Sending Continue", Server}), + Server ! continue + end, + [_|_] = application:which_applications(), + application:unload(deadlock), % clean up! + ok. %%----------------------------------------------------------------- diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app index 0c1001bed6..233c7a3f76 100644 --- a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app +++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app @@ -4,5 +4,5 @@ {applications, [kernel, stdlib, sasl]}, {modules, [deadlock]}, {mod, {deadlock, []}}, - {env, [{fail_start, false}]} + {env, [{fail_start, false}, {fail_stop, false}]} ]}. diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl index 5f68bf9078..3ef6105371 100644 --- a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl +++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl @@ -21,7 +21,7 @@ init([sup]) -> {ok, {{one_for_one, 5, 10}, [ { sasl_syslog_dm, {?MODULE, start_link, []}, - permanent, brutal_kill, worker, + permanent, 25000, worker, [deadlock] } ]}}; @@ -32,6 +32,8 @@ init([sup]) -> init([child]) -> case application:get_env(deadlock, fail_start) of {ok, false} -> + process_flag(trap_exit, true), + io:format("~p: Traps exit~n",[?MODULE]), %% we must not fail on the first init, otherwise supervisor %% terminates immediately {ok, []}; @@ -50,6 +52,14 @@ handle_info(_Msg, State) -> {noreply, State}. terminate(_Reason, _State) -> + case application:get_env(deadlock, fail_stop) of + {ok, false} -> ok; + {ok, Tester} -> + Tester ! {deadlock, self()}, + io:format("~p: Waiting in terminate (~p)~n",[?MODULE,Tester]), + receive continue -> ok end + end, + io:format("~p: terminates~n", [?MODULE]), ok. code_change(_OldVsn, State, _Extra) -> diff --git a/lib/kernel/test/application_SUITE_data/t4.config b/lib/kernel/test/application_SUITE_data/t4.config new file mode 100644 index 0000000000..8b2bc52c01 --- /dev/null +++ b/lib/kernel/test/application_SUITE_data/t4.config @@ -0,0 +1 @@ +[{app1, [{par1,t4}]}].
\ No newline at end of file diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 17983e972d..afedc17e57 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -37,8 +37,7 @@ native_early_modules/1, get_mode/1]). -export([init_per_testcase/2, end_per_testcase/2, - init_per_suite/1, end_per_suite/1, - sticky_compiler/1]). + init_per_suite/1, end_per_suite/1]). %% error_logger -export([init/1, @@ -55,7 +54,7 @@ all() -> delete, purge, purge_many_exits, soft_purge, is_loaded, all_loaded, load_binary, dir_req, object_code, set_path_file, upgrade, - pa_pz_option, add_del_path, dir_disappeared, + sticky_dir, pa_pz_option, add_del_path, dir_disappeared, ext_mod_dep, clash, load_cached, start_node_with_cache, add_and_rehash, where_is_file_no_cache, where_is_file_cached, purge_stacktrace, mult_lib_roots, @@ -219,6 +218,13 @@ del_path(suite) -> []; del_path(doc) -> []; del_path(Config) when is_list(Config) -> P = code:get_path(), + try + del_path_1(P) + after + code:set_path(P) + end. + +del_path_1(P) -> test_server:format("Initial code:get_path()=~p~n",[P]), {'EXIT',_} = (catch code:del_path(3)), false = code:del_path(my_dummy_name), @@ -226,19 +232,22 @@ del_path(Config) when is_list(Config) -> Dir = filename:join([code:lib_dir(kernel),"ebin"]), test_server:format("kernel dir: ~p~n",[Dir]), - true = code:del_path(kernel), NewP = code:get_path(), test_server:format("Path after removing 'kernel':~p~n",[NewP]), ReferenceP = lists:delete(Dir,P), test_server:format("Reference path:~p~n",[ReferenceP]), NewP = ReferenceP, % check that dir is deleted + code:set_path(P), + %% An superfluous "/" should also work. + true = code:del_path("kernel/"), + NewP = ReferenceP, % check that dir is deleted code:set_path(P), + true = code:del_path(Dir), NewP1 = code:get_path(), NewP1 = lists:delete(Dir,P), % check that dir is deleted - code:set_path(P), ok. replace_path(suite) -> []; @@ -577,35 +586,42 @@ sticky_dir(suite) -> []; sticky_dir(doc) -> ["Test that a module with the same name as a module in ", "a sticky directory cannot be loaded."]; sticky_dir(Config) when is_list(Config) -> - MyDir=filename:dirname(code:which(?MODULE)), - {ok, Node}=?t:start_node(sticky_dir, slave,[{args, "-pa \""++MyDir++"\""}]), - File=filename:join([?config(data_dir, Config), "calendar"]), - Ret=rpc:call(Node, ?MODULE, sticky_compiler, [File]), + Pa = filename:dirname(code:which(?MODULE)), + {ok,Node} = ?t:start_node(sticky_dir, slave, [{args,"-pa "++Pa}]), + Mods = [code,lists,erlang,init], + OutDir = filename:join(?config(priv_dir, Config), sticky_dir), + _ = file:make_dir(OutDir), + Ret = rpc:call(Node, erlang, apply, + [fun sticky_compiler/2,[Mods,OutDir]]), case Ret of - fail -> - ?t:fail("c:c allowed a sticky module to be compiled and loaded."); - ok -> + [] -> ok; Other -> - test_server:format("Other: ~p",[Other]) + io:format("~p\n", [Other]), + ?t:fail() end, - ?t:stop_node(Node). + ?t:stop_node(Node), + ok. -sticky_compiler(File) -> - Compiled=File++code:objfile_extension(), - Dir=filename:dirname(File), - code:add_patha(Dir), - file:delete(Compiled), - case c:c(File, [{outdir, Dir}]) of - {ok, Module} -> - case catch Module:test(apa) of - {error, _} -> - fail; - {'EXIT', _} -> - ok - end; - Other -> - test_server:format("c:c(~p) returned: ~p",[File, Other]), +sticky_compiler(Files, PrivDir) -> + code:add_patha(PrivDir), + Rets = [do_sticky_compile(F, PrivDir) || F <- Files], + [R || R <- Rets, R =/= ok]. + +do_sticky_compile(Mod, Dir) -> + %% Make sure that the module is loaded. A module being sticky + %% only prevents it from begin reloaded, not from being loaded + %% from the wrong place to begin with. + Mod = Mod:module_info(module), + File = filename:append(Dir, atom_to_list(Mod)), + Src = io_lib:format("-module(~s).\n" + "-export([test/1]).\n" + "test(me) -> fail.\n", [Mod]), + ok = file:write_file(File++".erl", Src), + case c:c(File, [{outdir,Dir}]) of + {ok,Module} -> + Module:test(me); + {error,sticky_directory} -> ok end. @@ -653,7 +669,7 @@ clash(Config) when is_list(Config) -> DDir = ?config(data_dir,Config)++"clash/", P = code:get_path(), [TestServerPath|_] = [Path || Path <- code:get_path(), - re:run(Path,"test_server/?$",[]) /= nomatch], + re:run(Path,"test_server/?$",[unicode]) /= nomatch], %% test non-clashing entries @@ -1527,7 +1543,10 @@ create_big_script(Config,Local) -> Leftover <- UnloadFix, lists:keymember(Leftover,1,InitialApplications) ], %% Now we should have only "real" applications... - [application:load(list_to_atom(Y)) || {match,[Y]} <- [ re:run(X,code:lib_dir()++"/"++"([^/-]*).*/ebin",[{capture,[1],list}]) || X <- code:get_path()],filter_app(Y,Local)], + [application:load(list_to_atom(Y)) + || {match,[Y]} <- [re:run(X,code:lib_dir()++"/"++"([^/-]*).*/ebin", + [{capture,[1],list},unicode]) || + X <- code:get_path()],filter_app(Y,Local)], Apps = [ {N,V} || {N,_,V} <- application:loaded_applications()], {ok,Fd} = file:open(Name ++ ".rel", [write]), io:format(Fd, diff --git a/lib/kernel/test/code_SUITE_data/calendar.erl b/lib/kernel/test/code_SUITE_data/calendar.erl deleted file mode 100644 index c1a4a1c12a..0000000000 --- a/lib/kernel/test/code_SUITE_data/calendar.erl +++ /dev/null @@ -1,23 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 1997-2009. 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(calendar). --export([test/1]). - -test(apa) -> - {error, this_function_should_not_be_called}. diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index c75639ae7e..f6d6cd94ab 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -161,7 +161,13 @@ init_per_suite(Config) when is_list(Config) -> ok -> [{sasl,started}] end, - ok = application:start(os_mon), + ok = case os:type() of + {ose,_} -> + ok; + _ -> + application:start(os_mon) + end, + case os:type() of {win32, _} -> Priv = ?config(priv_dir, Config), @@ -185,7 +191,13 @@ end_per_suite(Config) when is_list(Config) -> _ -> ok end, - application:stop(os_mon), + + case os:type() of + {ose,_} -> + ok; + _ -> + application:stop(os_mon) + end, case proplists:get_value(sasl, Config) of started -> application:stop(sasl); @@ -416,7 +428,13 @@ make_del_dir(Config) when is_list(Config) -> % because there are processes having that directory as current. ?line ok = ?FILE_MODULE:make_dir(NewDir), ?line {ok,CurrentDir} = file:get_cwd(), - ?line ok = ?FILE_MODULE:set_cwd(NewDir), + case {os:type(), length(NewDir) >= 260 } of + {{win32,_}, true} -> + io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH)\n", []), + io:format("\nNewDir = ~p\n", [NewDir]); + _ -> + ?line ok = ?FILE_MODULE:set_cwd(NewDir) + end, try %% Check that we get an error when trying to create... %% a deep directory @@ -473,32 +491,39 @@ cur_dir_0(Config) when is_list(Config) -> atom_to_list(?MODULE) ++"_curdir"), ?line ok = ?FILE_MODULE:make_dir(NewDir), - ?line io:format("cd to ~s",[NewDir]), - ?line ok = ?FILE_MODULE:set_cwd(NewDir), - - %% Create a file in the new current directory, and check that it - %% really is created there - ?line UncommonName = "uncommon.fil", - ?line {ok,Fd} = ?FILE_MODULE:open(UncommonName,read_write), - ?line ok = ?FILE_MODULE:close(Fd), - ?line {ok,NewDirFiles} = ?FILE_MODULE:list_dir("."), - ?line true = lists:member(UncommonName,NewDirFiles), - - %% Delete the directory and return to the old current directory - %% and check that the created file isn't there (too!) - ?line expect({error, einval}, {error, eacces}, - ?FILE_MODULE:del_dir(NewDir)), - ?line ?FILE_MODULE:delete(UncommonName), - ?line {ok,[]} = ?FILE_MODULE:list_dir("."), - ?line ok = ?FILE_MODULE:set_cwd(Dir1), - ?line io:format("cd back to ~s",[Dir1]), - ?line ok = ?FILE_MODULE:del_dir(NewDir), - ?line {error, enoent} = ?FILE_MODULE:set_cwd(NewDir), - ?line ok = ?FILE_MODULE:set_cwd(Dir1), - ?line io:format("cd back to ~s",[Dir1]), - ?line {ok,OldDirFiles} = ?FILE_MODULE:list_dir("."), - ?line false = lists:member(UncommonName,OldDirFiles), - + case {os:type(), length(NewDir) >= 260} of + {{win32,_}, true} -> + io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH):\n"), + io:format("\nNewDir = ~p\n", [NewDir]); + _ -> + io:format("cd to ~s",[NewDir]), + ok = ?FILE_MODULE:set_cwd(NewDir), + + %% Create a file in the new current directory, and check that it + %% really is created there + UncommonName = "uncommon.fil", + {ok,Fd} = ?FILE_MODULE:open(UncommonName,read_write), + ok = ?FILE_MODULE:close(Fd), + {ok,NewDirFiles} = ?FILE_MODULE:list_dir("."), + true = lists:member(UncommonName,NewDirFiles), + + %% Delete the directory and return to the old current directory + %% and check that the created file isn't there (too!) + expect({error, einval}, {error, eacces}, + ?FILE_MODULE:del_dir(NewDir)), + ?FILE_MODULE:delete(UncommonName), + {ok,[]} = ?FILE_MODULE:list_dir("."), + ok = ?FILE_MODULE:set_cwd(Dir1), + io:format("cd back to ~s",[Dir1]), + + ok = ?FILE_MODULE:del_dir(NewDir), + {error, enoent} = ?FILE_MODULE:set_cwd(NewDir), + ok = ?FILE_MODULE:set_cwd(Dir1), + io:format("cd back to ~s",[Dir1]), + {ok,OldDirFiles} = ?FILE_MODULE:list_dir("."), + false = lists:member(UncommonName,OldDirFiles) + end, + %% Try doing some bad things ?line {error, badarg} = ?FILE_MODULE:set_cwd({foo,bar}), ?line {error, enoent} = ?FILE_MODULE:set_cwd(""), @@ -525,11 +550,11 @@ cur_dir_1(Config) when is_list(Config) -> ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line case os:type() of - {unix, _} -> - ?line {error, enotsup} = ?FILE_MODULE:get_cwd("d:"); - {win32, _} -> - win_cur_dir_1(Config) - end, + {win32, _} -> + win_cur_dir_1(Config); + _ -> + ?line {error, enotsup} = ?FILE_MODULE:get_cwd("d:") + end, ?line [] = flush(), ?line test_server:timetrap_cancel(Dog), ok. @@ -712,7 +737,10 @@ open1(Config) when is_list(Config) -> ?line io:format(Fd1,Str,[]), ?line {ok,0} = ?FILE_MODULE:position(Fd1,bof), ?line Str = io:get_line(Fd1,''), - ?line Str = io:get_line(Fd2,''), + ?line case io:get_line(Fd2,'') of + Str -> Str; + eof -> Str + end, ?line ok = ?FILE_MODULE:close(Fd2), ?line {ok,0} = ?FILE_MODULE:position(Fd1,bof), ?line ok = ?FILE_MODULE:truncate(Fd1), @@ -1246,7 +1274,7 @@ file_info_basic_directory(Config) when is_list(Config) -> ?line test_directory("/", read_write), ?line test_directory("c:/", read_write), ?line test_directory("c:\\", read_write); - {unix, _} -> + _ -> ?line test_directory("/", read) end, test_server:timetrap_cancel(Dog). @@ -1967,7 +1995,6 @@ names(Config) when is_list(Config) -> ?line Name1 = filename:join(RootDir, FileName), ?line Name2 = [RootDir,"/","foo1",".","fil"], ?line Name3 = [RootDir,"/",foo,$1,[[[],[],'.']],"f",il], - ?line Name4 = list_to_atom(Name1), ?line {ok,Fd0} = ?FILE_MODULE:open(Name1,write), ?line ok = ?FILE_MODULE:close(Fd0), @@ -1980,23 +2007,33 @@ names(Config) when is_list(Config) -> ?line ok = ?FILE_MODULE:close(Fd2), ?line {ok,Fd3} = ?FILE_MODULE:open(Name3,read), ?line ok = ?FILE_MODULE:close(Fd3), - ?line {ok,Fd4} = ?FILE_MODULE:open(Name4,read), - ?line ok = ?FILE_MODULE:close(Fd4), + case length(Name1) > 255 of + true -> + io:format("Path too long for an atom:\n\n~p\n", [Name1]); + false -> + Name4 = list_to_atom(Name1), + {ok,Fd4} = ?FILE_MODULE:open(Name4,read), + ok = ?FILE_MODULE:close(Fd4) + end, %% Try some path names ?line Path1 = RootDir, ?line Path2 = [RootDir], ?line Path3 = ['',[],[RootDir,[[]]]], - ?line Path4 = list_to_atom(Path1), ?line {ok,Fd11,_} = ?FILE_MODULE:path_open([Path1],FileName,read), ?line ok = ?FILE_MODULE:close(Fd11), ?line {ok,Fd12,_} = ?FILE_MODULE:path_open([Path2],FileName,read), ?line ok = ?FILE_MODULE:close(Fd12), ?line {ok,Fd13,_} = ?FILE_MODULE:path_open([Path3],FileName,read), ?line ok = ?FILE_MODULE:close(Fd13), - ?line {ok,Fd14,_} = ?FILE_MODULE:path_open([Path4],FileName,read), - ?line ok = ?FILE_MODULE:close(Fd14), - + case length(Path1) > 255 of + true-> + io:format("Path too long for an atom:\n\n~p\n", [Path1]); + false -> + Path4 = list_to_atom(Path1), + {ok,Fd14,_} = ?FILE_MODULE:path_open([Path4],FileName,read), + ok = ?FILE_MODULE:close(Fd14) + end, ?line [] = flush(), ?line test_server:timetrap_cancel(Dog), ok. @@ -2030,15 +2067,15 @@ e_delete(Config) when is_list(Config) -> %% No permission. ?line case os:type() of - {unix, _} -> + {win32, _} -> + %% Remove a character device. + ?line {error, eacces} = ?FILE_MODULE:delete("nul"); + _ -> ?line ?FILE_MODULE:write_file_info( Base, #file_info {mode=0}), ?line {error, eacces} = ?FILE_MODULE:delete(Afile), ?line ?FILE_MODULE:write_file_info( - Base, #file_info {mode=8#600}); - {win32, _} -> - %% Remove a character device. - ?line {error, eacces} = ?FILE_MODULE:delete("nul") + Base, #file_info {mode=8#600}) end, ?line [] = flush(), @@ -2140,6 +2177,9 @@ e_rename(Config) when is_list(Config) -> %% At least Windows NT can %% successfully move a file to %% another drive. + ok; + {ose, _} -> + %% disabled for now ok end, [] = flush(), @@ -2171,13 +2211,13 @@ e_make_dir(Config) when is_list(Config) -> %% No permission (on Unix only). case os:type() of - {unix, _} -> + {win32, _} -> + ok; + _ -> ?FILE_MODULE:write_file_info(Base, #file_info {mode=0}), {error, eacces} = ?FILE_MODULE:make_dir(filename:join(Base, "xxxx")), ?FILE_MODULE:write_file_info( - Base, #file_info {mode=8#600}); - {win32, _} -> - ok + Base, #file_info {mode=8#600}) end, test_server:timetrap_cancel(Dog), ok. @@ -2220,14 +2260,14 @@ e_del_dir(Config) when is_list(Config) -> %% No permission. case os:type() of - {unix, _} -> + {win32, _} -> + ok; + _ -> ADirectory = filename:join(Base, "no_perm"), ok = ?FILE_MODULE:make_dir(ADirectory), ?FILE_MODULE:write_file_info( Base, #file_info {mode=0}), {error, eacces} = ?FILE_MODULE:del_dir(ADirectory), - ?FILE_MODULE:write_file_info( Base, #file_info {mode=8#600}); - {win32, _} -> - ok + ?FILE_MODULE:write_file_info( Base, #file_info {mode=8#600}) end, [] = flush(), test_server:timetrap_cancel(Dog), @@ -2655,6 +2695,9 @@ symlinks(Config) when is_list(Config) -> case ?FILE_MODULE:make_symlink(Name, Alias) of {error, enotsup} -> {skipped, "Links not supported on this platform"}; + {error, eperm} -> + {win32,_} = os:type(), + {skipped, "Windows user not privileged to create symlinks"}; ok -> ?line {ok, Info1} = ?FILE_MODULE:read_file_info(Name), ?line {ok, Info1} = ?FILE_MODULE:read_file_info(Alias), @@ -3581,7 +3624,11 @@ otp_10852(Config) when is_list(Config) -> ok = rpc_call(Node, list_dir_all, [B]), ok = rpc_call(Node, read_file, [B]), ok = rpc_call(Node, make_link, [B,B]), - ok = rpc_call(Node, make_symlink, [B,B]), + case rpc_call(Node, make_symlink, [B,B]) of + ok -> ok; + {error, E} when (E =:= enotsup) or (E =:= eperm) -> + {win32,_} = os:type() + end, ok = rpc_call(Node, delete, [B]), ok = rpc_call(Node, make_dir, [B]), ok = rpc_call(Node, del_dir, [B]), diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index ee8bfcceb1..2df4bf7c95 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2013. All Rights Reserved. +%% Copyright Ericsson AB 1998-2014. 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 @@ -50,6 +50,14 @@ oct_acceptor/1, otp_7731_server/1, zombie_server/2, do_iter_max_socks/2]). +init_per_testcase(wrapping_oct, Config) when is_list(Config) -> + Dog = case os:type() of + {ose,_} -> + test_server:timetrap(test_server:minutes(20)); + _Else -> + test_server:timetrap(test_server:seconds(600)) + end, + [{watchdog, Dog}|Config]; init_per_testcase(iter_max_socks, Config) when is_list(Config) -> Dog = case os:type() of {win32,_} -> @@ -58,6 +66,17 @@ init_per_testcase(iter_max_socks, Config) when is_list(Config) -> test_server:timetrap(test_server:seconds(240)) end, [{watchdog, Dog}|Config]; +init_per_testcase(accept_system_limit, Config) when is_list(Config) -> + case os:type() of + {ose,_} -> + {skip,"Skip in OSE"}; + _ -> + Dog = test_server:timetrap(test_server:seconds(240)), + [{watchdog,Dog}|Config] + end; +init_per_testcase(wrapping_oct, Config) when is_list(Config) -> + Dog = test_server:timetrap(test_server:seconds(600)), + [{watchdog, Dog}|Config]; init_per_testcase(_Func, Config) when is_list(Config) -> Dog = test_server:timetrap(test_server:seconds(240)), [{watchdog, Dog}|Config]. @@ -537,7 +556,6 @@ otp_3924(Config) when is_list(Config) -> otp_3924_1(MaxDelay). otp_3924_1(MaxDelay) -> - Dog = test_server:timetrap(test_server:seconds(240)), ?line {ok, Node} = start_node(otp_3924), ?line DataLen = 100*1024, ?line Data = otp_3924_data(DataLen), @@ -548,7 +566,6 @@ otp_3924_1(MaxDelay) -> ?line ok = otp_3924(MaxDelay, Node, Data, DataLen, N) end), ?line test_server:stop_node(Node), - test_server:timetrap_cancel(Dog), ok. otp_3924(MaxDelay, Node, Data, DataLen, N) -> @@ -1953,7 +1970,9 @@ accept_system_limit(doc) -> accept_system_limit(Config) when is_list(Config) -> ?line {ok, LS} = gen_tcp:listen(0, []), ?line {ok, TcpPort} = inet:port(LS), - ?line Connector = spawn_link(fun () -> connector(TcpPort) end), + Me = self(), + ?line Connector = spawn_link(fun () -> connector(TcpPort, Me) end), + receive {Connector, sync} -> Connector ! {self(), continue} end, ?line ok = acceptor(LS, false, []), ?line Connector ! stop, ok. @@ -1970,8 +1989,10 @@ acceptor(LS, GotSL, A) -> error end. -connector(TcpPort) -> +connector(TcpPort, Tester) -> ManyPorts = open_ports([]), + Tester ! {self(), sync}, + receive {Tester, continue} -> timer:sleep(100) end, ConnF = fun (Port) -> case catch gen_tcp:connect({127,0,0,1}, TcpPort, []) of {ok, Sock} -> @@ -2705,13 +2726,11 @@ wrapping_oct(doc) -> wrapping_oct(suite) -> []; wrapping_oct(Config) when is_list(Config) -> - Dog = test_server:timetrap(test_server:seconds(600)), {ok,Sock} = gen_tcp:listen(0,[{active,false},{mode,binary}]), {ok,Port} = inet:port(Sock), spawn_link(?MODULE,oct_acceptor,[Sock]), Res = oct_datapump(Port,16#1FFFFFFFF), gen_tcp:close(Sock), - test_server:timetrap_cancel(Dog), ok = Res, ok. diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl index 320b23bea1..35d3b75b34 100644 --- a/lib/kernel/test/heart_SUITE.erl +++ b/lib/kernel/test/heart_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2012. All Rights Reserved. +%% Copyright Ericsson AB 1996-2014. 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 @@ -93,10 +93,10 @@ start_check(Type, Name) -> start_check(Type, Name, []). start_check(Type, Name, Envs) -> Args = case ?t:os_type() of - {win32,_} -> - "-heart " ++ env_encode([{"HEART_COMMAND", no_reboot}|Envs]); + {win32,_} -> + "+t50000 -heart " ++ env_encode([{"HEART_COMMAND", no_reboot}|Envs]); _ -> - "-heart " ++ env_encode(Envs) + "+t50000 -heart " ++ env_encode(Envs) end, {ok, Node} = case Type of loose -> diff --git a/lib/kernel/test/kernel_SUITE.erl b/lib/kernel/test/kernel_SUITE.erl index 0f29d895e5..1884e8cf58 100644 --- a/lib/kernel/test/kernel_SUITE.erl +++ b/lib/kernel/test/kernel_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2014. 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 @@ -23,9 +23,6 @@ -include_lib("test_server/include/test_server.hrl"). -% Default timetrap timeout (set in init_per_testcase). --define(default_timeout, ?t:minutes(1)). - % Test server specific exports -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2]). @@ -59,11 +56,8 @@ end_per_group(_GroupName, Config) -> init_per_testcase(_Case, Config) -> - ?line Dog=test_server:timetrap(?default_timeout), - [{watchdog, Dog}|Config]. -end_per_testcase(_Case, Config) -> - Dog=?config(watchdog, Config), - test_server:timetrap_cancel(Dog), + Config. +end_per_testcase(_Case, _Config) -> ok. % @@ -78,56 +72,80 @@ app_test(Config) when is_list(Config) -> ok. -%% Test that appup allows upgrade from/downgrade to a maximum of two -%% major releases back. +%% Test that appup allows upgrade from/downgrade to a maximum of one +%% major release back. appup_test(_Config) -> - application:load(kernel), - {_,_,Vsn} = lists:keyfind(kernel,1,application:loaded_applications()), - AppupFile = filename:join([code:lib_dir(kernel),ebin,"kernel.appup"]), + appup_tests(kernel,create_test_vsns(kernel)). + +appup_tests(_App,{[],[]}) -> + {skip,"no previous releases available"}; +appup_tests(App,{OkVsns,NokVsns}) -> + application:load(App), + {_,_,Vsn} = lists:keyfind(App,1,application:loaded_applications()), + AppupFileName = atom_to_list(App) ++ ".appup", + AppupFile = filename:join([code:lib_dir(App),ebin,AppupFileName]), {ok,[{Vsn,UpFrom,DownTo}=AppupScript]} = file:consult(AppupFile), ct:log("~p~n",[AppupScript]), - {OkVsns,NokVsns} = create_test_vsns(Vsn), + ct:log("Testing ok versions: ~p~n",[OkVsns]), check_appup(OkVsns,UpFrom,{ok,[restart_new_emulator]}), check_appup(OkVsns,DownTo,{ok,[restart_new_emulator]}), + ct:log("Testing not ok versions: ~p~n",[NokVsns]), check_appup(NokVsns,UpFrom,error), check_appup(NokVsns,DownTo,error), ok. -create_test_vsns(Current) -> - [XStr,YStr|Rest] = string:tokens(Current,"."), - X = list_to_integer(XStr), - Y = list_to_integer(YStr), - SecondMajor = vsn(X,Y-2), - SecondMinor = SecondMajor ++ ".1.3", - FirstMajor = vsn(X,Y-1), - FirstMinor = FirstMajor ++ ".57", - ThisMajor = vsn(X,Y), - This = - case Rest of - [] -> - []; - ["1"] -> - [ThisMajor]; - _ -> - ThisMinor = ThisMajor ++ ".1", - [ThisMajor,ThisMinor] +create_test_vsns(App) -> + ThisMajor = erlang:system_info(otp_release), + FirstMajor = previous_major(ThisMajor), + SecondMajor = previous_major(FirstMajor), + Ok = app_vsn(App,[ThisMajor,FirstMajor]), + Nok0 = app_vsn(App,[SecondMajor]), + Nok = case Ok of + [Ok1|_] -> + [Ok1 ++ ",1" | Nok0]; % illegal + _ -> + Nok0 + end, + {Ok,Nok}. + +previous_major("17") -> + "r16b"; +previous_major("r16b") -> + "r15b"; +previous_major(Rel) -> + integer_to_list(list_to_integer(Rel)-1). + +app_vsn(App,[R|Rs]) -> + OldRel = + case test_server:is_release_available(R) of + true -> + {release,R}; + false -> + case ct:get_config({otp_releases,list_to_atom(R)}) of + undefined -> + false; + Prog0 -> + case os:find_executable(Prog0) of + false -> + false; + Prog -> + {prog,Prog} + end + end end, - OkVsns = This ++ [FirstMajor, FirstMinor, SecondMajor, SecondMinor], - - ThirdMajor = vsn(X,Y-3), - ThirdMinor = ThirdMajor ++ ".10.12", - Illegal = ThisMajor ++ ",1", - Newer1Major = vsn(X,Y+1), - Newer1Minor = Newer1Major ++ ".1", - Newer2Major = ThisMajor ++ "1", - NokVsns = [ThirdMajor,ThirdMinor, - Illegal, - Newer1Major,Newer1Minor, - Newer2Major], - {OkVsns,NokVsns}. - -vsn(X,Y) -> - integer_to_list(X) ++ "." ++ integer_to_list(Y). + case OldRel of + false -> + app_vsn(App,Rs); + _ -> + {ok,N} = test_server:start_node(prevrel,peer,[{erl,[OldRel]}]), + _ = rpc:call(N,application,load,[App]), + As = rpc:call(N,application,loaded_applications,[]), + {_,_,V} = lists:keyfind(App,1,As), + test_server:stop_node(N), + [V|app_vsn(App,Rs)] + end; +app_vsn(_App,[]) -> + []. check_appup([Vsn|Vsns],Instrs,Expected) -> case systools_relup:appup_search_for_version(Vsn, Instrs) of diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index 199e597e78..05bd5b3a3d 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2013. All Rights Reserved. +%% Copyright Ericsson AB 2000-2014. 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 @@ _ -> apply(?PRIM_FILE, F, [H | A]) end). -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> []. all() -> [read_write_file, {group, dirs}, {group, files}, @@ -183,7 +183,6 @@ time_dist({_D1, _T1} = DT1, {_D2, _T2} = DT2) -> read_write_file(suite) -> []; read_write_file(doc) -> []; read_write_file(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir,Config), ?line Name = filename:join(RootDir, atom_to_list(?MODULE) @@ -232,7 +231,6 @@ read_write_file(Config) when is_list(Config) -> ?line {ok,Bin5} = ?PRIM_FILE:read_file(Name), ?line {Bin1,Bin2} = split_binary(Bin5,byte_size(Bin1)), - ?line test_server:timetrap_cancel(Dog), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -254,7 +252,6 @@ make_del_dir_b(Config) when is_list(Config) -> Result. make_del_dir(Config, Handle, Suffix) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir,Config), ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) @@ -269,7 +266,13 @@ make_del_dir(Config, Handle, Suffix) -> % because there are processes having that directory as current. ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), ?line {ok, CurrentDir} = ?PRIM_FILE_call(get_cwd, Handle, []), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), + case {os:type(), length(NewDir) >= 260 } of + {{win32,_}, true} -> + io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH)\n", []), + io:format("\nNewDir = ~p\n", [NewDir]); + _ -> + ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]) + end, try %% Check that we get an error when trying to create... %% a deep directory @@ -302,9 +305,7 @@ make_del_dir(Config, Handle, Suffix) -> {error, einval} -> ok %FreeBSD end, ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]), - ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]), - - ?line test_server:timetrap_cancel(Dog) + ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]) after ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir]) end, @@ -324,7 +325,6 @@ cur_dir_0b(Config) when is_list(Config) -> Result. cur_dir_0(Config, Handle) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), %% Find out the current dir, and cd to it ;-) ?line {ok,BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []), ?line Dir1 = BaseDir ++ "", %% Check that it's a string @@ -341,31 +341,37 @@ cur_dir_0(Config, Handle) -> ?line RootDir = ?config(priv_dir,Config), ?line NewDir = filename:join(RootDir, DirName), ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), - ?line io:format("cd to ~s",[NewDir]), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), - - %% Create a file in the new current directory, and check that it - %% really is created there - ?line UncommonName = "uncommon.fil", - ?line {ok,Fd} = ?PRIM_FILE:open(UncommonName, [read, write]), - ?line ok = ?PRIM_FILE:close(Fd), - ?line {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]), - ?line true = lists:member(UncommonName,NewDirFiles), - - %% Delete the directory and return to the old current directory - %% and check that the created file isn't there (too!) - ?line expect({error, einval}, {error, eacces}, {error, eexist}, + case {os:type(), length(NewDir) >= 260} of + {{win32,_}, true} -> + io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH):\n"), + io:format("\nNewDir = ~p\n", [NewDir]); + _ -> + io:format("cd to ~s",[NewDir]), + ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), + + %% Create a file in the new current directory, and check that it + %% really is created there + UncommonName = "uncommon.fil", + {ok,Fd} = ?PRIM_FILE:open(UncommonName, [read, write]), + ok = ?PRIM_FILE:close(Fd), + {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]), + true = lists:member(UncommonName,NewDirFiles), + + %% Delete the directory and return to the old current directory + %% and check that the created file isn't there (too!) + expect({error, einval}, {error, eacces}, {error, eexist}, ?PRIM_FILE_call(del_dir, Handle, [NewDir])), - ?line ?PRIM_FILE_call(delete, Handle, [UncommonName]), - ?line {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, ["."]), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), - ?line io:format("cd back to ~s",[Dir1]), - ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), - ?line {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), - ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), - ?line io:format("cd back to ~s",[Dir1]), - ?line {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]), - ?line false = lists:member(UncommonName,OldDirFiles), + ?PRIM_FILE_call(delete, Handle, [UncommonName]), + {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, ["."]), + ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), + io:format("cd back to ~s",[Dir1]), + ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), + {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), + ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]), + io:format("cd back to ~s",[Dir1]), + {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]), + false = lists:member(UncommonName,OldDirFiles) + end, %% Try doing some bad things ?line {error, badarg} = @@ -385,7 +391,6 @@ cur_dir_0(Config, Handle) -> ?line {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []), ?line false = lists:member($\\, BaseDir), - ?line test_server:timetrap_cancel(Dog), ok. %% Tests ?PRIM_FILE:get_cwd/1. @@ -404,16 +409,13 @@ cur_dir_1b(Config) when is_list(Config) -> Result. cur_dir_1(Config, Handle) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), - ?line case os:type() of - {unix, _} -> - ?line {error, enotsup} = - ?PRIM_FILE_call(get_cwd, Handle, ["d:"]); {win32, _} -> - win_cur_dir_1(Config, Handle) + win_cur_dir_1(Config, Handle); + _ -> + ?line {error, enotsup} = + ?PRIM_FILE_call(get_cwd, Handle, ["d:"]) end, - ?line test_server:timetrap_cancel(Dog), ok. win_cur_dir_1(_Config, Handle) -> @@ -439,7 +441,6 @@ win_cur_dir_1(_Config, Handle) -> open1(suite) -> []; open1(doc) -> []; open1(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir,Config), ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) @@ -453,7 +454,10 @@ open1(Config) when is_list(Config) -> ?line ?PRIM_FILE:write(Fd1,Str), ?line {ok,0} = ?PRIM_FILE:position(Fd1,bof), ?line {ok, Str} = ?PRIM_FILE:read(Fd1,Length), - ?line {ok, Str} = ?PRIM_FILE:read(Fd2,Length), + ?line case ?PRIM_FILE:read(Fd2,Length) of + {ok,Str} -> Str; + eof -> Str + end, ?line ok = ?PRIM_FILE:close(Fd2), ?line {ok,0} = ?PRIM_FILE:position(Fd1,bof), ?line ok = ?PRIM_FILE:truncate(Fd1), @@ -462,7 +466,6 @@ open1(Config) when is_list(Config) -> ?line {ok,Fd3} = ?PRIM_FILE:open(Name, [read]), ?line eof = ?PRIM_FILE:read(Fd3,Length), ?line ok = ?PRIM_FILE:close(Fd3), - ?line test_server:timetrap_cancel(Dog), ok. %% Tests all open modes. @@ -514,7 +517,6 @@ modes(Config) when is_list(Config) -> close(suite) -> []; close(doc) -> []; close(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir,Config), ?line Name = filename:join(RootDir, atom_to_list(?MODULE) @@ -531,13 +533,11 @@ close(Config) when is_list(Config) -> ?line Val = ?PRIM_FILE:close(Fd1), ?line io:format("Second close gave: ~p", [Val]), - ?line test_server:timetrap_cancel(Dog), ok. access(suite) -> []; access(doc) -> []; access(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir,Config), ?line Name = filename:join(RootDir, atom_to_list(?MODULE) @@ -559,7 +559,6 @@ access(Config) when is_list(Config) -> ?line {ok, Str} = ?PRIM_FILE:read(Fd3,length(Str)), ?line ok = ?PRIM_FILE:close(Fd3), - ?line test_server:timetrap_cancel(Dog), ok. %% Tests ?PRIM_FILE:read/2 and ?PRIM_FILE:write/2. @@ -567,7 +566,6 @@ access(Config) when is_list(Config) -> read_write(suite) -> []; read_write(doc) -> []; read_write(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir, Config), ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) @@ -579,7 +577,6 @@ read_write(Config) when is_list(Config) -> ?line {ok, Fd} = ?PRIM_FILE:open(Name, [read, write]), ?line read_write_test(Fd), - ?line test_server:timetrap_cancel(Dog), ok. read_write_test(File) -> @@ -597,7 +594,6 @@ read_write_test(File) -> pread_write(suite) -> []; pread_write(doc) -> []; pread_write(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir, Config), ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) @@ -609,7 +605,6 @@ pread_write(Config) when is_list(Config) -> ?line {ok, Fd} = ?PRIM_FILE:open(Name, [read, write]), ?line pread_write_test(Fd), - ?line test_server:timetrap_cancel(Dog), ok. pread_write_test(File) -> @@ -629,7 +624,6 @@ pread_write_test(File) -> append(doc) -> "Test appending to a file."; append(suite) -> []; append(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir, Config), ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) @@ -656,13 +650,11 @@ append(Config) when is_list(Config) -> ?line Expected = list_to_binary([First, Second, Third]), ?line {ok, Expected} = ?PRIM_FILE:read_file(Name1), - ?line test_server:timetrap_cancel(Dog), ok. exclusive(suite) -> []; exclusive(doc) -> "Test exclusive access to a file."; exclusive(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir,Config), ?line NewDir = filename:join(RootDir, atom_to_list(?MODULE) @@ -672,7 +664,6 @@ exclusive(Config) when is_list(Config) -> ?line {ok,Fd} = ?PRIM_FILE:open(Name, [write, exclusive]), ?line {error, eexist} = ?PRIM_FILE:open(Name, [write, exclusive]), ?line ok = ?PRIM_FILE:close(Fd), - ?line test_server:timetrap_cancel(Dog), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -681,7 +672,6 @@ exclusive(Config) when is_list(Config) -> pos1(suite) -> []; pos1(doc) -> []; pos1(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir,Config), ?line Name = filename:join(RootDir, atom_to_list(?MODULE) @@ -738,13 +728,11 @@ pos1(Config) when is_list(Config) -> ?line {ok, 0} = ?PRIM_FILE:position(Fd2,{eof,-8}), ?line {ok, "A"} = ?PRIM_FILE:read(Fd2,1), ?line {error, einval} = ?PRIM_FILE:position(Fd2,{eof,-9}), - ?line test_server:timetrap_cancel(Dog), ok. pos2(suite) -> []; pos2(doc) -> []; pos2(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir,Config), ?line Name = filename:join(RootDir, atom_to_list(?MODULE) @@ -761,7 +749,6 @@ pos2(Config) when is_list(Config) -> ?line {ok, "D"} = ?PRIM_FILE:read(Fd2,1), ?line io:format("DONE"), - ?line test_server:timetrap_cancel(Dog), ok. @@ -779,7 +766,6 @@ file_info_basic_file_b(Config) when is_list(Config) -> Result. file_info_basic_file(Config, Handle, Suffix) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir, Config), %% Create a short file. @@ -808,7 +794,6 @@ file_info_basic_file(Config, Handle, Suffix) -> ?line {MD, MT} = ModifyTime, ?line all_integers(tuple_to_list(MD) ++ tuple_to_list(MT)), - ?line test_server:timetrap_cancel(Dog), ok. file_info_basic_directory_a(suite) -> []; @@ -825,8 +810,6 @@ file_info_basic_directory_b(Config) when is_list(Config) -> Result. file_info_basic_directory(Config, Handle) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), - %% Note: filename:join/1 removes any trailing slash, %% which is essential for ?PRIM_FILE:read_file_info/1 to work on %% platforms such as Windows95. @@ -843,10 +826,10 @@ file_info_basic_directory(Config, Handle) -> ?line test_directory("/", read_write, Handle), ?line test_directory("c:/", read_write, Handle), ?line test_directory("c:\\", read_write, Handle); - {unix, _} -> + _ -> ?line test_directory("/", read, Handle) end, - ?line test_server:timetrap_cancel(Dog). + ok. test_directory(Name, ExpectedAccess, Handle) -> ?line {ok, FileInfo} = ?PRIM_FILE_call(read_file_info, Handle, [Name]), @@ -887,14 +870,12 @@ file_info_bad_b(Config) when is_list(Config) -> Result. file_info_bad(Config, Handle) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = filename:join([?config(priv_dir, Config)]), ?line {error, enoent} = ?PRIM_FILE_call( read_file_info, Handle, [filename:join(RootDir, atom_to_list(?MODULE)++"_nonexistent")]), - ?line test_server:timetrap_cancel(Dog), ok. %% Test that the file times behave as they should. @@ -1189,7 +1170,6 @@ get_good_directory(Config) -> truncate(suite) -> []; truncate(doc) -> []; truncate(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir,Config), ?line Name = filename:join(RootDir, atom_to_list(?MODULE) @@ -1215,14 +1195,12 @@ truncate(Config) when is_list(Config) -> ?line {ok, 5} = ?PRIM_FILE:position(Fd2, 5), ?line {error, _} = ?PRIM_FILE:truncate(Fd2), - ?line test_server:timetrap_cancel(Dog), ok. datasync(suite) -> []; datasync(doc) -> "Tests that ?PRIM_FILE:datasync/1 at least doesn't crash."; datasync(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line PrivDir = ?config(priv_dir, Config), ?line Sync = filename:join(PrivDir, atom_to_list(?MODULE) @@ -1233,14 +1211,12 @@ datasync(Config) when is_list(Config) -> ?line ok = ?PRIM_FILE:datasync(Fd), ?line ok = ?PRIM_FILE:close(Fd), - ?line test_server:timetrap_cancel(Dog), ok. sync(suite) -> []; sync(doc) -> "Tests that ?PRIM_FILE:sync/1 at least doesn't crash."; sync(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line PrivDir = ?config(priv_dir, Config), ?line Sync = filename:join(PrivDir, atom_to_list(?MODULE) @@ -1251,14 +1227,12 @@ sync(Config) when is_list(Config) -> ?line ok = ?PRIM_FILE:sync(Fd), ?line ok = ?PRIM_FILE:close(Fd), - ?line test_server:timetrap_cancel(Dog), ok. advise(suite) -> []; advise(doc) -> "Tests that ?PRIM_FILE:advise/4 at least doesn't crash."; advise(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line PrivDir = ?config(priv_dir, Config), ?line Advise = filename:join(PrivDir, atom_to_list(?MODULE) @@ -1322,7 +1296,6 @@ advise(Config) when is_list(Config) -> ?line eof = ?PRIM_FILE:read_line(Fd9), ?line ok = ?PRIM_FILE:close(Fd9), - ?line test_server:timetrap_cancel(Dog), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1366,7 +1339,6 @@ check_large_write(Dog, Fd, _, _, []) -> allocate(suite) -> []; allocate(doc) -> "Tests that ?PRIM_FILE:allocate/3 at least doesn't crash."; allocate(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line PrivDir = ?config(priv_dir, Config), ?line Allocate = filename:join(PrivDir, atom_to_list(?MODULE) @@ -1399,7 +1371,6 @@ allocate(Config) when is_list(Config) -> ?line ok = ?PRIM_FILE:write(Fd4, Line2), ?line ok = ?PRIM_FILE:close(Fd4), - ?line test_server:timetrap_cancel(Dog), ok. allocate_and_assert(Fd, Offset, Length) -> @@ -1447,7 +1418,6 @@ delete_b(Config) when is_list(Config) -> Result. delete(Config, Handle, Suffix) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir,Config), ?line Name = filename:join(RootDir, atom_to_list(?MODULE) @@ -1463,7 +1433,6 @@ delete(Config, Handle, Suffix) -> ?line {error, _} = ?PRIM_FILE:open(Name, [read]), %% Try deleting a nonexistent file ?line {error, enoent} = ?PRIM_FILE_call(delete, Handle, [Name]), - ?line test_server:timetrap_cancel(Dog), ok. rename_a(suite) ->[]; @@ -1480,7 +1449,6 @@ rename_b(Config) when is_list(Config) -> Result. rename(Config, Handle, Suffix) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), ?line RootDir = ?config(priv_dir,Config), ?line FileName1 = atom_to_list(?MODULE)++"_rename"++Suffix++".fil", ?line FileName2 = atom_to_list(?MODULE)++"_rename"++Suffix++".ful", @@ -1533,7 +1501,6 @@ rename(Config, Handle, Suffix) -> ?PRIM_FILE_call(rename, Handle, [DirName2, Name2foo]), ?line io:format("Errmsg2: ~p",[Msg2]), - ?line test_server:timetrap_cancel(Dog), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1568,15 +1535,15 @@ e_delete(Config) when is_list(Config) -> %% No permission. ?line case os:type() of - {unix, _} -> + {win32, _} -> + %% Remove a character device. + ?line {error, eacces} = ?PRIM_FILE:delete("nul"); + _ -> ?line ?PRIM_FILE:write_file_info( Base, #file_info {mode=0}), ?line {error, eacces} = ?PRIM_FILE:delete(Afile), ?line ?PRIM_FILE:write_file_info( - Base, #file_info {mode=8#600}); - {win32, _} -> - %% Remove a character device. - ?line {error, eacces} = ?PRIM_FILE:delete("nul") + Base, #file_info {mode=8#600}) end, ?line test_server:timetrap_cancel(Dog), @@ -1656,7 +1623,12 @@ e_rename(Config) when is_list(Config) -> %% XXX - Gross hack! ?line Comment = case os:type() of - {unix, _} -> + {win32, _} -> + %% At least Windows NT can + %% successfully move a file to + %% another drive. + ok; + {unix, _ } -> OtherFs = "/tmp", ?line NameOnOtherFs = filename:join(OtherFs, @@ -1681,10 +1653,8 @@ e_rename(Config) when is_list(Config) -> Else end, Com; - {win32, _} -> - %% At least Windows NT can - %% successfully move a file to - %% another drive. + {ose, _} -> + %% disabled for now ok end, ?line test_server:timetrap_cancel(Dog), @@ -1714,14 +1684,14 @@ e_make_dir(Config) when is_list(Config) -> %% No permission (on Unix only). case os:type() of - {unix, _} -> + {win32, _} -> + ok; + _ -> ?line ?PRIM_FILE:write_file_info(Base, #file_info {mode=0}), ?line {error, eacces} = ?PRIM_FILE:make_dir(filename:join(Base, "xxxx")), ?line - ?PRIM_FILE:write_file_info(Base, #file_info {mode=8#600}); - {win32, _} -> - ok + ?PRIM_FILE:write_file_info(Base, #file_info {mode=8#600}) end, ?line test_server:timetrap_cancel(Dog), ok. @@ -1767,15 +1737,15 @@ e_del_dir(Config) when is_list(Config) -> %% No permission. case os:type() of - {unix, _} -> + {win32, _} -> + ok; + _ -> ?line ADirectory = filename:join(Base, "no_perm"), ?line ok = ?PRIM_FILE:make_dir(ADirectory), ?line ?PRIM_FILE:write_file_info(Base, #file_info {mode=0}), ?line {error, eacces} = ?PRIM_FILE:del_dir(ADirectory), ?line ?PRIM_FILE:write_file_info( - Base, #file_info {mode=8#600}); - {win32, _} -> - ok + Base, #file_info {mode=8#600}) end, ?line test_server:timetrap_cancel(Dog), ok. @@ -2023,6 +1993,9 @@ symlinks(Config, Handle, Suffix) -> case ?PRIM_FILE_call(make_symlink, Handle, [Name, Alias]) of {error, enotsup} -> {skipped, "Links not supported on this platform"}; + {error, eperm} -> + {win32,_} = os:type(), + {skipped, "Windows user not privileged to create links"}; ok -> ?line {ok, Info1} = ?PRIM_FILE_call(read_file_info, Handle, [Name]), diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl index 4cf4c6489d..123e849ccb 100644 --- a/lib/kernel/test/sendfile_SUITE.erl +++ b/lib/kernel/test/sendfile_SUITE.erl @@ -24,7 +24,14 @@ -compile(export_all). -all() -> +all() -> [{group,async_threads}, + {group,no_async_threads}]. + +groups() -> + [{async_threads,[],tcs()}, + {no_async_threads,[],tcs()}]. + +tcs() -> [t_sendfile_small ,t_sendfile_big_all ,t_sendfile_big_size @@ -33,6 +40,7 @@ all() -> ,t_sendfile_offset ,t_sendfile_sendafter ,t_sendfile_recvafter + ,t_sendfile_recvafter_remoteclose ,t_sendfile_sendduring ,t_sendfile_recvduring ,t_sendfile_closeduring @@ -63,6 +71,19 @@ init_per_suite(Config) -> end_per_suite(Config) -> file:delete(proplists:get_value(big_file, Config)). +init_per_group(async_threads,Config) -> + case erlang:system_info(thread_pool_size) of + 0 -> + {skip,"No async threads"}; + _ -> + [{sendfile_opts,[{use_threads,true}]}|Config] + end; +init_per_group(no_async_threads,Config) -> + [{sendfile_opts,[{use_threads,false}]}|Config]. + +end_per_group(_,_Config) -> + ok. + init_per_testcase(TC,Config) when TC == t_sendfile_recvduring; TC == t_sendfile_sendduring -> Filename = proplists:get_value(small_file, Config), @@ -71,7 +92,7 @@ init_per_testcase(TC,Config) when TC == t_sendfile_recvduring; {_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, @@ -92,6 +113,7 @@ t_sendfile_small(Config) when is_list(Config) -> Send = fun(Sock) -> {Size, Data} = sendfile_file_info(Filename), + %% Here we make sure to test the sendfile/2 api {ok, Size} = file:sendfile(Filename, Sock), Data end, @@ -101,6 +123,7 @@ t_sendfile_small(Config) when is_list(Config) -> t_sendfile_many_small(Config) when is_list(Config) -> Filename = proplists:get_value(small_file, Config), FileOpts = proplists:get_value(file_opts, Config, []), + SendfileOpts = proplists:get_value(sendfile_opts, Config), error_logger:add_report_handler(?MODULE,[self()]), @@ -109,7 +132,7 @@ t_sendfile_many_small(Config) when is_list(Config) -> N = 10000, {ok,D} = file:open(Filename,[read|FileOpts]), [begin - {ok,Size} = file:sendfile(D,Sock,0,0,[]) + {ok,Size} = file:sendfile(D,Sock,0,0,SendfileOpts) end || _I <- lists:seq(1,N)], file:close(D), Size*N @@ -127,11 +150,12 @@ t_sendfile_many_small(Config) when is_list(Config) -> t_sendfile_big_all(Config) when is_list(Config) -> Filename = proplists:get_value(big_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock) -> {ok, #file_info{size = Size}} = file:read_file_info(Filename), - {ok, Size} = file:sendfile(Filename, Sock), + {ok, Size} = sendfile(Filename, Sock, SendfileOpts), Size end, @@ -140,12 +164,13 @@ t_sendfile_big_all(Config) when is_list(Config) -> t_sendfile_big_size(Config) -> Filename = proplists:get_value(big_file, Config), FileOpts = proplists:get_value(file_opts, Config, []), + SendfileOpts = proplists:get_value(sendfile_opts, Config), SendAll = fun(Sock) -> {ok, #file_info{size = Size}} = file:read_file_info(Filename), {ok,D} = file:open(Filename,[read|FileOpts]), - {ok, Size} = file:sendfile(D, Sock,0,Size,[]), + {ok, Size} = file:sendfile(D, Sock,0,Size,SendfileOpts), Size end, @@ -154,12 +179,13 @@ t_sendfile_big_size(Config) -> t_sendfile_partial(Config) -> Filename = proplists:get_value(small_file, Config), FileOpts = proplists:get_value(file_opts, Config, []), + SendfileOpts = proplists:get_value(sendfile_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,[]), + {ok,5} = file:sendfile(D,Sock,0,5,SendfileOpts), file:close(D), Data end, @@ -170,14 +196,14 @@ t_sendfile_partial(Config) -> {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,[]), + {ok,5} = file:sendfile(D,Sock,0,5,SendfileOpts), FData end, ok = sendfile_send(FSend), SSend = fun(Sock) -> - {ok,3} = file:sendfile(D,Sock,5,3,[]), + {ok,3} = file:sendfile(D,Sock,5,3,SendfileOpts), SData end, @@ -190,12 +216,13 @@ t_sendfile_partial(Config) -> t_sendfile_offset(Config) -> Filename = proplists:get_value(small_file, Config), FileOpts = proplists:get_value(file_opts, Config, []), + SendfileOpts = proplists:get_value(sendfile_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,3} = file:sendfile(D,Sock,5,3,SendfileOpts), {ok, AllData} = file:read(D,100), file:close(D), Data @@ -205,10 +232,11 @@ t_sendfile_offset(Config) -> t_sendfile_sendafter(Config) -> Filename = proplists:get_value(small_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock) -> {Size, Data} = sendfile_file_info(Filename), - {ok, Size} = file:sendfile(Filename, Sock), + {ok, Size} = sendfile(Filename, Sock, SendfileOpts), ok = gen_tcp:send(Sock, <<2>>), <<Data/binary,2>> end, @@ -217,10 +245,11 @@ t_sendfile_sendafter(Config) -> t_sendfile_recvafter(Config) -> Filename = proplists:get_value(small_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock) -> {Size, Data} = sendfile_file_info(Filename), - {ok, Size} = file:sendfile(Filename, Sock), + {ok, Size} = sendfile(Filename, Sock, SendfileOpts), ok = gen_tcp:send(Sock, <<1>>), {ok,<<1>>} = gen_tcp:recv(Sock, 1), <<Data/binary,1>> @@ -228,8 +257,28 @@ t_sendfile_recvafter(Config) -> ok = sendfile_send(Send). +%% This tests specifically for a bug fixed in 17.0 +t_sendfile_recvafter_remoteclose(Config) -> + Filename = proplists:get_value(small_file, Config), + + Send = fun(Sock, SFServer) -> + {Size, _Data} = sendfile_file_info(Filename), + {ok, Size} = file:sendfile(Filename, Sock), + + %% Make sure the remote end has been closed + SFServer ! stop, + timer:sleep(100), + + %% In the bug this returned {error,ebadf} + {error,closed} = gen_tcp:recv(Sock, 1), + -1 + end, + + ok = sendfile_send({127,0,0,1},Send,0). + t_sendfile_sendduring(Config) -> Filename = proplists:get_value(big_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock) -> {ok, #file_info{size = Size}} = @@ -238,7 +287,7 @@ t_sendfile_sendduring(Config) -> timer:sleep(50), ok = gen_tcp:send(Sock, <<2>>) end), - {ok, Size} = file:sendfile(Filename, Sock), + {ok, Size} = sendfile(Filename, Sock, SendfileOpts), Size+1 end, @@ -246,6 +295,7 @@ t_sendfile_sendduring(Config) -> t_sendfile_recvduring(Config) -> Filename = proplists:get_value(big_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock) -> {ok, #file_info{size = Size}} = @@ -255,7 +305,7 @@ t_sendfile_recvduring(Config) -> ok = gen_tcp:send(Sock, <<1>>), {ok,<<1>>} = gen_tcp:recv(Sock, 1) end), - {ok, Size} = file:sendfile(Filename, Sock), + {ok, Size} = sendfile(Filename, Sock, SendfileOpts), timer:sleep(1000), Size+1 end, @@ -264,6 +314,7 @@ t_sendfile_recvduring(Config) -> t_sendfile_closeduring(Config) -> Filename = proplists:get_value(big_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), Send = fun(Sock,SFServPid) -> spawn_link(fun() -> @@ -272,13 +323,14 @@ t_sendfile_closeduring(Config) -> end), case erlang:system_info(thread_pool_size) of 0 -> - {error, closed} = file:sendfile(Filename, Sock); + {error, closed} = sendfile(Filename, Sock, + SendfileOpts); _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 + case sendfile(Filename, Sock, SendfileOpts) of {error, closed} -> ok; {ok, Size} when is_integer(Size) -> @@ -292,6 +344,7 @@ t_sendfile_closeduring(Config) -> t_sendfile_crashduring(Config) -> Filename = proplists:get_value(big_file, Config), + SendfileOpts = proplists:get_value(sendfile_opts, Config), error_logger:add_report_handler(?MODULE,[self()]), @@ -300,7 +353,7 @@ t_sendfile_crashduring(Config) -> timer:sleep(50), exit(die) end), - {error, closed} = file:sendfile(Filename, Sock), + {error, closed} = sendfile(Filename, Sock, SendfileOpts), -1 end, process_flag(trap_exit,true), @@ -395,6 +448,16 @@ sendfile_file_info(File) -> {ok, Data} = file:read_file(File), {Size, Data}. +sendfile(Filename,Sock,Opts) -> + case file:open(Filename, [read, raw, binary]) of + {error, Reason} -> + {error, Reason}; + {ok, Fd} -> + Res = file:sendfile(Fd, Sock, 0, 0, Opts), + _ = file:close(Fd), + Res + end. + %% Error handler diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl index e91f6f18d4..3be6f39d95 100644 --- a/lib/kernel/test/zlib_SUITE.erl +++ b/lib/kernel/test/zlib_SUITE.erl @@ -178,7 +178,7 @@ api_deflateInit(Config) when is_list(Config) -> ?m(ok,zlib:close(Z)) end, lists:seq(1,8)), - Strategies = [filtered,huffman_only,default], + Strategies = [filtered,huffman_only,rle,default], lists:foreach(fun(Strategy) -> ?line Z = zlib:open(), ?m(ok, zlib:deflateInit(Z,best_speed,deflated,-15,8,Strategy)), @@ -220,7 +220,6 @@ api_deflateParams(Config) when is_list(Config) -> ?m(_, zlib:deflate(Z1, <<1,1,1,1,1,1,1,1,1>>, none)), ?m(ok, zlib:deflateParams(Z1, best_compression, huffman_only)), ?m(_, zlib:deflate(Z1, <<1,1,1,1,1,1,1,1,1>>, sync)), - ?m({'EXIT',_}, zlib:deflateParams(Z1,best_speed, filtered)), ?m(ok, zlib:close(Z1)). api_deflate(doc) -> "Test deflate"; |