diff options
Diffstat (limited to 'lib/kernel')
78 files changed, 2642 insertions, 1701 deletions
diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile index 5e04bff0c1..de3ca1e176 100644 --- a/lib/kernel/doc/src/Makefile +++ b/lib/kernel/doc/src/Makefile @@ -58,7 +58,6 @@ XML_REF3_FILES = application.xml \ net_adm.xml \ net_kernel.xml \ os.xml \ - packages.xml \ pg2.xml \ rpc.xml \ seq_trace.xml \ diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml index 08d8f49ef6..279c7558bc 100644 --- a/lib/kernel/doc/src/code.xml +++ b/lib/kernel/doc/src/code.xml @@ -728,16 +728,13 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name>is_module_native(Module) -> boolean() | undefined</name> + <name name="is_module_native" arity="1"/> <fsummary>Test whether a module has native code</fsummary> - <type> - <v>Module = module()</v> - </type> <desc> - <p>This function returns <c>true</c> if <c>Module</c> is + <p>This function returns <c>true</c> if <c><anno>Module</anno></c> is name of a loaded module that has native code loaded, and - <c>false</c> if <c>Module</c> is loaded but does not have - native. If <c>Module</c> is not loaded, this function returns + <c>false</c> if <c><anno>Module</anno></c> is loaded but does not have + native. If <c><anno>Module</anno></c> is not loaded, this function returns <c>undefined</c>.</p> </desc> </func> diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml index 1911fb628e..26db11cfcd 100644 --- a/lib/kernel/doc/src/erl_ddll.xml +++ b/lib/kernel/doc/src/erl_ddll.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1997</year><year>2011</year> + <year>1997</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -182,11 +182,8 @@ </datatypes> <funcs> <func> - <name>demonitor(MonitorRef) -> ok</name> + <name name="demonitor" arity="1"/> <fsummary>Remove a monitor for a driver</fsummary> - <type> - <v>MonitorRef = reference()</v> - </type> <desc> <p>Removes a driver monitor in much the same way as <seealso marker="erts:erlang#erlang:demonitor/1">erlang:demonitor/1</seealso> does with process @@ -232,24 +229,19 @@ </desc> </func> <func> - <name>info(Name, Tag) -> Value</name> + <name name="info" arity="2"/> <fsummary>Retrieve specific information about one driver</fsummary> - <type> - <v>Name = string() | atom()</v> - <v>Tag = processes | driver_options | port_count | linked_in_driver | permanent | awaiting_load | awaiting_unload</v> - <v>Value = term()</v> - </type> <desc> <p>This function returns specific information about one aspect - of a driver. The <c>Tag</c> parameter specifies which aspect - to get information about. The <c>Value</c> return differs + of a driver. The <c><anno>Tag</anno></c> parameter specifies which aspect + to get information about. The <c><anno>Value</anno></c> return differs between different tags:</p> <taglist> <tag><em>processes</em></tag> <item> <p>Return all processes containing <seealso marker="#users">users</seealso> of the specific drivers - as a list of tuples <c>{pid(),int()}</c>, where the - <c>int()</c> denotes the number of users in the process + as a list of tuples <c>{pid(),integer() >= 0}</c>, where the + <c>integer()</c> denotes the number of users in the process <c>pid()</c>.</p> </item> <tag><em>driver_options</em></tag> @@ -261,16 +253,16 @@ </item> <tag><em>port_count</em></tag> <item> - <p>Return the number of ports (an <c>int()</c>) using the driver.</p> + <p>Return the number of ports (an <c>integer >= 0()</c>) using the driver.</p> </item> <tag><em>linked_in_driver</em></tag> <item> - <p>Return a <c>bool()</c>, being <c>true</c> if the driver is a + <p>Return a <c>boolean()</c>, being <c>true</c> if the driver is a statically linked in one and <c>false</c> otherwise.</p> </item> <tag><em>permanent</em></tag> <item> - <p>Return a <c>bool()</c>, being <c>true</c> if the driver has made + <p>Return a <c>boolean()</c>, being <c>true</c> if the driver has made itself permanent (and is <em>not</em> a statically linked in driver). <c>false</c> otherwise.</p> </item> @@ -278,14 +270,14 @@ <item> <p>Return a list of all processes having monitors for <c>loading</c> active, each process returned as - <c>{pid(),int()}</c>, where the <c>int()</c> is the + <c>{pid(),integer() >= 0}</c>, where the <c>integer()</c> is the number of monitors held by the process <c>pid()</c>.</p> </item> <tag><em>awaiting_unload</em></tag> <item> <p>Return a list of all processes having monitors for <c>unloading</c> active, each process returned as - <c>{pid(),int()}</c>, where the <c>int()</c> is the + <c>{pid(),integer() >= 0}</c>, where the <c>integer()</c> is the number of monitors held by the process <c>pid()</c>.</p> </item> </taglist> @@ -377,41 +369,34 @@ </desc> </func> <func> - <name>monitor(Tag, Item) -> MonitorRef</name> + <name name="monitor" arity="2"/> <fsummary>Create a monitor for a driver</fsummary> - <type> - <v>Tag = driver </v> - <v>Item = {Name, When}</v> - <v>Name = atom() | string()</v> - <v>When = loaded | unloaded | unloaded_only</v> - <v>MonitorRef = reference()</v> - </type> <desc> <p>This function creates a driver monitor and works in many ways as the function <seealso marker="erts:erlang#erlang:monitor/2">erlang:monitor/2</seealso>, does for processes. When a driver changes state, the monitor results in a monitor-message being sent to the calling - process. The <c>MonitorRef</c> returned by this function is + process. The <c><anno>MonitorRef</anno></c> returned by this function is included in the message sent.</p> <p>As with process monitors, each driver monitor set will only generate <em>one single message</em>. The monitor is "destroyed" after the message is sent and there is then no need to call <seealso marker="#demonitor/1">demonitor/1</seealso>.</p> - <p>The <c>MonitorRef</c> can also be used in subsequent calls + <p>The <c><anno>MonitorRef</anno></c> can also be used in subsequent calls to <seealso marker="#demonitor/1">demonitor/1</seealso> to remove a monitor.</p> <p>The function accepts the following parameters:</p> <taglist> - <tag><em>Tag</em></tag> + <tag><em><anno>Tag</anno></em></tag> <item> <p>The monitor tag is always <c>driver</c> as this function can only be used to create driver monitors. In the future, driver monitors will be integrated with process monitors, why this parameter has to be given for consistence.</p> </item> - <tag><em>Item</em></tag> + <tag><em><anno>Item</anno></em></tag> <item> - <p>The <c>Item</c> parameter specifies which driver one + <p>The <c><anno>Item</anno></c> parameter specifies which driver one wants to monitor (the name of the driver) as well as which state change one wants to monitor. The parameter is a tuple of arity two whose first element is the @@ -588,22 +573,8 @@ </desc> </func> <func> - <name>try_load(Path, Name, OptionList) -> {ok,Status} | {ok, PendingStatus, Ref} | {error, ErrorDesc}</name> + <name name="try_load" arity="3"/> <fsummary>Load a driver</fsummary> - <type> - <v>Path = Name = string() | atom()</v> - <v>OptionList = [ Option ]</v> - <v>Option = {driver_options, DriverOptionList} | {monitor, MonitorOption} | {reload, ReloadOption}</v> - <v>DriverOptionList = [ DriverOption ]</v> - <v>DriverOption = kill_ports</v> - <v>MonitorOption = pending_driver | pending</v> - <v>ReloadOption = pending_driver | pending</v> - <v>Status = loaded | already_loaded | PendingStatus </v> - <v>PendingStatus = pending_driver | pending_process</v> - <v>Ref = reference()</v> - <v>ErrorDesc = ErrorAtom | OpaqueError</v> - <v>ErrorAtom = linked_in_driver | inconsistent | permanent | not_loaded_by_this_process | not_loaded | pending_reload | pending_process</v> - </type> <desc> <p>This function provides more control than the <c>load/2</c>/<c>reload/2</c> and @@ -655,65 +626,65 @@ <p>When the function returns <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c>, one might want to get information about when the driver is <em>actually</em> loaded. This can - be achieved by using the <c>{monitor, PendingOption}</c> option.</p> + be achieved by using the <c>{monitor, <anno>MonitorOption</anno>}</c> option.</p> <p>When monitoring is requested, and a corresponding <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c> would be - returned, the function will instead return a tuple <c>{ok, PendingStatus, reference()}</c> and the process will, at a later + returned, the function will instead return a tuple <c>{ok, <anno>PendingStatus</anno>, reference()}</c> and the process will, at a later time when the driver actually gets loaded, get a monitor message. The monitor message one can expect is described in the <seealso marker="#monitor/2">monitor/2</seealso> function description. </p> <note> <p>Note that in case of loading, monitoring can - <em>not</em> only get triggered by using the <c>{reload, ReloadOption}</c> option, but also in special cases where + <em>not</em> only get triggered by using the <c>{reload, <anno>ReloadOption</anno>}</c> option, but also in special cases where the load-error is transient, why <c>{monitor, pending_driver}</c> should be used under basically <em>all</em> real world circumstances!</p> </note> <p>The function accepts the following parameters:</p> <taglist> - <tag><em>Path</em></tag> + <tag><em><anno>Path</anno></em></tag> <item> <p>The filesystem path to the directory where the driver object file is situated. The filename of the object file (minus extension) must correspond to the driver name (used in the name parameter) and the driver must identify itself with the very same name. The - <c>Path</c> might be provided as an <em>io_list</em>, - meaning it can be a list of other io_lists, characters + <c><anno>Path</anno></c> might be provided as an <em>iolist()</em>, + meaning it can be a list of other <c>iolist()</c>s, characters (eight bit integers) or binaries, all to be flattened into a sequence of characters.</p> - <p>The (possibly flattened) <c>Path</c> parameter must be + <p>The (possibly flattened) <c><anno>Path</anno></c> parameter must be consistent throughout the system, a driver should, by all <seealso marker="#users">users</seealso>, be loaded - using the same <em>literal</em><c>Path</c>. The + using the same <em>literal</em><c><anno>Path</anno></c>. The exception is when <em>reloading</em> is requested, in - which case the <c>Path</c> may be specified + which case the <c><anno>Path</anno></c> may be specified differently. Note that all <seealso marker="#users">users</seealso> trying to load the - driver at a later time will need to use the <em>new</em><c>Path</c> if the <c>Path</c> is changed using a + driver at a later time will need to use the <em>new</em><c><anno>Path</anno></c> if the <c><anno>Path</anno></c> is changed using a <c>reload</c> option. This is yet another reason to have <em>only one loader</em> of a driver one wants to upgrade in a running system! </p> </item> - <tag><em>Name</em></tag> + <tag><em><anno>Name</anno></em></tag> <item> <p>The name parameter is the name of the driver to be used in subsequent calls to <seealso marker="erts:erlang#open_port/2">open_port</seealso>. The - name can be specified either as an <c>io_list()</c> or + name can be specified either as an <c>iolist()</c> or as an <c>atom()</c>. The name given when loading is used to find the actual object file (with the - help of the <c>Path</c> and the system implied + help of the <c><anno>Path</anno></c> and the system implied extension suffix, i.e. <c>.so</c>). The name by which the driver identifies itself must also be consistent - with this <c>Name</c> parameter, much as a beam-file's + with this <c><anno>Name</anno></c> parameter, much as a beam-file's module name much correspond to its filename.</p> </item> - <tag><em>OptionList</em></tag> + <tag><em><anno>OptionList</anno></em></tag> <item> <p>A number of options can be specified to control the loading operation. The options are given as a list of two-tuples, the tuples having the following values and meanings:</p> <taglist> - <tag><em>{driver_options, DriverOptionsList}</em></tag> + <tag><em>{driver_options, <anno>DriverOptionList</anno>}</em></tag> <item> <p>This option is to provide options that will change its general behavior and will "stick" to the driver @@ -729,14 +700,14 @@ when the last <seealso marker="#users">user</seealso> calls <seealso marker="#try_unload/2">try_unload/2</seealso>, or the last process having loaded the driver exits.</p> </item> - <tag><em>{monitor, MonitorOption}</em></tag> + <tag><em>{monitor, <anno>MonitorOption</anno>}</em></tag> <item> - <p>A <c>MonitorOption</c> tells <c>try_load/3</c> to + <p>A <c><anno>MonitorOption</anno></c> tells <c>try_load/3</c> to trigger a driver monitor under certain conditions. When the monitor is triggered, the - function will return a three-tuple <c>{ok, PendingStatus, reference()}</c>, where the <c>reference()</c> is + function will return a three-tuple <c>{ok, <anno>PendingStatus</anno>, reference()}</c>, where the <c>reference()</c> is the monitor ref for the driver monitor.</p> - <p>Only one <c>MonitorOption</c> can be specified and + <p>Only one <c><anno>MonitorOption</anno></c> can be specified and it is either the atom <c>pending</c>, which means that a monitor should be created whenever a load operation is delayed, and the atom @@ -747,7 +718,7 @@ is present for completeness, it is very well defined which reload-options might give rise to which delays. It might, however, be a good idea to use the - same <c>MonitorOption</c> as the <c>ReloadOption</c> + same <c><anno>MonitorOption</anno></c> as the <c><anno>ReloadOption</anno></c> if present.</p> <p>If reloading is not requested, it might still be useful to specify the <c>monitor</c> option, as @@ -760,12 +731,12 @@ <c>{monitor, pending_driver}</c> in production code (see the monitor discussion above). </p> </item> - <tag><em>{reload,RealoadOption}</em></tag> + <tag><em>{reload,<anno>ReloadOption</anno>}</em></tag> <item> <p>This option is used when one wants to <em>reload</em> a driver from disk, most often in a code upgrade scenario. Having a <c>reload</c> option - also implies that the <c>Path</c> parameter need + also implies that the <c><anno>Path</anno></c> parameter need <em>not</em> be consistent with earlier loads of the driver.</p> <p>To reload a driver, the process needs to have previously @@ -814,9 +785,9 @@ <tag><em>{error,inconsistent}</em></tag> <item> <p>The driver has already been loaded with either other - <c>DriverOptions</c> or a different <em>literal</em><c>Path</c> argument.</p> + <c><anno>DriverOptionList</anno></c> or a different <em>literal</em><c>Path</c> argument.</p> <p>This can happen even if a <c>reload</c> option is given, - if the <c>DriverOptions</c> differ from the current.</p> + if the <c>DriverOptionList</c> differ from the current.</p> </item> <tag><em>{error, permanent}</em></tag> <item> @@ -830,19 +801,19 @@ </item> <tag><em>{error, pending_reload}</em></tag> <item> - <p>Driver reload is already requested by another <seealso marker="#users">user</seealso> when the <c>{reload, ReloadOption}</c> option was given.</p> + <p>Driver reload is already requested by another <seealso marker="#users">user</seealso> when the <c>{reload, <anno>ReloadOption</anno>}</c> option was given.</p> </item> <tag><em>{error, not_loaded_by_this_process}</em></tag> <item> <p>Appears when the <c>reload</c> option is given. The - driver <c>Name</c> is present in the system, but there is no + driver <c><anno>Name</anno></c> is present in the system, but there is no <seealso marker="#users">user</seealso> of it in this process.</p> </item> <tag><em>{error, not_loaded}</em></tag> <item> <p>Appears when the <c>reload</c> option is given. The - driver <c>Name</c> is not in the system. Only drivers + driver <c><anno>Name</anno></c> is not in the system. Only drivers loaded by this process can be reloaded.</p> </item> </taglist> @@ -856,18 +827,8 @@ </desc> </func> <func> - <name>try_unload(Name, OptionList) -> {ok,Status} | {ok, PendingStatus, Ref} | {error, ErrorAtom}</name> + <name name="try_unload" arity="2"/> <fsummary>Unload a driver</fsummary> - <type> - <v>Name = string() | atom()</v> - <v>OptionList = [ Option ]</v> - <v>Option = {monitor, MonitorOption} | kill_ports</v> - <v>MonitorOption = pending_driver | pending</v> - <v>Status = unloaded | PendingStatus </v> - <v>PendingStatus = pending_driver | pending_process</v> - <v>Ref = reference()</v> - <v>ErrorAtom = linked_in_driver | not_loaded | not_loaded_by_this_process | permanent</v> - </type> <desc> <p>This is the low level function to unload (or decrement reference counts of) a driver. It can be used to force port @@ -948,15 +909,15 @@ </taglist> <p>The function accepts the following parameters:</p> <taglist> - <tag><em>Name</em></tag> + <tag><em><anno>Name</anno></em></tag> <item> <p>The name parameter is the name of the driver to be unloaded. The name can be specified either as an - <c>io_list()</c> or as an <c>atom()</c>. </p> + <c>iolist()</c> or as an <c>atom()</c>. </p> </item> - <tag><em>OptionList</em></tag> + <tag><em><anno>OptionList</anno></em></tag> <item> - <p>The <c>OptionList</c> argument can be used to specify + <p>The <c><anno>OptionList</anno></c> argument can be used to specify certain behavior regarding ports as well as triggering monitors under certain conditions:</p> <taglist> @@ -972,10 +933,10 @@ unloads, one should use the driver option <c>kill_ports</c> when loading the driver instead.</p> </item> - <tag><em>{monitor, MonitorOption}</em></tag> + <tag><em>{monitor, <anno>MonitorOption</anno>}</em></tag> <item> <p>This option creates a driver monitor if the condition - given in <c>MonitorOptions</c> is true. The valid + given in <c><anno>MonitorOption</anno></c> is true. The valid options are:</p> <taglist> <tag><em>pending_driver</em></tag> @@ -989,7 +950,7 @@ <c>{ok, pending_driver}</c> or <c>{ok, pending_process}</c>.</p> </item> </taglist> - <p>The <c>pending_driver</c> <c>MonitorOption</c> is by far + <p>The <c>pending_driver</c> <c><anno>MonitorOption</anno></c> is by far the most useful and it has to be used to ensure that the driver has really been unloaded and the ports closed whenever the <c>kill_ports</c> option is used or the @@ -1016,11 +977,11 @@ </item> <tag><em>{error, not_loaded}</em></tag> <item> - <p>The driver <c>Name</c> is not present in the system.</p> + <p>The driver <c><anno>Name</anno></c> is not present in the system.</p> </item> <tag><em>{error, not_loaded_by_this_process}</em></tag> <item> - <p>The driver <c>Name</c> is present in the system, but + <p>The driver <c><anno>Name</anno></c> is present in the system, but there is no <seealso marker="#users">user</seealso> of it in this process. </p> <p>As a special case, drivers can be unloaded from @@ -1088,12 +1049,8 @@ </desc> </func> <func> - <name>loaded_drivers() -> {ok, Drivers}</name> + <name name="loaded_drivers" arity="0"/> <fsummary>List loaded drivers</fsummary> - <type> - <v>Drivers = [Driver]</v> - <v>Driver = string()</v> - </type> <desc> <p>Returns a list of all the available drivers, both (statically) linked-in and dynamically loaded ones.</p> diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml index ec3274965a..cd86b364f6 100644 --- a/lib/kernel/doc/src/error_logger.xml +++ b/lib/kernel/doc/src/error_logger.xml @@ -127,11 +127,8 @@ ok</pre> </desc> </func> <func> - <name>warning_map() -> Tag</name> + <name name="warning_map" arity="0"/> <fsummary>Return the current mapping for warning events</fsummary> - <type> - <v>Tag = error | warning | info</v> - </type> <desc> <p>Returns the current mapping for warning events. Events sent using <c>warning_msg/1,2</c> or <c>warning_report/1,2</c> diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 772eff13cc..e30ade1bd2 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>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -110,7 +110,7 @@ <desc> <p>As returned by <seealso marker="#open/2">file:open/2</seealso>, - a process handling IO protocols.</p> + a process handling I/O-protocols.</p> </desc> </datatype> <datatype> @@ -170,6 +170,18 @@ </desc> </func> <func> + <name name="allocate" arity="3"/> + <fsummary>Allocate file space</fsummary> + <desc> + <p><c>allocate/3</c> can be used to preallocate space for a file.</p> + <p>This function only succeeds in platforms that implement this + feature. When it succeeds, space is preallocated for the file but + the file size might not be updated. This behaviour depends on the + preallocation implementation. To guarantee the file size is updated + one must truncate the file to the new size.</p> + </desc> + </func> + <func> <name name="change_group" arity="2"/> <fsummary>Change group of a file</fsummary> <desc> @@ -261,6 +273,9 @@ {person, "pelle", 30}.</code> <pre>1> <input>file:consult("f.txt").</input> {ok,[{person,"kalle",25},{person,"pelle",30}]}</pre> + <p>The encoding of of <c><anno>Filename</anno></c> can be set + by a comment as described in <seealso + marker="stdlib:epp#encoding">epp(3)</seealso>.</p> </desc> </func> <func> @@ -399,6 +414,9 @@ of the error.</p> </item> </taglist> + <p>The encoding of of <c><anno>Filename</anno></c> can be set + by a comment as described in <seealso + marker="stdlib:epp#encoding">epp(3)</seealso>.</p> </desc> </func> <func> @@ -412,7 +430,7 @@ </desc> </func> <func> - <name>file_info(Filename) -> {ok, FileInfo} | {error, Reason}</name> + <name name="file_info" arity="1"/> <fsummary>Get information about a file (deprecated)</fsummary> <desc> <p>This function is obsolete. Use <c>read_file_info/1,2</c> @@ -598,7 +616,7 @@ </desc> </func> <func> - <name>native_name_encoding() -> latin1 | utf8</name> + <name name="native_name_encoding" arity="0"/> <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> @@ -610,7 +628,7 @@ <name name="open" arity="2"/> <fsummary>Open a file</fsummary> <desc> - <p>Opens the file <c><anno>Filename</anno></c> in the mode determined + <p>Opens the file <c><anno>File</anno></c> in the mode determined by <c><anno>Modes</anno></c>, which may contain one or more of the following items:</p> <taglist> @@ -767,6 +785,10 @@ <p>The Encoding can be changed for a file "on the fly" by using the <seealso marker="stdlib:io#setopts/2">io:setopts/2</seealso> function, why a file can be analyzed in latin1 encoding for i.e. a BOM, positioned beyond the BOM and then be set for the right encoding before further reading.See the <seealso marker="stdlib:unicode">unicode(3)</seealso> module for functions identifying BOM's.</p> <p>This option is not allowed on <c>raw</c> files.</p> </item> + <tag><c>ram</c></tag> + <item> + <p><c>File</c> must be <c>iodata()</c>. Returns an <c>fd()</c> which lets the <c>file</c> module operate on the data in-memory as if it is a file.</p> + </item> </taglist> <p>Returns:</p> <taglist> @@ -861,6 +883,9 @@ the error.</p> </item> </taglist> + <p>The encoding of of <c><anno>Filename</anno></c> can be set + by a comment as described in <seealso + marker="stdlib:epp#encoding">epp(3)</seealso>.</p> </desc> </func> <func> @@ -902,6 +927,9 @@ of the error.</p> </item> </taglist> + <p>The encoding of of <c><anno>Filename</anno></c> can be set + by a comment as described in <seealso + marker="stdlib:epp#encoding">epp(3)</seealso>.</p> </desc> </func> <func> @@ -971,7 +999,10 @@ of the error.</p> </item> </taglist> - </desc> + <p>The encoding of of <c><anno>Filename</anno></c> can be set + by a comment as described in <seealso + marker="stdlib:epp#encoding">epp(3)</seealso>.</p> + </desc> </func> <func> <name name="path_script" arity="3"/> @@ -1502,6 +1533,9 @@ of the error.</p> </item> </taglist> + <p>The encoding of of <c><anno>Filename</anno></c> can be set + by a comment as described in <seealso + marker="stdlib:epp#encoding">epp(3)</seealso>.</p> </desc> </func> <func> diff --git a/lib/kernel/doc/src/global.xml b/lib/kernel/doc/src/global.xml index 304a9b1d88..9c50049503 100644 --- a/lib/kernel/doc/src/global.xml +++ b/lib/kernel/doc/src/global.xml @@ -163,7 +163,8 @@ <fsummary>Globally register a name for a pid</fsummary> <type name="method"/> <type_desc name="method">{<c>Module</c>, <c>Function</c>} - is also allowed + is currently also allowed for backward compatibility, but its use is + deprecated </type_desc> <desc> <p>Globally associates the name <c><anno>Name</anno></c> with a pid, that is, @@ -180,6 +181,15 @@ unregistered. This function is called once for each name clash.</p> + <warning> + <p>If you plan to change code without restarting your system, + you must use an external fun (<c>fun Module:Function/Arity</c>) + as the <c><anno>Resolve</anno></c> function; if you use a + local fun you can never replace the code for the module that + the fun belongs to. + </p> + </warning> + <p>There are three pre-defined resolve functions: <c>random_exit_name/3</c>, <c>random_notify_name/3</c>, and <c>notify_all_name/3</c>. If no <c><anno>Resolve</anno></c> function is diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml index 2826d3d00a..2856d84dcf 100644 --- a/lib/kernel/doc/src/heart.xml +++ b/lib/kernel/doc/src/heart.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2011</year> + <year>1996</year><year>2012</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index b727960d96..3d929a772e 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -323,8 +323,11 @@ fe80::204:acff:fe17:bf38 <type name="stat_option"/> <desc> <p>Gets one or more statistic options for a socket.</p> + <p><c>getstat(<anno>Socket</anno>)</c> is equivalent to - <c>getstat(<anno>Socket</anno>, [recv_avg, recv_cnt, recv_dvi, recv_max, recv_oct, send_avg, send_cnt, send_dvi, send_max, send_oct])</c></p> + <c>getstat(<anno>Socket</anno>, [recv_avg, recv_cnt, recv_dvi, + recv_max, recv_oct, send_avg, send_cnt, send_dvi, send_max, + send_oct])</c>.</p> <p>The following options are available:</p> <taglist> <tag><c>recv_avg</c></tag> @@ -371,7 +374,51 @@ fe80::204:acff:fe17:bf38 </taglist> </desc> </func> - + <func> + <name name="parse_ipv4_address" arity="1" /> + <fsummary>Parse an IPv4 address</fsummary> + <desc> + <p>Parses an IPv4 address string and returns an <a href="#type-ip4_address">ip4_address()</a>. + Accepts a shortened IPv4 shortened address string.</p> + </desc> + </func> + <func> + <name name="parse_ipv4strict_address" arity="1" /> + <fsummary>Parse an IPv4 address strict.</fsummary> + <desc> + <p>Parses an IPv4 address string containing four fields, i.e <b>not</b> shortened, and returns an <a href="#type-ip4_adress">ip4_address()</a>.</p> + </desc> + </func> + <func> + <name name="parse_ipv6_address" arity="1" /> + <fsummary>Parse an IPv6 address</fsummary> + <desc> + <p>Parses an IPv6 address string and returns an <a href="#type-ip6_address">ip6_address()</a>. + If an IPv4 address string is passed, an IPv4-mapped IPv6 address is returned.</p> + </desc> + </func> + <func> + <name name="parse_ipv6strict_address" arity="1" /> + <fsummary>Parse an IPv6 address strict.</fsummary> + <desc> + <p>Parses an IPv6 address string and returns an <a href="#type-ip6_address">ip6_address()</a>. + Does <b>not</b> accept IPv4 adresses.</p> + </desc> + </func> + <func> + <name name="parse_address" arity="1" /> + <fsummary>Parse an IPv4 or IPv6 address.</fsummary> + <desc> + <p>Parses an IPv4 or IPv6 address string and returns an <a href="#type-ip4_address">ip4_address()</a> or <a href="#type-ip6_address">ip6_address()</a>. Accepts a shortened IPv4 address string.</p> + </desc> + </func> + <func> + <name name="parse_strict_address" arity="1" /> + <fsummary>Parse an IPv4 or IPv6 address strict.</fsummary> + <desc> + <p>Parses an IPv4 or IPv6 address string and returns an <a href="#type-ip4_address">ip4_address()</a> or <a href="#type-ip6_adress">ip6_address()</a>. Does <b>not</b> accept a shortened IPv4 address string.</p> + </desc> + </func> <func> <name name="peername" arity="1"/> <fsummary>Return the address and port for the other end of a connection</fsummary> @@ -446,16 +493,6 @@ fe80::204:acff:fe17:bf38 faster than the receiver can read.</p> </item> - <tag><c>{bit8, clear | set | on | off}</c></tag> - <item> - <p> - Scans every byte in received data-packets and checks if the 8 bit - is set in any of them. Information is retrieved with - <c>inet:getopts/2</c>. - </p> - <p>Note that the <c>bit8</c> option is deprecated and will be removed in Erlang/OTP R16.</p> - </item> - <tag><c>{broadcast, Boolean}</c>(UDP sockets)</tag> <item> <p>Enable/disable permission to send broadcasts.</p> @@ -522,13 +559,100 @@ fe80::204:acff:fe17:bf38 <c>[Byte1,Byte2|Binary]</c>.</p> </item> - <tag><c>{high_watermark, Size}</c></tag> - <item> <p> - Sender is forced busy if sent and enqueued data - reaches the highwater mark. - <br /> Default: 8192 kB. - </p> - </item> + <tag><c>{high_msgq_watermark, Size}</c> (TCP/IP sockets)</tag> + <item> + <p>The socket message queue will be set into a busy + state when the amount of data queued on the message + queue reaches this limit. Note that this limit only + concerns data that have not yet reached the ERTS internal + socket implementation. Default value used is 8 kB.</p> + <p>Senders of data to the socket will be suspended if + either the socket message queue is busy, or the socket + itself is busy.</p> + <p>For more information see the <c>low_msgq_watermark</c>, + <c>high_watermark</c>, and <c>low_watermark</c> options.</p> + <p>Note that distribution sockets will disable the use of + <c>high_msgq_watermark</c> and <c>low_msgq_watermark</c>, + and will instead use the + <seealso marker="erts:erlang#system_info_dist_buf_busy_limit">distribution + buffer busy limit</seealso> which is a similar feature.</p> + </item> + + <tag><c>{high_watermark, Size}</c> (TCP/IP sockets)</tag> + <item> + <p>The socket will be set into a busy state when the amount + of data queued internally by the ERTS socket implementation + reaches this limit. Default value used is 8 kB.</p> + <p>Senders of data to the socket will be suspended if + either the socket message queue is busy, or the socket + itself is busy.</p> + <p>For more information see the <c>low_watermark</c>, + <c>high_msgq_watermark</c>, and <c>low_msqg_watermark</c> + options.</p> + </item> + + <tag><c>{ipv6_v6only, Boolean}</c></tag> + <item> + <p> + Restricts the socket to only use IPv6, prohibiting any + IPv4 connections. This is only applicable for + IPv6 sockets (option <c>inet6</c>). + </p> + <p> + On most platforms this option has to be set on the socket + before associating it to an address. Therefore it is only + reasonable to give it when creating the socket and not + to use it when calling the function + (<seealso marker="#setopts/2">setopts/2</seealso>) + containing this description. + </p> + <p> + The behaviour of a socket with this socket option set to + <c>true</c> is becoming the only portable one. The original + idea when IPv6 was new of using IPv6 for all traffic + is now not recommended by FreeBSD (you can use + <c>{ipv6_v6only,false}</c> to override the recommended + system default value), + forbidden by OpenBSD (the supported GENERIC kernel) + and impossible on Windows (that has separate + IPv4 and IPv6 protocol stacks). Most Linux distros + still have a system default value of <c>false</c>. + This policy shift among operating systems towards + separating IPv6 from IPv4 traffic has evolved since + it gradually proved hard and complicated to get + a dual stack implementation correct and secure. + </p> + <p> + On some platforms the only allowed value for this option + is <c>true</c>, e.g. OpenBSD and Windows. Trying to set + this option to <c>false</c> when creating the socket + will in this case fail. + </p> + <p> + Setting this option on platforms where it does not exist + is ignored and getting this option with + <seealso marker="#getopts/2">getopts/2</seealso> + returns no value i.e the returned list will not contain an + <c>{ipv6_v6only,_}</c> tuple. On Windows the option acually + does not exist, but it is emulated as being a + read-only option with the value <c>true</c>. + </p> + <p> + So it boils down to that setting this option to <c>true</c> + when creating a socket will never fail except possibly + (at the time of this writing) on a platform where you + have customized the kernel to only allow <c>false</c>, + which might be doable (but weird) on e.g. OpenBSD. + </p> + <p> + If you read back the option value using + <seealso marker="#getopts/2">getopts/2</seealso> + and get no value the option does not exist in the host OS + and all bets are off regarding the behaviour of both + an IPv6 and an IPv4 socket listening on the same port + as well as for an IPv6 socket getting IPv4 traffic. + </p> + </item> <tag><c>{keepalive, Boolean}</c>(TCP/IP sockets)</tag> <item> @@ -550,14 +674,41 @@ fe80::204:acff:fe17:bf38 the flushing time-out in seconds.</p> </item> - <tag><c>{low_watermark, Size}</c></tag> - <item> <p> - If the port has reached its <c>high_watermark</c> it will - force busy onto senders. When the port data queue reaches the - <c>low_watermark</c> callers are no longer forced busy. - <br /> Default: 4096 kB. - </p> - </item> + <tag><c>{low_msgq_watermark, Size}</c> (TCP/IP sockets)</tag> + <item> + <p>If the socket message queue is in a busy state, the + socket message queue will be set in a not busy state when + the amount of data queued in the message queue falls + below this limit. Note that this limit only concerns data + that have not yet reached the ERTS internal socket + implementation. Default value used is 4 kB.</p> + <p>Senders that have been suspended due to either a + busy message queue or a busy socket, will be resumed + when neither the socket message queue, nor the socket + are busy.</p> + <p>For more information see the <c>high_msgq_watermark</c>, + <c>high_watermark</c>, and <c>low_watermark</c> options.</p> + <p>Note that distribution sockets will disable the use of + <c>high_msgq_watermark</c> and <c>low_msgq_watermark</c>, + and will instead use the + <seealso marker="erts:erlang#system_info_dist_buf_busy_limit">distribution + buffer busy limit</seealso> which is a similar feature.</p> + </item> + + <tag><c>{low_watermark, Size}</c> (TCP/IP sockets)</tag> + <item> + <p>If the socket is in a busy state, the socket will + be set in a not busy state when the amount of data + queued internally by the ERTS socket implementation + falls below this limit. Default value used is 4 kB.</p> + <p>Senders that have been suspended due to either a + busy message queue or a busy socket, will be resumed + when neither the socket message queue, nor the socket + are busy.</p> + <p>For more information see the <c>high_watermark</c>, + <c>high_msgq_watermark</c>, and <c>low_msgq_watermark</c> + options.</p> + </item> <tag><c>{mode, Mode :: binary | list}</c></tag> <item> diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index 8e911a406b..78bc533464 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -30,6 +30,44 @@ </header> <p>This document describes the changes made to the Kernel application.</p> +<section><title>Kernel 2.15.3</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Ensure 'erl_crash.dump' when asked for it. This will + change erl_crash.dump behaviour.</p> + <p> + * Not setting ERL_CRASH_DUMP_SECONDS will now terminate + beam immediately on a crash without writing a crash dump + file.</p> + <p> + * Setting ERL_CRASH_DUMP_SECONDS to 0 will also terminate + beam immediately on a crash without writing a crash dump + file, i.e. same as not setting ERL_CRASH_DUMP_SECONDS + environment variable.</p> + <p> + * Setting ERL_CRASH_DUMP_SECONDS to a negative value will + let the beam wait indefinitely on the crash dump file + being written.</p> + <p> + * Setting ERL_CRASH_DUMP_SECONDS to a positive value will + let the beam wait that many seconds on the crash dump + file being written.</p> + <p> + A positive value will set an alarm/timeout for restart + both in beam and in heart if heart is running.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-10422 Aux Id: kunagi-250 [161] </p> + </item> + </list> + </section> + +</section> + <section><title>Kernel 2.15.2</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml index f3a051c989..5e182de41d 100644 --- a/lib/kernel/doc/src/os.xml +++ b/lib/kernel/doc/src/os.xml @@ -73,7 +73,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </desc> </func> <func> - <name>getenv() -> [string()]</name> + <name name="getenv" arity="0"/> <fsummary>List all environment variables</fsummary> <desc> <p>Returns a list of all environment variables. @@ -87,66 +87,51 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </desc> </func> <func> - <name>getenv(VarName) -> Value | false</name> + <name name="getenv" arity="1"/> <fsummary>Get the value of an environment variable</fsummary> - <type> - <v>VarName = string() </v> - <v>Value = string()</v> - </type> <desc> - <p>Returns the <c>Value</c> of the environment variable - <c>VarName</c>, or <c>false</c> if the environment variable + <p>Returns the <c><anno>Value</anno></c> of the environment variable + <c><anno>VarName</anno></c>, or <c>false</c> if the environment variable is undefined.</p> <p>If Unicode file name encoding is in effect (see the <seealso marker="erts:erl#file_name_encoding">erl manual - page</seealso>), the strings (both <c>VarName</c> and - <c>Value</c>) may contain characters with codepoints > 255.</p> + page</seealso>), the strings (both <c><anno>VarName</anno></c> and + <c><anno>Value</anno></c>) may contain characters with codepoints > 255.</p> </desc> </func> <func> - <name>getpid() -> Value </name> + <name name="getpid" arity="0"/> <fsummary>Return the process identifier of the emulator process</fsummary> - <type> - <v>Value = string()</v> - </type> <desc> <p>Returns the process identifier of the current Erlang emulator in the format most commonly used by the operating system - environment. <c>Value</c> is returned as a string containing + environment. <c><anno>Value</anno></c> is returned as a string containing the (usually) numerical identifier for a process. On Unix, this is typically the return value of the <c>getpid()</c> - system call. On VxWorks, <c>Value</c> contains the task id - (decimal notation) of the Erlang task. On Windows, + system call. On Windows, the process id as returned by the <c>GetCurrentProcessId()</c> system call is used.</p> </desc> </func> <func> - <name>putenv(VarName, Value) -> true</name> + <name name="putenv" arity="2"/> <fsummary>Set a new value for an environment variable</fsummary> - <type> - <v>VarName = string() </v> - <v>Value = string()</v> - </type> <desc> - <p>Sets a new <c>Value</c> for the environment variable - <c>VarName</c>.</p> + <p>Sets a new <c><anno>Value</anno></c> for the environment variable + <c><anno>VarName</anno></c>.</p> <p>If Unicode filename encoding is in effect (see the <seealso marker="erts:erl#file_name_encoding">erl manual - page</seealso>), the strings (both <c>VarName</c> and - <c>Value</c>) may contain characters with codepoints > 255.</p> + page</seealso>), the strings (both <c><anno>VarName</anno></c> and + <c><anno>Value</anno></c>) may contain characters with codepoints > 255.</p> <p>On Unix platforms, the environment will be set using UTF-8 encoding if Unicode file name translation is in effect. On Windows the environment is set using wide character interfaces.</p> </desc> </func> <func> - <name>timestamp() -> Timestamp</name> + <name name="timestamp" arity="0"/> + <type_desc variable="Timestamp">Timestamp = {MegaSecs, Secs, MicroSecs}</type_desc> <fsummary>Returna a timestamp from the OS in the erlang:now/0 format</fsummary> - <type> - <v>Timestamp = {MegaSecs, Secs, MicroSecs} = <seealso marker="erts:erlang#type-timestamp">erlang:timestamp()</seealso></v> - <v>MegaSecs = Secs = MicroSecs = integer() >= 0</v> - </type> <desc> <p>Returns a tuple in the same format as <seealso marker="erts:erlang#now/0">erlang:now/0</seealso>. The difference is that this function returns what the operating system thinks (a.k.a. the wall clock time) without any attempts at time correction. The result of two different calls to this function is <em>not</em> guaranteed to be different.</p> <p>The most obvious use for this function is logging. The tuple can be used together with the function <seealso marker="stdlib:calendar#now_to_universal_time/1">calendar:now_to_universal_time/1</seealso> @@ -183,8 +168,6 @@ format_utc_timestamp() -> Solaris 1 and 2, it will be <c>sunos</c>.</p> <p>In Windows, <c><anno>Osname</anno></c> will be either <c>nt</c> (on Windows NT), or <c>windows</c> (on Windows 95).</p> - <p>On VxWorks the OS family alone is returned, that is - <c>vxworks</c>.</p> <note> <p>Think twice before using this function. Use the <c>filename</c> module if you want to inspect or build diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile index c76ff9e2f0..60291bbce6 100644 --- a/lib/kernel/src/Makefile +++ b/lib/kernel/src/Makefile @@ -107,7 +107,6 @@ MODULES = \ net_adm \ net_kernel \ os \ - packages \ pg2 \ ram_file \ rpc \ diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl index c299fb085c..9b7c4aa7b8 100644 --- a/lib/kernel/src/application.erl +++ b/lib/kernel/src/application.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -37,8 +37,7 @@ -type application_opt() :: {'description', Description :: string()} | {'vsn', Vsn :: string()} | {'id', Id :: string()} - | {'modules', [(Module :: module()) | - {Module :: module(), Version :: term()}]} + | {'modules', [Module :: module()]} | {'registered', Names :: [Name :: atom()]} | {'applications', [Application :: atom()]} | {'included_applications', [Application :: atom()]} diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl index ebfe84463a..75ce852001 100644 --- a/lib/kernel/src/application_controller.erl +++ b/lib/kernel/src/application_controller.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -162,7 +162,7 @@ %% appl_opt() = {description, string()} | %% {vsn, string()} | %% {id, string()}, | -%% {modules, [Module|{Module,Vsn}]} | +%% {modules, [Module]} | %% {registered, [atom()]} | %% {applications, [atom()]} | %% {included_applications, [atom()]} | @@ -172,7 +172,6 @@ %% {maxP, integer()|infinity} | %% {mod, {Module, term()}} %% Module = atom() -%% Vsn = term() %% Purpose: Starts the application_controller. This process starts all %% application masters for the applications. %% The kernel application is the only application that is @@ -446,7 +445,7 @@ get_application_module(Module) -> get_application_module(Module, AppModules). get_application_module(Module, [[AppName, Modules]|AppModules]) -> - case in_modules(Module, Modules) of + case lists:member(Module, Modules) of true -> {ok, AppName}; false -> @@ -455,16 +454,6 @@ get_application_module(Module, [[AppName, Modules]|AppModules]) -> get_application_module(_Module, []) -> undefined. -%% 'modules' key in .app is a list of Module or {Module,Vsn} -in_modules(Module, [Module|_Modules]) -> - true; -in_modules(Module, [{Module, _Vsn}|_Modules]) -> - true; -in_modules(Module, [_Module|Modules]) -> - in_modules(Module, Modules); -in_modules(_Module, []) -> - false. - permit_application(ApplName, Flag) -> gen_server:call(?AC, {permit_application, ApplName, Flag}, @@ -1971,5 +1960,5 @@ to_string(Term) -> true -> Term; false -> - lists:flatten(io_lib:write(Term)) + lists:flatten(io_lib:format("~134217728p", [Term])) end. diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index 363072951e..361f2bdf8a 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -70,46 +70,6 @@ -include_lib("kernel/include/file.hrl"). -%% User interface. -%% -%% objfile_extension() -> ".beam" -%% get_path() -> [Dir] -%% set_path([Dir]) -> true | {error, bad_directory | bad_path} -%% add_path(Dir) -> true | {error, bad_directory} -%% add_patha(Dir) -> true | {error, bad_directory} -%% add_pathz(Dir) -> true | {error, bad_directory} -%% add_paths([Dir]) -> ok -%% add_pathsa([Dir]) -> ok -%% add_pathsz([Dir]) -> ok -%% del_path(Dir) -> boolean() | {error, bad_name} -%% replace_path(Name, Dir) -> true | {error, bad_directory | bad_name -%% | {badarg,_}} -%% load_file(Module) -> {module, Module} | {error, What :: atom()} -%% load_abs(File) -> {module, Module} | {error, What :: atom()} -%% load_abs(File, Module) -> {module, Module} | {error, What :: atom()} -%% load_binary(Module, File, Bin)-> {module, Module} | {error, What :: atom()} -%% ensure_loaded(Module) -> {module, Module} | {error, What :: atom()} -%% delete(Module) -> boolean() -%% purge(Module) -> boolean() kills all procs running old code -%% soft_purge(Module) -> boolean() -%% is_loaded(Module) -> {file, loaded_filename()} | false -%% all_loaded() -> [{Module, loaded_filename()}] -%% get_object_code(Module) -> {Module, Bin, Filename} | error -%% stop() -> no_return() -%% root_dir() -> Dir -%% compiler_dir() -> Dir -%% lib_dir() -> Dir -%% lib_dir(Application) -> Dir | {error, bad_name} -%% priv_dir(Application) -> Dir | {error, bad_name} -%% stick_dir(Dir) -> ok | error -%% unstick_dir(Dir) -> ok | error -%% stick_mod(Module) -> true -%% unstick_mod(Module) -> true -%% is_sticky(Module) -> boolean() -%% which(Module) -> Filename | loaded_ret_atoms() | non_existing -%% set_primary_archive((FileName, ArchiveBin, FileInfo, ParserFun) -> ok | {error, Reason} -%% clash() -> ok prints out number of clashes - %%---------------------------------------------------------------------------- %% Some types for basic exported functions of this module %%---------------------------------------------------------------------------- @@ -125,6 +85,39 @@ -type loaded_ret_atoms() :: 'cover_compiled' | 'preloaded'. -type loaded_filename() :: (Filename :: file:filename()) | loaded_ret_atoms(). +%%% BIFs + +-export([get_chunk/2, is_module_native/1, make_stub_module/3, module_md5/1]). + +-spec get_chunk(Bin, Chunk) -> + binary() | undefined when + Bin :: binary(), + Chunk :: string(). + +get_chunk(_, _) -> + erlang:nif_error(undef). + +-spec is_module_native(Module) -> true | false | undefined when + Module :: module(). + +is_module_native(_) -> + erlang:nif_error(undef). + +-spec make_stub_module(Module, Beam, Info) -> Module when + Module :: module(), + Beam :: binary(), + Info :: {list(), list()}. + +make_stub_module(_, _, _) -> + erlang:nif_error(undef). + +-spec module_md5(binary()) -> binary() | undefined. + +module_md5(_) -> + erlang:nif_error(undef). + +%%% End of BIFs + %%---------------------------------------------------------------------------- %% User interface %%---------------------------------------------------------------------------- @@ -366,7 +359,6 @@ load_code_server_prerequisites() -> hipe_unified_loader, lists, os, - packages, unicode], [M = M:module_info(module) || M <- Needed], ok. @@ -420,7 +412,7 @@ which(Module) when is_atom(Module) -> end. which2(Module) -> - Base = to_path(Module), + Base = atom_to_list(Module), File = filename:basename(Base) ++ objfile_extension(), Path = get_path(), which(File, filename:dirname(Base), Path). @@ -554,9 +546,6 @@ has_ext(Ext, Extlen, File) -> _ -> false end. -to_path(X) -> - filename:join(packages:split(X)). - -spec load_native_code_for_all_loaded() -> ok. load_native_code_for_all_loaded() -> Architecture = erlang:system_info(hipe_architecture), diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index 00ad923466..b2d2c19f78 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -1229,7 +1229,7 @@ load_abs(File, Mod0, Caller, St) -> end. try_load_module(Mod, Dir, Caller, St) -> - File = filename:append(Dir, to_path(Mod) ++ + File = filename:append(Dir, to_list(Mod) ++ objfile_extension()), case erl_prim_loader:get_file(File) of error -> @@ -1347,7 +1347,7 @@ load_file_1(Mod, Caller, #state{cache=Cache}=St0) -> end. mod_to_bin([Dir|Tail], Mod) -> - File = filename:append(Dir, to_path(Mod) ++ objfile_extension()), + File = filename:append(Dir, to_list(Mod) ++ objfile_extension()), case erl_prim_loader:get_file(File) of error -> mod_to_bin(Tail, Mod); @@ -1356,7 +1356,7 @@ mod_to_bin([Dir|Tail], Mod) -> end; mod_to_bin([], Mod) -> %% At last, try also erl_prim_loader's own method - File = to_path(Mod) ++ objfile_extension(), + File = to_list(Mod) ++ objfile_extension(), case erl_prim_loader:get_file(File) of error -> error; % No more alternatives ! @@ -1570,6 +1570,3 @@ to_list(X) when is_atom(X) -> atom_to_list(X). to_atom(X) when is_atom(X) -> X; to_atom(X) when is_list(X) -> list_to_atom(X). - -to_path(X) -> - filename:join(packages:split(X)). diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl index 5b1efcd395..1513fdaec0 100644 --- a/lib/kernel/src/disk_log.erl +++ b/lib/kernel/src/disk_log.erl @@ -44,6 +44,8 @@ %% To be used for debugging only: -export([pid2name/1]). +-export_type([continuation/0]). + -type dlog_state_error() :: 'ok' | {'error', term()}. -record(state, {queue = [], diff --git a/lib/kernel/src/disk_log_1.erl b/lib/kernel/src/disk_log_1.erl index 266df84a03..0cb1ed579a 100644 --- a/lib/kernel/src/disk_log_1.erl +++ b/lib/kernel/src/disk_log_1.erl @@ -1495,7 +1495,7 @@ fwrite_close2(Fd, FileName, B) -> pwrite_close2(Fd, FileName, Position, B) -> case file:pwrite(Fd, Position, B) of ok -> ok; - Error -> file_error(FileName, {error, Error}) + {error,Error} -> file_error(FileName, {error, Error}) end. position2(Fd, FileName, Pos) -> diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl index f0d54a2f3e..e3511988a6 100644 --- a/lib/kernel/src/dist_util.erl +++ b/lib/kernel/src/dist_util.erl @@ -757,7 +757,8 @@ setup_timer(Pid, Timeout) -> end. reset_timer(Timer) -> - Timer ! {self(), reset}. + Timer ! {self(), reset}, + ok. cancel_timer(Timer) -> unlink(Timer), diff --git a/lib/kernel/src/erl_ddll.erl b/lib/kernel/src/erl_ddll.erl index 646cac99c5..e03d280cd8 100644 --- a/lib/kernel/src/erl_ddll.erl +++ b/lib/kernel/src/erl_ddll.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,9 +30,97 @@ %%---------------------------------------------------------------------------- -type path() :: string() | atom(). --type driver() :: string() | atom(). +-type driver() :: iolist() | atom(). %%---------------------------------------------------------------------------- +%%% BIFs + +-export([demonitor/1, info/2, format_error_int/1, monitor/2, + try_load/3, try_unload/2, loaded_drivers/0]). + +-spec demonitor(MonitorRef) -> ok when + MonitorRef :: reference(). + +demonitor(_) -> + erlang:nif_error(undef). + +-spec info(Name, Tag) -> Value when + Name :: driver(), + Tag :: processes | driver_options | port_count | linked_in_driver + | permanent | awaiting_load | awaiting_unload, + Value :: term(). + +info(_, _) -> + erlang:nif_error(undef). + +-spec format_error_int(ErrSpec) -> string() when + ErrSpec :: term(). + +format_error_int(_) -> + erlang:nif_error(undef). + +-spec monitor(Tag, Item) -> MonitorRef when + Tag :: driver, + Item :: {Name, When}, + Name :: driver(), + When :: loaded | unloaded | unloaded_only, + MonitorRef :: reference(). + +monitor(_, _) -> + erlang:nif_error(undef). + +-spec try_load(Path, Name, OptionList) -> + {ok,Status} | + {ok, PendingStatus, Ref} | + {error, ErrorDesc} when + Path :: path(), + Name :: driver(), + OptionList :: [Option], + Option :: {driver_options, DriverOptionList} + | {monitor, MonitorOption} + | {reload, ReloadOption}, + DriverOptionList :: [DriverOption], + DriverOption :: kill_ports, + MonitorOption :: pending_driver | pending, + ReloadOption :: pending_driver | pending, + Status :: loaded | already_loaded | PendingStatus, + PendingStatus :: pending_driver | pending_process, + Ref :: reference(), + ErrorDesc :: ErrorAtom | OpaqueError, + ErrorAtom :: linked_in_driver | inconsistent | permanent + | not_loaded_by_this_process | not_loaded + | pending_reload | pending_process, + OpaqueError :: term(). + +try_load(_, _, _) -> + erlang:nif_error(undef). + +-spec try_unload(Name, OptionList) -> + {ok, Status} | + {ok, PendingStatus, Ref} | + {error, ErrorAtom} when + Name :: driver(), + OptionList :: [Option], + Option :: {monitor, MonitorOption} | kill_ports, + MonitorOption :: pending_driver | pending, + Status :: unloaded | PendingStatus, + PendingStatus :: pending_driver | pending_process, + Ref :: reference(), + ErrorAtom :: linked_in_driver | not_loaded | + not_loaded_by_this_process | permanent. + +try_unload(_, _) -> + erlang:nif_error(undef). + +-spec loaded_drivers() -> {ok, Drivers} when + Drivers :: [Driver], + Driver :: string(). + +loaded_drivers() -> + erlang:nif_error(undef). + +%%% End of BIFs + -spec start() -> {'error', {'already_started', 'undefined'}}. diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl index a67b11a888..f8bc5f499c 100644 --- a/lib/kernel/src/error_handler.erl +++ b/lib/kernel/src/error_handler.erl @@ -90,7 +90,7 @@ int() -> int. crash(Fun, Args) -> crash({Fun,Args,[]}). --spec crash(atom(), atom(), arity()) -> no_return(). +-spec crash(atom(), atom(), arity() | [term()]) -> no_return(). crash(M, F, A) -> crash({M,F,A,[]}). diff --git a/lib/kernel/src/error_logger.erl b/lib/kernel/src/error_logger.erl index f94cca000f..92c1eb80dc 100644 --- a/lib/kernel/src/error_logger.erl +++ b/lib/kernel/src/error_logger.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -42,6 +42,18 @@ -type state() :: {non_neg_integer(), non_neg_integer(), [term()]}. +%%% BIF + +-export([warning_map/0]). + +-spec warning_map() -> Tag when + Tag :: error | warning | info. + +warning_map() -> + erlang:nif_error(undef). + +%%% End of BIF + %%----------------------------------------------------------------- -spec start() -> {'ok', pid()} | {'error', any()}. diff --git a/lib/kernel/src/erts_debug.erl b/lib/kernel/src/erts_debug.erl index b8871e0d45..6654cd9ee7 100644 --- a/lib/kernel/src/erts_debug.erl +++ b/lib/kernel/src/erts_debug.erl @@ -28,6 +28,135 @@ %% same/2 %% flat_size/1 +%%% BIFs + +-export([breakpoint/2, disassemble/1, display/1, dist_ext_to_term/2, + dump_monitors/1, dump_links/1, flat_size/1, + get_internal_state/1, instructions/0, lock_counters/1, + same/2, set_internal_state/2]). + +-spec breakpoint(MFA, Flag) -> non_neg_integer() when + MFA :: {Module :: module(), + Function :: atom(), + Arity :: arity() | '_'}, + Flag :: boolean(). + +breakpoint(_, _) -> + erlang:nif_error(undef). + +-spec disassemble(What) -> false | undef | Result when + What :: MFA | Address, + Result :: {Address, Code, MFA}, + MFA :: mfa(), + Address :: non_neg_integer(), + Code :: binary(). + +disassemble(_) -> + erlang:nif_error(undef). + +-spec display(Term) -> string() when + Term :: term(). + +display(_) -> + erlang:nif_error(undef). + +-spec dist_ext_to_term(Tuple, Binary) -> term() when + Tuple :: tuple(), + Binary :: binary(). + +dist_ext_to_term(_, _) -> + erlang:nif_error(undef). + +-spec dump_monitors(Id) -> true when + Id :: pid() | atom(). + +dump_monitors(_) -> + erlang:nif_error(undef). + +-spec dump_links(Id) -> true when + Id :: pid() | port() | atom(). + +dump_links(_) -> + erlang:nif_error(undef). + +-spec flat_size(Term) -> non_neg_integer() when + Term :: term(). + +flat_size(_) -> + erlang:nif_error(undef). + +-spec get_internal_state(W) -> term() when + W :: reds_left | node_and_dist_references | monitoring_nodes + | next_pid | 'DbTable_words' | check_io_debug + | process_info_args | processes | processes_bif_info + | max_atom_out_cache_index | nbalance | available_internal_state + | force_heap_frags | memory + | {process_status, pid()} + | {link_list, pid() | port() | node()} + | {monitor_list, pid() | node()} + | {channel_number, non_neg_integer()} + | {have_pending_exit, pid() | port() | atom()} + | {binary_info, binary()} + | {term_to_binary_no_funs, term()} + | {dist_port, port()} + | {atom_out_cache_index, atom()} + | {fake_scheduler_bindings, + default_bind | spread | processor_spread | thread_spread + | thread_no_node_processor_spread | no_node_processor_spread + | no_node_thread_spread | no_spread | unbound} + | {reader_groups_map, non_neg_integer()}. + +get_internal_state(_) -> + erlang:nif_error(undef). + +-spec instructions() -> [string()]. + +instructions() -> + erlang:nif_error(undef). + +-spec lock_counters(info) -> term(); + (clear) -> ok; + ({copy_save, boolean()}) -> boolean(); + ({process_locks, boolean()}) -> boolean(). + +lock_counters(_) -> + erlang:nif_error(undef). + +-spec same(Term1, Term2) -> boolean() when + Term1 :: term(), + Term2 :: term(). + +same(_, _) -> + erlang:nif_error(undef). + +-spec set_internal_state(available_internal_state, boolean()) -> boolean(); + (reds_left, non_neg_integer()) -> true; + (block, non_neg_integer()) -> true; + (sleep, non_neg_integer()) -> true; + (block_scheduler, non_neg_integer()) -> true; + (next_pid, non_neg_integer()) -> false | integer(); + (force_gc, pid() | atom()) -> boolean(); + (send_fake_exit_signal, {pid() | port(), pid(), term()}) -> dead | message | unaffected | exit; + (colliding_names, {atom(), non_neg_integer()}) -> + [atom()]; + (binary_loop_limit, default) -> -1; + (binary_loop_limit, non_neg_integer()) -> non_neg_integer(); + (re_loop_limit, default) -> -1; + (re_loop_limit, non_neg_integer()) -> non_neg_integer(); + (unicode_loop_limit, default) -> -1; + (unicode_loop_limit, non_neg_integer()) -> non_neg_integer(); + (hipe_test_reschedule_suspend, term()) -> nil(); + (hipe_test_reschedule_resume, pid() | port()) -> boolean(); + (test_long_gc_sleep, non_neg_integer()) -> true; + (kill_dist_connection, port()) -> boolean(); + (not_running_optimization, boolean()) -> boolean(); + (wait, deallocations) -> ok. + +set_internal_state(_, _) -> + erlang:nif_error(undef). + +%%% End of BIFs + %% size(Term) %% Returns the size of Term in actual heap words. Shared subterms are %% counted once. Example: If A = [a,b], B =[A,A] then size(B) returns 8, diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index cdb984c333..16f2dde464 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -38,7 +38,7 @@ %% Specialized -export([ipread_s32bu_p32bu/3]). %% Generic file contents. --export([open/2, close/1, advise/4, +-export([open/2, close/1, advise/4, allocate/3, read/2, write/2, pread/2, pread/3, pwrite/2, pwrite/3, read_line/1, @@ -111,6 +111,24 @@ -type sendfile_option() :: {chunk_size, non_neg_integer()}. -type file_info_option() :: {'time', 'local'} | {'time', 'universal'} | {'time', 'posix'}. +%%% BIFs + +-export([file_info/1, native_name_encoding/0]). + +-spec file_info(Filename) -> {ok, FileInfo} | {error, Reason} when + Filename :: name(), + FileInfo :: file_info(), + Reason :: posix() | badarg. + +file_info(_) -> + erlang:nif_error(undef). + +-spec native_name_encoding() -> latin1 | utf8. + +native_name_encoding() -> + erlang:nif_error(undef). + +%%% End of BIFs %%%----------------------------------------------------------------- @@ -379,9 +397,10 @@ raw_write_file_info(Name, #file_info{} = Info) -> %% Contemporary mode specification - list of options --spec open(Filename, Modes) -> {ok, IoDevice} | {error, Reason} when +-spec open(File, Modes) -> {ok, IoDevice} | {error, Reason} when + File :: Filename | iodata(), Filename :: name(), - Modes :: [mode()], + Modes :: [mode() | ram], IoDevice :: io_device(), Reason :: posix() | badarg | system_limit. @@ -471,6 +490,18 @@ advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) -> advise(_, _, _, _) -> {error, badarg}. +-spec allocate(File, Offset, Length) -> + 'ok' | {'error', posix()} when + File :: io_device(), + Offset :: non_neg_integer(), + Length :: non_neg_integer(). + +allocate(File, Offset, Length) when is_pid(File) -> + R = file_request(File, {allocate, Offset, Length}), + wait_file_reply(File, R); +allocate(#file_descriptor{module = Module} = Handle, Offset, Length) -> + Module:allocate(Handle, Offset, Length). + -spec read(IoDevice, Number) -> {ok, Data} | eof | {error, Reason} when IoDevice :: io_device() | atom(), Number :: non_neg_integer(), @@ -1296,6 +1327,7 @@ sendfile_send(Sock, Data, Old) -> %%% Helpers consult_stream(Fd) -> + _ = epp:set_encoding(Fd), consult_stream(Fd, 1, []). consult_stream(Fd, Line, Acc) -> @@ -1309,6 +1341,7 @@ consult_stream(Fd, Line, Acc) -> end. eval_stream(Fd, Handling, Bs) -> + _ = epp:set_encoding(Fd), eval_stream(Fd, Handling, 1, undefined, [], Bs). eval_stream(Fd, H, Line, Last, E, Bs) -> diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl index 0bff56cf46..fad2ed7fb3 100644 --- a/lib/kernel/src/file_io_server.erl +++ b/lib/kernel/src/file_io_server.erl @@ -40,6 +40,8 @@ format_error({_Line, ?MODULE, Reason}) -> io_lib:format("~w", [Reason]); format_error({_Line, Mod, Reason}) -> Mod:format_error(Reason); +format_error(invalid_unicode) -> + io_lib:format("cannot translate from UTF-8", []); format_error(ErrorId) -> erl_posix_msg:message(ErrorId). @@ -209,6 +211,10 @@ file_request({advise,Offset,Length,Advise}, Reply -> {reply,Reply,State} end; +file_request({allocate, Offset, Length}, + #state{handle = Handle} = State) -> + Reply = ?PRIM_FILE:allocate(Handle, Offset, Length), + {reply, Reply, State}; file_request({pread,At,Sz}, #state{handle=Handle,buf=Buf,read_mode=ReadMode}=State) -> case position(Handle, At, Buf) of @@ -549,7 +555,7 @@ get_chars_notempty(Mod, Func, XtraArg, S, OutEnc, <<>> -> get_chars_apply(Mod, Func, XtraArg, S, OutEnc, State, eof); _ -> - {stop,invalid_unicode,{error,invalid_unicode},State} + {stop,invalid_unicode,invalid_unicode_error(Mod, Func, XtraArg, S),State} end; {error,Reason}=Error -> {stop,Reason,Error,State} @@ -616,12 +622,22 @@ get_chars_apply(Mod, Func, XtraArg, S0, OutEnc, end catch exit:ExReason -> - {stop,ExReason,{error,err_func(Mod, Func, XtraArg)},State}; + {stop,ExReason,invalid_unicode_error(Mod, Func, XtraArg, S0),State}; error:ErrReason -> {stop,ErrReason,{error,err_func(Mod, Func, XtraArg)},State} end. - +%% A hack that tries to inform the caller about the position where the +%% error occured. +invalid_unicode_error(Mod, Func, XtraArg, S) -> + try + {erl_scan,tokens,_Args} = XtraArg, + Location = erl_scan:continuation_location(S), + {error,{Location, ?MODULE, invalid_unicode},Location} + catch + _:_ -> + {error,err_func(Mod, Func, XtraArg)} + end. %% Convert error code to make it look as before err_func(io_lib, get_until, {_,F,_}) -> diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index 8fa963ec78..74ad192802 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -44,6 +44,7 @@ {priority, non_neg_integer()} | {recbuf, non_neg_integer()} | {reuseaddr, boolean()} | + {ipv6_v6only, boolean()} | {sctp_adaptation_layer, #sctp_setadaptation{}} | {sctp_associnfo, #sctp_assocparams{}} | {sctp_autoclose, non_neg_integer()} | @@ -72,6 +73,7 @@ priority | recbuf | reuseaddr | + ipv6_v6only | sctp_adaptation_layer | sctp_associnfo | sctp_autoclose | diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl index e6dfdadb03..ec13ab6d2e 100644 --- a/lib/kernel/src/gen_tcp.erl +++ b/lib/kernel/src/gen_tcp.erl @@ -37,9 +37,11 @@ {dontroute, boolean()} | {exit_on_close, boolean()} | {header, non_neg_integer()} | + {high_msgq_watermark, pos_integer()} | {high_watermark, non_neg_integer()} | {keepalive, boolean()} | {linger, {boolean(), non_neg_integer()}} | + {low_msgq_watermark, pos_integer()} | {low_watermark, non_neg_integer()} | {mode, list | binary} | list | binary | {nodelay, boolean()} | @@ -57,7 +59,8 @@ {send_timeout, non_neg_integer() | infinity} | {send_timeout_close, boolean()} | {sndbuf, non_neg_integer()} | - {tos, non_neg_integer()}. + {tos, non_neg_integer()} | + {ipv6_v6only, boolean()}. -type option_name() :: active | buffer | @@ -66,9 +69,11 @@ dontroute | exit_on_close | header | + high_msgq_watermark | high_watermark | keepalive | linger | + low_msgq_watermark | low_watermark | mode | nodelay | @@ -85,7 +90,8 @@ send_timeout | send_timeout_close | sndbuf | - tos. + tos | + ipv6_v6only. -type connect_option() :: {ip, inet:ip_address()} | {fd, Fd :: non_neg_integer()} | diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl index 830ca61b3c..c5a1173575 100644 --- a/lib/kernel/src/gen_udp.erl +++ b/lib/kernel/src/gen_udp.erl @@ -47,7 +47,8 @@ {recbuf, non_neg_integer()} | {reuseaddr, boolean()} | {sndbuf, non_neg_integer()} | - {tos, non_neg_integer()}. + {tos, non_neg_integer()} | + {ipv6_v6only, boolean()}. -type option_name() :: active | broadcast | @@ -69,7 +70,8 @@ recbuf | reuseaddr | sndbuf | - tos. + tos | + ipv6_v6only. -type socket() :: port(). -export_type([option/0, option_name/0]). diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl index 36cb713ee1..b24a9d5eac 100644 --- a/lib/kernel/src/global.erl +++ b/lib/kernel/src/global.erl @@ -232,7 +232,8 @@ register_name(Name, Pid) when is_pid(Pid) -> Name :: term(), Pid :: pid(), Resolve :: method(). -register_name(Name, Pid, Method) when is_pid(Pid) -> +register_name(Name, Pid, Method0) when is_pid(Pid) -> + Method = allow_tuple_fun(Method0), Fun = fun(Nodes) -> case (where(Name) =:= undefined) andalso check_dupname(Name, Pid) of true -> @@ -290,7 +291,8 @@ re_register_name(Name, Pid) when is_pid(Pid) -> Name :: term(), Pid :: pid(), Resolve :: method(). -re_register_name(Name, Pid, Method) when is_pid(Pid) -> +re_register_name(Name, Pid, Method0) when is_pid(Pid) -> + Method = allow_tuple_fun(Method0), Fun = fun(Nodes) -> gen_server:multi_call(Nodes, global_name_server, @@ -2218,3 +2220,9 @@ intersection(_, []) -> []; intersection(L1, L2) -> L1 -- (L1 -- L2). + +%% Support legacy tuple funs as resolve functions. +allow_tuple_fun({M, F}) when is_atom(M), is_atom(F) -> + fun M:F/3; +allow_tuple_fun(Fun) when is_function(Fun, 3) -> + Fun. diff --git a/lib/kernel/src/group.erl b/lib/kernel/src/group.erl index f92c6f7208..4d2e31a429 100644 --- a/lib/kernel/src/group.erl +++ b/lib/kernel/src/group.erl @@ -424,7 +424,7 @@ get_password_chars(Drv,Buf) -> end. get_chars(Prompt, M, F, Xa, Drv, Buf, Encoding) -> - Pbs = prompt_bytes(Prompt), + Pbs = prompt_bytes(Prompt, Encoding), get_chars_loop(Pbs, M, F, Xa, Drv, Buf, start, Encoding). get_chars_loop(Pbs, M, F, Xa, Drv, Buf0, State, Encoding) -> @@ -688,9 +688,9 @@ edit_password([Char|Cs],Chars) -> edit_password(Cs,[Char|Chars]). %% prompt_bytes(Prompt) -%% Return a flat list of bytes for the Prompt. -prompt_bytes(Prompt) -> - lists:flatten(io_lib:format_prompt(Prompt)). +%% Return a flat list of characters for the Prompt. +prompt_bytes(Prompt, Encoding) -> + lists:flatten(io_lib:format_prompt(Prompt, Encoding)). cast(L, binary,latin1) when is_list(L) -> list_to_binary(L); diff --git a/lib/kernel/src/heart.erl b/lib/kernel/src/heart.erl index de287bfa43..87cb9d7f51 100644 --- a/lib/kernel/src/heart.erl +++ b/lib/kernel/src/heart.erl @@ -46,6 +46,7 @@ -define(TIMEOUT, 5000). -define(CYCLE_TIMEOUT, 10000). +-define(HEART_PORT_NAME, heart_port). %%--------------------------------------------------------------------- @@ -132,7 +133,7 @@ start_portprogram() -> case wait_ack(Port) of ok -> %% register port so the vm can find it if need be - register(heart_port, Port), + register(?HEART_PORT_NAME, Port), {ok, Port}; {error, Reason} -> report_problem({{port_problem, Reason}, @@ -228,6 +229,7 @@ no_reboot_shutdown(Port) -> end. do_cycle_port_program(Caller, Parent, Port, Cmd) -> + unregister(?HEART_PORT_NAME), case catch start_portprogram() of {ok, NewPort} -> send_shutdown(Port), diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl index 514c002d87..06d404905d 100644 --- a/lib/kernel/src/hipe_unified_loader.erl +++ b/lib/kernel/src/hipe_unified_loader.erl @@ -337,11 +337,16 @@ exports(ExportMap, BaseAddress) -> exports(ExportMap, BaseAddress, [], []). exports([Offset,M,F,A,IsClosure,IsExported|Rest], BaseAddress, MFAs, Addresses) -> - MFA = {M,F,A}, - Address = BaseAddress + Offset, - FunDef = #fundef{address=Address, mfa=MFA, is_closure=IsClosure, - is_exported=IsExported}, - exports(Rest, BaseAddress, [MFA|MFAs], [FunDef|Addresses]); + case IsExported andalso erlang:is_builtin(M, F, A) of + true -> + exports(Rest, BaseAddress, MFAs, Addresses); + _false -> + MFA = {M,F,A}, + Address = BaseAddress + Offset, + FunDef = #fundef{address=Address, mfa=MFA, is_closure=IsClosure, + is_exported=IsExported}, + exports(Rest, BaseAddress, [MFA|MFAs], [FunDef|Addresses]) + end; exports([], _, MFAs, Addresses) -> {MFAs, Addresses}. @@ -505,7 +510,7 @@ patch_offset(Type, Data, Address, ConstAndZone, Addresses) -> Atom = Data, patch_atom(Address, Atom); sdesc -> - patch_sdesc(Data, Address, ConstAndZone); + patch_sdesc(Data, Address, ConstAndZone, Addresses); x86_abs_pcrel -> patch_instr(Address, Data, x86_abs_pcrel) %% _ -> @@ -518,14 +523,16 @@ patch_atom(Address, Atom) -> patch_instr(Address, hipe_bifs:atom_to_word(Atom), atom). patch_sdesc(?STACK_DESC(SymExnRA, FSize, Arity, Live), - Address, {_ConstMap2,CodeAddress}) -> + Address, {_ConstMap2,CodeAddress}, _Addresses) -> ExnRA = case SymExnRA of [] -> 0; % No catch LabelOffset -> CodeAddress + LabelOffset end, ?ASSERT(assert_local_patch(Address)), - hipe_bifs:enter_sdesc({Address, ExnRA, FSize, Arity, Live}). + DBG_MFA = ?IF_DEBUG(address_to_mfa_lth(Address, _Addresses), {undefined,undefined,0}), + hipe_bifs:enter_sdesc({Address, ExnRA, FSize, Arity, Live, DBG_MFA}). + %%---------------------------------------------------------------- %% Handle a 'load_address'-type patch. @@ -732,7 +739,7 @@ find_const(ConstNo, []) -> %% add_ref(CalleeMFA, Address, Addresses, RefType, Trampoline, RemoteOrLocal) -> - CallerMFA = address_to_mfa(Address, Addresses), + CallerMFA = address_to_mfa_lth(Address, Addresses), %% just a sanity assertion below true = case RemoteOrLocal of local -> @@ -745,11 +752,31 @@ add_ref(CalleeMFA, Address, Addresses, RefType, Trampoline, RemoteOrLocal) -> %% io:format("Adding ref ~w\n",[{CallerMFA, CalleeMFA, Address, RefType}]), hipe_bifs:add_ref(CalleeMFA, {CallerMFA,Address,RefType,Trampoline,RemoteOrLocal}). -address_to_mfa(Address, [#fundef{address=Adr, mfa=MFA}|_Rest]) when Address >= Adr -> MFA; -address_to_mfa(Address, [_ | Rest]) -> address_to_mfa(Address, Rest); -address_to_mfa(Address, []) -> - ?error_msg("Local adddress not found ~w\n",[Address]), - exit({?MODULE, local_address_not_found}). +% For FunDefs sorted from low to high addresses +address_to_mfa_lth(Address, FunDefs) -> + case address_to_mfa_lth(Address, FunDefs, false) of + false -> + ?error_msg("Local adddress not found ~w\n",[Address]), + exit({?MODULE, local_address_not_found}); + MFA -> + MFA + end. + +address_to_mfa_lth(Address, [#fundef{address=Adr, mfa=MFA}|Rest], Prev) -> + if Address < Adr -> + Prev; + true -> + address_to_mfa_lth(Address, Rest, MFA) + end; +address_to_mfa_lth(_Address, [], Prev) -> + Prev. + +% For FunDefs sorted from high to low addresses +%% address_to_mfa_htl(Address, [#fundef{address=Adr, mfa=MFA}|_Rest]) when Address >= Adr -> MFA; +%% address_to_mfa_htl(Address, [_ | Rest]) -> address_to_mfa_htl(Address, Rest); +%% address_to_mfa_htl(Address, []) -> +%% ?error_msg("Local adddress not found ~w\n",[Address]), +%% exit({?MODULE, local_address_not_found}). %%---------------------------------------------------------------- %% Change callers of the given module to instead trap to BEAM. diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 1a03424f88..9670271b2e 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -30,7 +30,9 @@ ifget/3, ifget/2, ifset/3, ifset/2, getstat/1, getstat/2, ip/1, stats/0, options/0, - pushf/3, popf/1, close/1, gethostname/0, gethostname/1]). + pushf/3, popf/1, close/1, gethostname/0, gethostname/1, + parse_ipv4_address/1, parse_ipv6_address/1, parse_ipv4strict_address/1, + parse_ipv6strict_address/1, parse_address/1, parse_strict_address/1]). -export([connect_options/2, listen_options/2, udp_options/2, sctp_options/2]). @@ -527,15 +529,58 @@ getservbyname(Name, Protocol) when is_atom(Name) -> Error -> Error end. +-spec parse_ipv4_address(Address) -> + {ok, IPv4Address} | {error, einval} when + Address :: string(), + IPv4Address :: ip_address(). +parse_ipv4_address(Addr) -> + inet_parse:ipv4_address(Addr). + +-spec parse_ipv6_address(Address) -> + {ok, IPv6Address} | {error, einval} when + Address :: string(), + IPv6Address :: ip_address(). +parse_ipv6_address(Addr) -> + inet_parse:ipv6_address(Addr). + +-spec parse_ipv4strict_address(Address) -> + {ok, IPv4Address} | {error, einval} when + Address :: string(), + IPv4Address :: ip_address(). +parse_ipv4strict_address(Addr) -> + inet_parse:ipv4strict_address(Addr). + +-spec parse_ipv6strict_address(Address) -> + {ok, IPv6Address} | {error, einval} when + Address :: string(), + IPv6Address :: ip_address(). +parse_ipv6strict_address(Addr) -> + inet_parse:ipv6strict_address(Addr). + +-spec parse_address(Address) -> + {ok, IPAddress} | {error, einval} when + Address :: string(), + IPAddress :: ip_address(). +parse_address(Addr) -> + inet_parse:address(Addr). + +-spec parse_strict_address(Address) -> + {ok, IPAddress} | {error, einval} when + Address :: string(), + IPAddress :: ip_address(). +parse_strict_address(Addr) -> + inet_parse:strict_address(Addr). + %% Return a list of available options options() -> [ tos, priority, reuseaddr, keepalive, dontroute, linger, - broadcast, sndbuf, recbuf, nodelay, + broadcast, sndbuf, recbuf, nodelay, ipv6_v6only, buffer, header, active, packet, deliver, mode, multicast_if, multicast_ttl, multicast_loop, exit_on_close, high_watermark, low_watermark, - bit8, send_timeout, send_timeout_close + high_msgq_watermark, low_msgq_watermark, + send_timeout, send_timeout_close ]. %% Return a list of statistics options @@ -552,8 +597,8 @@ stats() -> connect_options() -> [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, header, active, packet, packet_size, buffer, mode, deliver, - exit_on_close, high_watermark, low_watermark, bit8, send_timeout, - send_timeout_close, delay_send,raw]. + exit_on_close, high_watermark, low_watermark, high_msgq_watermark, + low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw]. connect_options(Opts, Family) -> BaseOpts = @@ -607,9 +652,10 @@ con_add(Name, Val, R, Opts, AllOpts) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% listen_options() -> [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, - header, active, packet, buffer, mode, deliver, backlog, - exit_on_close, high_watermark, low_watermark, bit8, send_timeout, - send_timeout_close, delay_send, packet_size,raw]. + header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only, + exit_on_close, high_watermark, low_watermark, high_msgq_watermark, + low_msgq_watermark, send_timeout, send_timeout_close, delay_send, + packet_size, raw]. listen_options(Opts, Family) -> BaseOpts = @@ -664,7 +710,7 @@ list_add(Name, Val, R, Opts, As) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% udp_options() -> [tos, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode, - deliver, + deliver, ipv6_v6only, broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop, add_membership, drop_membership, read_packets,raw]. @@ -720,7 +766,7 @@ udp_add(Name, Val, R, Opts, As) -> sctp_options() -> [ % The following are generic inet options supported for SCTP sockets: mode, active, buffer, tos, priority, dontroute, reuseaddr, linger, sndbuf, - recbuf, + recbuf, ipv6_v6only, % Other options are SCTP-specific (though they may be similar to their % TCP and UDP counter-parts): @@ -1283,7 +1329,10 @@ tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) -> _ -> case prim_inet:getopt(S, active) of {ok, A0} -> - prim_inet:setopt(S, active, false), + case A0 of + false -> ok; + _ -> prim_inet:setopt(S, active, false) + end, case tcp_sync_input(S, NewOwner, false) of true -> %% socket already closed, ok; @@ -1291,7 +1340,10 @@ tcp_controlling_process(S, NewOwner) when is_port(S), is_pid(NewOwner) -> try erlang:port_connect(S, NewOwner) of true -> unlink(S), %% unlink from port - prim_inet:setopt(S, active, A0), + case A0 of + false -> ok; + _ -> prim_inet:setopt(S, active, A0) + end, ok catch error:Reason -> diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl index 1ddbdcec25..526baca335 100644 --- a/lib/kernel/src/inet_config.erl +++ b/lib/kernel/src/inet_config.erl @@ -197,16 +197,6 @@ do_load_resolv({win32,Type}, longnames) -> win32_load_from_registry(Type), inet_db:set_lookup([native]); -do_load_resolv(vxworks, _) -> - vxworks_load_hosts(), - inet_db:set_lookup([file, dns]), - case os:getenv("ERLRESCONF") of - false -> - no_ERLRESCONF; - Resolv -> - load_resolv(Resolv, resolv) - end; - do_load_resolv(_, _) -> inet_db:set_lookup([native]). @@ -408,55 +398,6 @@ win32_get_strings(Reg, [Name|Rest], Result) -> win32_get_strings(_, [], Result) -> lists:reverse(Result). -%% -%% Load host data from VxWorks hostShow command -%% - -vxworks_load_hosts() -> - HostShow = os:cmd("hostShow"), - case check_hostShow(HostShow) of - Hosts when is_list(Hosts) -> - case inet_parse:hosts_vxworks({chars, Hosts}) of - {ok, Ls} -> - foreach( - fun({IP, Name, Aliases}) -> - inet_db:add_host(IP, [Name|Aliases]) - end, - Ls); - {error,Reason} -> - error("parser error VxWorks hostShow ~s", [Reason]) - end; - _Error -> - error("error in VxWorks hostShow~s~n", [HostShow]) - end. - -%% -%% Check if hostShow yields at least two line; the first one -%% starting with "hostname", the second one starting with -%% "--------". -%% Returns: list of hosts in VxWorks notation -%% rows of 'Name IP [Aliases] \n' -%% if hostShow yielded these two lines, false otherwise. -check_hostShow(HostShow) -> - check_hostShow(["hostname", "--------"], HostShow). - -check_hostShow([], HostShow) -> - HostShow; -check_hostShow([String_match|Rest], HostShow) -> - case lists:prefix(String_match, HostShow) of - true -> - check_hostShow(Rest, next_line(HostShow)); - false -> - false - end. - -next_line([]) -> - []; -next_line([$\n|Rest]) -> - Rest; -next_line([_First|Rest]) -> - next_line(Rest). - read_rc() -> {RcFile,CfgList} = read_inetrc(), case extract_cfg_files(CfgList, [], []) of diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index cf893c73eb..000119bc74 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -124,6 +124,7 @@ -define(UDP_OPT_MULTICAST_LOOP, 13). -define(UDP_OPT_ADD_MEMBERSHIP, 14). -define(UDP_OPT_DROP_MEMBERSHIP, 15). +-define(INET_OPT_IPV6_V6ONLY, 16). % "Local" options: codes start from 20: -define(INET_LOPT_BUFFER, 20). -define(INET_LOPT_HEADER, 21). @@ -134,13 +135,14 @@ -define(INET_LOPT_EXITONCLOSE, 26). -define(INET_LOPT_TCP_HIWTRMRK, 27). -define(INET_LOPT_TCP_LOWTRMRK, 28). --define(INET_LOPT_BIT8, 29). -define(INET_LOPT_TCP_SEND_TIMEOUT, 30). -define(INET_LOPT_TCP_DELAY_SEND, 31). -define(INET_LOPT_PACKET_SIZE, 32). -define(INET_LOPT_READ_PACKETS, 33). -define(INET_OPT_RAW, 34). -define(INET_LOPT_TCP_SEND_TIMEOUT_CLOSE, 35). +-define(INET_LOPT_TCP_MSGQ_HIWTRMRK, 36). +-define(INET_LOPT_TCP_MSGQ_LOWTRMRK, 37). % Specific SCTP options: separate range: -define(SCTP_OPT_RTOINFO, 100). -define(SCTP_OPT_ASSOCINFO, 101). @@ -186,12 +188,6 @@ -define(TCP_PB_HTTP_BIN,13). -define(TCP_PB_HTTPH_BIN,14). -%% bit options, INET_LOPT_BIT8 --define(INET_BIT8_CLEAR, 0). --define(INET_BIT8_SET, 1). --define(INET_BIT8_ON, 2). --define(INET_BIT8_OFF, 3). - %% getstat, INET_REQ_GETSTAT -define(INET_STAT_RECV_CNT, 1). diff --git a/lib/kernel/src/inet_parse.erl b/lib/kernel/src/inet_parse.erl index 65edddcb46..3551e701b6 100644 --- a/lib/kernel/src/inet_parse.erl +++ b/lib/kernel/src/inet_parse.erl @@ -23,7 +23,6 @@ %% Avoid warning for local function error/2 clashing with autoimported BIF. -compile({no_auto_import,[error/2]}). -export([hosts/1, hosts/2]). --export([hosts_vxworks/1]). -export([protocols/1, protocols/2]). -export([netmasks/1, netmasks/2]). -export([networks/1, networks/2]). @@ -37,7 +36,7 @@ -export([ipv4_address/1, ipv6_address/1]). -export([ipv4strict_address/1, ipv6strict_address/1]). --export([address/1]). +-export([address/1, strict_address/1]). -export([visible_string/1, domain/1]). -export([ntoa/1, dots/1]). -export([split_line/1]). @@ -107,18 +106,6 @@ hosts(Fname,File) -> parse_file(Fname, File, Fn). %% -------------------------------------------------------------------------- -%% Parse hostShow vxworks style -%% Syntax: -%% Name IP [Aliases] \n -%% -------------------------------------------------------------------------- -hosts_vxworks(Hosts) -> - Fn = fun([Name, Address | Aliases]) -> - {ok,IP} = address(Address), - {IP, Name, Aliases} - end, - parse_file(Hosts, Fn). - -%% -------------------------------------------------------------------------- %% Parse resolv file unix style %% Syntax: %% domain Domain \n @@ -291,9 +278,6 @@ networks(Fname, File) -> %% %% -------------------------------------------------------------------------- -parse_file(File, Fn) -> - parse_file(noname, File, Fn). - parse_file(Fname, {fd,Fd}, Fn) -> parse_fd(Fname,Fd, 1, Fn, []); parse_file(Fname, {chars,Cs}, Fn) when is_list(Cs) -> @@ -472,6 +456,17 @@ address(Cs) when is_list(Cs) -> address(_) -> {error, einval}. +%%Parse ipv4 strict address or ipv6 strict address +strict_address(Cs) when is_list(Cs) -> + case ipv4strict_address(Cs) of + {ok,IP} -> + {ok,IP}; + _ -> + ipv6strict_address(Cs) + end; +strict_address(Cs) -> + {error, einval}. + %% %% Parse IPv4 address: %% d1.d2.d3.d4 diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src index 17ab84c177..9a20baf8d0 100644 --- a/lib/kernel/src/kernel.app.src +++ b/lib/kernel/src/kernel.app.src @@ -28,7 +28,6 @@ application_starter, auth, code, - packages, code_server, dist_util, erl_boot_server, diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src index bded2408a7..54628800a8 100644 --- a/lib/kernel/src/kernel.appup.src +++ b/lib/kernel/src/kernel.appup.src @@ -17,11 +17,11 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max two major revisions back - [{<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 - {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 - {<<"2\\.13(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13 + [{<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R14 %% Down to - max two major revisions back - [{<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 - {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14 - {<<"2\\.13(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13 + [{<<"2\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R16 + {<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15 + {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R14 }. diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl index 9e3d730cee..0d59e7af67 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -142,6 +142,17 @@ -include("net_address.hrl"). +%%% BIF + +-export([dflag_unicode_io/1]). + +-spec dflag_unicode_io(pid()) -> boolean(). + +dflag_unicode_io(_) -> + erlang:nif_error(undef). + +%%% End of BIF + %% Interface functions kernel_apply(M,F,A) -> request({apply,M,F,A}). diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl index f6769df585..e20a2434b4 100644 --- a/lib/kernel/src/os.erl +++ b/lib/kernel/src/os.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -24,16 +24,48 @@ -include("file.hrl"). --spec type() -> vxworks | {Osfamily, Osname} when +%%% BIFs + +-export([getenv/0, getenv/1, getpid/0, putenv/2, timestamp/0]). + +-spec getenv() -> [string()]. + +getenv() -> erlang:nif_error(undef). + +-spec getenv(VarName) -> Value | false when + VarName :: string(), + Value :: string(). + +getenv(_) -> + erlang:nif_error(undef). + +-spec getpid() -> Value when + Value :: string(). + +getpid() -> + erlang:nif_error(undef). + +-spec putenv(VarName, Value) -> true when + VarName :: string(), + Value :: string(). + +putenv(_, _) -> + erlang:nif_error(undef). + +-spec timestamp() -> Timestamp when + Timestamp :: erlang:timestamp(). + +timestamp() -> + erlang:nif_error(undef). + +%%% End of BIFs + +-spec type() -> {Osfamily, Osname} when Osfamily :: unix | win32, Osname :: atom(). type() -> - case erlang:system_info(os_type) of - {vxworks, _} -> - vxworks; - Else -> Else - end. + erlang:system_info(os_type). -spec version() -> VersionString | {Major, Minor, Release} when VersionString :: string(), @@ -83,25 +115,14 @@ find_executable1(_Name, [], _Extensions) -> verify_executable(Name0, [Ext|Rest], OrigExtensions) -> Name1 = Name0 ++ Ext, - case os:type() of - vxworks -> - %% We consider all existing VxWorks files to be executable - case file:read_file_info(Name1) of - {ok, _} -> - {ok, Name1}; - _ -> - verify_executable(Name0, Rest, OrigExtensions) - end; + case file:read_file_info(Name1) of + {ok, #file_info{type=regular,mode=Mode}} + when Mode band 8#111 =/= 0 -> + %% XXX This test for execution permission is not fool-proof + %% on Unix, since we test if any execution bit is set. + {ok, Name1}; _ -> - case file:read_file_info(Name1) of - {ok, #file_info{type=regular,mode=Mode}} - when Mode band 8#111 =/= 0 -> - %% XXX This test for execution permission is not fool-proof - %% on Unix, since we test if any execution bit is set. - {ok, Name1}; - _ -> - verify_executable(Name0, Rest, OrigExtensions) - end + verify_executable(Name0, Rest, OrigExtensions) end; verify_executable(Name, [], OrigExtensions) when OrigExtensions =/= [""] -> %% Windows %% Will only happen on windows, hence case insensitivity @@ -154,8 +175,7 @@ reverse_element(List) -> extensions() -> case type() of {win32, _} -> [".exe",".com",".cmd",".bat"]; - {unix, _} -> [""]; - vxworks -> [""] + {unix, _} -> [""] end. %% Executes the given command in the default shell for the operating system. @@ -173,11 +193,6 @@ cmd(Cmd) -> {Cspec,_} -> lists:concat([Cspec," /c",Cmd]) end, Port = open_port({spawn, Command}, [stream, in, eof, hide]), - get_data(Port, []); - %% VxWorks uses a 'sh -c hook' in 'vxcall.c' to run os:cmd. - vxworks -> - Command = lists:concat(["sh -c '", Cmd, "'"]), - Port = open_port({spawn, Command}, [stream, in, eof]), get_data(Port, []) end. diff --git a/lib/kernel/src/packages.erl b/lib/kernel/src/packages.erl deleted file mode 100644 index e0b1f36b85..0000000000 --- a/lib/kernel/src/packages.erl +++ /dev/null @@ -1,158 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2002-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(packages). - --export([to_string/1, concat/1, concat/2, is_valid/1, is_segmented/1, - split/1, last/1, first/1, strip_last/1, find_modules/1, - find_modules/2]). - -%% A package name (or a package-qualified module name) may be an atom or -%% a string (list of nonnegative integers) - not a deep list, and not a -%% list containing atoms. A name may be empty, but may not contain two -%% consecutive period (`.') characters or end with a period character. - --type package_name() :: atom() | string(). - --spec to_string(package_name()) -> string(). -to_string(Name) when is_atom(Name) -> - atom_to_list(Name); -to_string(Name) -> - Name. - -%% `concat' does not insert a leading period if the first segment is -%% empty. However, the result may contain leading, consecutive or -%% dangling period characters, if any of the segments after the first -%% are empty. Use 'is_valid' to check the result if necessary. - --spec concat(package_name(), package_name()) -> string(). -concat(A, B) -> - concat([A, B]). - --spec concat([package_name()]) -> string(). -concat([H | T]) when is_atom(H) -> - concat([atom_to_list(H) | T]); -concat(["" | T]) -> - concat_1(T); -concat(L) -> - concat_1(L). - -concat_1([H | T]) when is_atom(H) -> - concat_1([atom_to_list(H) | T]); -concat_1([H]) -> - H; -concat_1([H | T]) -> - H ++ "." ++ concat_1(T); -concat_1([]) -> - ""; -concat_1(Name) -> - erlang:error({badarg, Name}). - --spec is_valid(package_name()) -> boolean(). -is_valid(Name) when is_atom(Name) -> - is_valid_1(atom_to_list(Name)); -is_valid([$. | _]) -> - false; -is_valid(Name) -> - is_valid_1(Name). - -is_valid_1([$.]) -> false; -is_valid_1([$., $. | _]) -> false; -is_valid_1([H | T]) when is_integer(H), H >= 0 -> - is_valid_1(T); -is_valid_1([]) -> true; -is_valid_1(_) -> false. - --spec split(package_name()) -> [string()]. -split(Name) when is_atom(Name) -> - split_1(atom_to_list(Name), []); -split(Name) -> - split_1(Name, []). - -split_1([$. | T], Cs) -> - [lists:reverse(Cs) | split_1(T, [])]; -split_1([H | T], Cs) when is_integer(H), H >= 0 -> - split_1(T, [H | Cs]); -split_1([], Cs) -> - [lists:reverse(Cs)]; -split_1(_, _) -> - erlang:error(badarg). - -%% This is equivalent to testing if `split(Name)' yields a list of -%% length larger than one (i.e., if the name can be split into two or -%% more segments), but is cheaper. - --spec is_segmented(package_name()) -> boolean(). -is_segmented(Name) when is_atom(Name) -> - is_segmented_1(atom_to_list(Name)); -is_segmented(Name) -> - is_segmented_1(Name). - -is_segmented_1([$. | _]) -> true; -is_segmented_1([H | T]) when is_integer(H), H >= 0 -> - is_segmented_1(T); -is_segmented_1([]) -> false; -is_segmented_1(_) -> - erlang:error(badarg). - --spec last(package_name()) -> string(). -last(Name) -> - last_1(split(Name)). - -last_1([H]) -> H; -last_1([_ | T]) -> last_1(T). - --spec first(package_name()) -> [string()]. -first(Name) -> - first_1(split(Name)). - -first_1([H | T]) when T =/= [] -> [H | first_1(T)]; -first_1(_) -> []. - --spec strip_last(package_name()) -> string(). -strip_last(Name) -> - concat(first(Name)). - -%% This finds all modules available for a given package, using the -%% current code server search path. (There is no guarantee that the -%% modules are loadable; only that the object files exist.) - --spec find_modules(package_name()) -> [string()]. -find_modules(P) -> - find_modules(P, code:get_path()). - --spec find_modules(package_name(), [string()]) -> [string()]. -find_modules(P, Paths) -> - P1 = filename:join(packages:split(P)), - find_modules(P1, Paths, code:objfile_extension(), sets:new()). - -find_modules(P, [Path | Paths], Ext, S0) -> - case file:list_dir(filename:join(Path, P)) of - {ok, Fs} -> - Fs1 = [F || F <- Fs, filename:extension(F) =:= Ext], - S1 = lists:foldl(fun (F, S) -> - F1 = filename:rootname(F, Ext), - sets:add_element(F1, S) - end, - S0, Fs1), - find_modules(P, Paths, Ext, S1); - _ -> - find_modules(P, Paths, Ext, S0) - end; -find_modules(_P, [], _Ext, S) -> - sets:to_list(S). diff --git a/lib/kernel/src/pg2.erl b/lib/kernel/src/pg2.erl index 0d5838716e..1ff10eb303 100644 --- a/lib/kernel/src/pg2.erl +++ b/lib/kernel/src/pg2.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -159,7 +159,7 @@ get_closest_pid(Name) -> -record(state, {}). --opaque state() :: #state{}. +-type state() :: #state{}. -spec init(Arg :: []) -> {'ok', state()}. diff --git a/lib/kernel/src/ram_file.erl b/lib/kernel/src/ram_file.erl index 48ea871433..ca881ff8a4 100644 --- a/lib/kernel/src/ram_file.erl +++ b/lib/kernel/src/ram_file.erl @@ -29,6 +29,7 @@ %% Specialized file operations -export([get_size/1, get_file/1, set_file/2, get_file_close/1]). -export([compress/1, uncompress/1, uuencode/1, uudecode/1, advise/4]). +-export([allocate/3]). -export([open_mode/1]). %% used by ftp-file @@ -72,6 +73,7 @@ -define(RAM_FILE_UUDECODE, 36). -define(RAM_FILE_SIZE, 37). -define(RAM_FILE_ADVISE, 38). +-define(RAM_FILE_ALLOCATE, 39). %% Open modes for RAM_FILE_OPEN -define(RAM_FILE_MODE_READ, 1). @@ -383,6 +385,11 @@ advise(#file_descriptor{module = ?MODULE, data = Port}, Offset, advise(#file_descriptor{}, _Offset, _Length, _Advise) -> {error, enotsup}. +allocate(#file_descriptor{module = ?MODULE, data = Port}, Offset, Length) -> + call_port(Port, <<?RAM_FILE_ALLOCATE, Offset:64/signed, Length:64/signed>>); +allocate(#file_descriptor{}, _Offset, _Length) -> + {error, enotsup}. + %%%----------------------------------------------------------------- diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl index 0b1fc6e939..7c965ca384 100644 --- a/lib/kernel/src/rpc.erl +++ b/lib/kernel/src/rpc.erl @@ -62,6 +62,8 @@ %% Internals -export([proxy_user_flush/0]). +-export_type([key/0]). + %%------------------------------------------------------------------------ -type state() :: gb_tree(). diff --git a/lib/kernel/src/user.erl b/lib/kernel/src/user.erl index 88f32df20b..d6449d9e5e 100644 --- a/lib/kernel/src/user.erl +++ b/lib/kernel/src/user.erl @@ -81,7 +81,7 @@ server(PortName,PortSettings) -> run(P) -> put(read_mode,list), - put(unicode,false), + put(encoding,latin1), case init:get_argument(noshell) of %% non-empty list -> noshell {ok, [_|_]} -> @@ -191,39 +191,27 @@ do_io_request(Req, From, ReplyAs, Port, Q0) -> %% New in R13B %% Encoding option (unicode/latin1) io_request({put_chars,unicode,Chars}, Port, Q) -> % Binary new in R9C - put_chars(wrap_characters_to_binary(Chars,unicode, - case get(unicode) of - true -> unicode; - _ -> latin1 - end), Port, Q); + put_chars(wrap_characters_to_binary(Chars,unicode, get(encoding)), Port, Q); io_request({put_chars,unicode,Mod,Func,Args}, Port, Q) -> Result = case catch apply(Mod,Func,Args) of Data when is_list(Data); is_binary(Data) -> - wrap_characters_to_binary(Data,unicode, - case get(unicode) of - true -> unicode; - _ -> latin1 - end); + wrap_characters_to_binary(Data,unicode,get(encoding)); Undef -> Undef end, put_chars(Result, Port, Q); io_request({put_chars,latin1,Chars}, Port, Q) -> % Binary new in R9C - Data = case get(unicode) of - true -> + Data = case get(encoding) of + unicode -> unicode:characters_to_binary(Chars,latin1,unicode); - false -> + latin1 -> erlang:iolist_to_binary(Chars) end, put_chars(Data, Port, Q); io_request({put_chars,latin1,Mod,Func,Args}, Port, Q) -> Result = case catch apply(Mod,Func,Args) of Data when is_list(Data); is_binary(Data) -> - unicode:characters_to_binary(Data,latin1, - case get(unicode) of - true -> unicode; - _ -> latin1 - end); + unicode:characters_to_binary(Data,latin1,get(encoding)); Undef -> Undef end, @@ -351,9 +339,9 @@ check_valid_opts(_) -> do_setopts(Opts, _Port, Q) -> case proplists:get_value(encoding,Opts) of Valid when Valid =:= unicode; Valid =:= utf8 -> - put(unicode,true); + put(encoding,unicode); latin1 -> - put(unicode,false); + put(encoding,latin1); undefined -> ok end, @@ -370,12 +358,7 @@ do_setopts(Opts, _Port, Q) -> getopts(_Port,Q) -> Bin = {binary, get(read_mode) =:= binary}, - Uni = {encoding, case get(unicode) of - true -> - unicode; - _ -> - latin1 - end}, + Uni = {encoding, get(encoding)}, {ok,[Bin,Uni],Q}. @@ -575,31 +558,32 @@ binrev(L, T) -> %% end %% end %% end. -%% get_chars(Prompt, Module, Function, XtraArg, Port, Queue) +%% get_chars(Prompt, Module, Function, XtraArg, Port, Queue, Encoding) %% Gets characters from the input port until the applied function %% returns {stop,Result,RestBuf}. Does not block output until input -%% has been received. +%% has been received. Encoding is the encoding of the data sent to +%% the client and to Function. %% Returns: %% {Status,Result,NewQueue} %% {exit,Reason} %% Entry function. -get_chars(Prompt, M, F, Xa, Port, Q, Fmt) -> +get_chars(Prompt, M, F, Xa, Port, Q, Enc) -> prompt(Port, Prompt), case {get(eof),queue:is_empty(Q)} of {true,true} -> {ok,eof,Q}; _ -> - get_chars(Prompt, M, F, Xa, Port, Q, start, Fmt) + get_chars(Prompt, M, F, Xa, Port, Q, start, Enc) end. %% First loop. Wait for port data. Respond to output requests. -get_chars(Prompt, M, F, Xa, Port, Q, State, Fmt) -> +get_chars(Prompt, M, F, Xa, Port, Q, State, Enc) -> case queue:is_empty(Q) of true -> receive {Port,{data,Bytes}} -> - get_chars_bytes(State, M, F, Xa, Port, Q, Bytes, Fmt); + get_chars_bytes(State, M, F, Xa, Port, Q, Bytes, Enc); {Port, eof} -> put(eof, true), {ok, eof, []}; @@ -610,41 +594,41 @@ get_chars(Prompt, M, F, Xa, Port, Q, State, Fmt) -> do_io_request(Req, From, ReplyAs, Port, queue:new()), %Keep Q over this call %% No prompt. - get_chars(Prompt, M, F, Xa, Port, Q, State, Fmt); + get_chars(Prompt, M, F, Xa, Port, Q, State, Enc); {io_request,From,ReplyAs,Request} when is_pid(From) -> get_chars_req(Prompt, M, F, Xa, Port, Q, State, - Request, From, ReplyAs, Fmt); + Request, From, ReplyAs, Enc); {'EXIT',From,What} when node(From) =:= node() -> {exit,What} end; false -> - get_chars_apply(State, M, F, Xa, Port, Q, Fmt) + get_chars_apply(State, M, F, Xa, Port, Q, Enc) end. get_chars_req(Prompt, M, F, XtraArg, Port, Q, State, - Req, From, ReplyAs, Fmt) -> + Req, From, ReplyAs, Enc) -> do_io_request(Req, From, ReplyAs, Port, queue:new()), %Keep Q over this call prompt(Port, Prompt), - get_chars(Prompt, M, F, XtraArg, Port, Q, State, Fmt). + get_chars(Prompt, M, F, XtraArg, Port, Q, State, Enc). %% Second loop. Pass data to client as long as it wants more. %% A ^G in data interrupts loop if 'noshell' is not undefined. -get_chars_bytes(State, M, F, Xa, Port, Q, Bytes, Fmt) -> +get_chars_bytes(State, M, F, Xa, Port, Q, Bytes, Enc) -> case get(shell) of noshell -> - get_chars_apply(State, M, F, Xa, Port, queue:snoc(Q, Bytes),Fmt); + get_chars_apply(State, M, F, Xa, Port, queue:snoc(Q, Bytes),Enc); _ -> case contains_ctrl_g_or_ctrl_c(Bytes) of false -> get_chars_apply(State, M, F, Xa, Port, - queue:snoc(Q, Bytes),Fmt); + queue:snoc(Q, Bytes),Enc); _ -> throw(new_shell) end end. -get_chars_apply(State0, M, F, Xa, Port, Q, Fmt) -> - case catch M:F(State0, cast(queue:head(Q),Fmt), Fmt, Xa) of +get_chars_apply(State0, M, F, Xa, Port, Q, Enc) -> + case catch M:F(State0, cast(queue:head(Q),Enc), Enc, Xa) of {stop,Result,<<>>} -> {ok,Result,queue:tail(Q)}; {stop,Result,[]} -> @@ -653,32 +637,32 @@ get_chars_apply(State0, M, F, Xa, Port, Q, Fmt) -> {ok,Result,queue:tail(Q)}; {stop,Result,Buf} -> {ok,Result,queue:cons(Buf, queue:tail(Q))}; - {'EXIT',_} -> + {'EXIT',_Why} -> {error,{error,err_func(M, F, Xa)},queue:new()}; State1 -> - get_chars_more(State1, M, F, Xa, Port, queue:tail(Q), Fmt) + get_chars_more(State1, M, F, Xa, Port, queue:tail(Q), Enc) end. -get_chars_more(State, M, F, Xa, Port, Q, Fmt) -> +get_chars_more(State, M, F, Xa, Port, Q, Enc) -> case queue:is_empty(Q) of true -> case get(eof) of undefined -> receive {Port,{data,Bytes}} -> - get_chars_bytes(State, M, F, Xa, Port, Q, Bytes, Fmt); + get_chars_bytes(State, M, F, Xa, Port, Q, Bytes, Enc); {Port,eof} -> put(eof, true), get_chars_apply(State, M, F, Xa, Port, - queue:snoc(Q, eof), Fmt); + queue:snoc(Q, eof), Enc); {'EXIT',From,What} when node(From) =:= node() -> {exit,What} end; _ -> - get_chars_apply(State, M, F, Xa, Port, queue:snoc(Q, eof), Fmt) + get_chars_apply(State, M, F, Xa, Port, queue:snoc(Q, eof), Enc) end; false -> - get_chars_apply(State, M, F, Xa, Port, Q, Fmt) + get_chars_apply(State, M, F, Xa, Port, Q, Enc) end. @@ -689,11 +673,10 @@ get_chars_more(State, M, F, Xa, Port, Q, Fmt) -> prompt(_Port, '') -> ok; prompt(Port, Prompt) -> - put_port(wrap_characters_to_binary(io_lib:format_prompt(Prompt),unicode, - case get(unicode) of - true -> unicode; - _ -> latin1 - end), Port). + Encoding = get(encoding), + put_port(wrap_characters_to_binary(io_lib:format_prompt(Prompt, Encoding), + unicode, Encoding), + Port). %% Convert error code to make it look as before err_func(io_lib, get_until, {_,F,_}) -> @@ -710,56 +693,65 @@ contains_ctrl_g_or_ctrl_c(BinOrList)-> end. %% Convert a buffer between list and binary -cast(Data, _Format) when is_atom(Data) -> +cast(Data, _Encoding) when is_atom(Data) -> Data; -cast(Data, Format) -> - cast(Data, get(read_mode), Format, get(unicode)). +cast(Data, Encoding) -> + IoEncoding = get(encoding), + cast(Data, get(read_mode), IoEncoding, Encoding). -cast(B, binary, latin1, false) when is_binary(B) -> +cast(B, binary, latin1, latin1) when is_binary(B) -> B; -cast(B, binary, latin1, true) when is_binary(B) -> - unicode:characters_to_binary(B, unicode, latin1); -cast(L, binary, latin1, false) -> - erlang:iolist_to_binary(L); -cast(L, binary, latin1, true) -> - case unicode:characters_to_binary( - erlang:iolist_to_binary(L),unicode,latin1) of % may fail - {error,_,_} -> exit({no_translation, unicode, latin1}); - Else -> Else +cast(L, binary, latin1, latin1) -> + case catch erlang:iolist_to_binary(L) of + Bin when is_binary(Bin) -> Bin; + _ -> exit({no_translation, latin1, latin1}) + end; +cast(Data, binary, unicode, latin1) when is_binary(Data); is_list(Data) -> + case catch unicode:characters_to_binary(Data, unicode, latin1) of + Bin when is_binary(Bin) -> Bin; + _ -> exit({no_translation, unicode, latin1}) + end; +cast(Data, binary, latin1, unicode) when is_binary(Data); is_list(Data) -> + case catch unicode:characters_to_binary(Data, latin1, unicode) of + Bin when is_binary(Bin) -> Bin; + _ -> exit({no_translation, latin1, unicode}) end; -cast(B, binary, unicode, true) when is_binary(B) -> +cast(B, binary, unicode, unicode) when is_binary(B) -> B; -cast(B, binary, unicode, false) when is_binary(B) -> - unicode:characters_to_binary(B,latin1,unicode); -cast(L, binary, unicode, true) -> - % possibly a list containing UTF-8 encoded characters - unicode:characters_to_binary(erlang:iolist_to_binary(L)); -cast(L, binary, unicode, false) -> - unicode:characters_to_binary(L, latin1, unicode); -cast(L, list, latin1, UniTerm) -> - case UniTerm of - true -> % Convert input characters to protocol format (i.e latin1) - case unicode:characters_to_list( - erlang:iolist_to_binary(L),unicode) of % may fail - {error,_,_} -> exit({no_translation, unicode, latin1}); - Else -> [ case X of - High when High > 255 -> - exit({no_translation, unicode, latin1}); - Low -> - Low - end || X <- Else ] - end; - _ -> - binary_to_list(erlang:iolist_to_binary(L)) +cast(L, binary, unicode, unicode) -> + case catch unicode:characters_to_binary(L, unicode) of + Bin when is_binary(Bin) -> Bin; + _ -> exit({no_translation, unicode, unicode}) end; -cast(L, list, unicode, UniTerm) -> - unicode:characters_to_list(erlang:iolist_to_binary(L), - case UniTerm of - true -> unicode; - _ -> latin1 - end); -cast(Other, _, _,_) -> - Other. +cast(B, list, latin1, latin1) when is_binary(B) -> + binary_to_list(B); +cast(L, list, latin1, latin1) -> + case catch erlang:iolist_to_binary(L) of + Bin when is_binary(Bin) -> binary_to_list(Bin); + _ -> exit({no_translation, latin1, latin1}) + end; +cast(Data, list, unicode, latin1) when is_binary(Data); is_list(Data) -> + case catch unicode:characters_to_list(Data, unicode) of + Chars when is_list(Chars) -> + [ case X of + High when High > 255 -> + exit({no_translation, unicode, latin1}); + Low -> + Low + end || X <- Chars ]; + _ -> + exit({no_translation, unicode, latin1}) + end; +cast(Data, list, latin1, unicode) when is_binary(Data); is_list(Data) -> + case catch unicode:characters_to_list(Data, latin1) of + Chars when is_list(Chars) -> Chars; + _ -> exit({no_translation, latin1, unicode}) + end; +cast(Data, list, unicode, unicode) when is_binary(Data); is_list(Data) -> + case catch unicode:characters_to_list(Data, unicode) of + Chars when is_list(Chars) -> Chars; + _ -> exit({no_translation, unicode, unicode}) + end. wrap_characters_to_binary(Chars,unicode,latin1) -> case unicode:characters_to_binary(Chars,unicode,latin1) of diff --git a/lib/kernel/src/wrap_log_reader.erl b/lib/kernel/src/wrap_log_reader.erl index c41e0091e4..689269fc28 100644 --- a/lib/kernel/src/wrap_log_reader.erl +++ b/lib/kernel/src/wrap_log_reader.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. +%% Copyright Ericsson AB 1998-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,6 +30,8 @@ -export([open/1, open/2, chunk/1, chunk/2, close/1]). +-export_type([continuation/0]). + -include("disk_log.hrl"). -record(wrap_reader, diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index 8eca37029d..7fd3afe93c 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -73,6 +73,7 @@ MODULES= \ seq_trace_SUITE \ wrap_log_reader_SUITE \ cleanup \ + ignore_cores \ zlib_SUITE \ loose_node \ sendfile_SUITE diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 827208b048..d7424c0c9a 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -25,6 +25,7 @@ replace_path/1, load_file/1, load_abs/1, ensure_loaded/1, delete/1, purge/1, soft_purge/1, is_loaded/1, all_loaded/1, load_binary/1, dir_req/1, object_code/1, set_path_file/1, + upgrade/1, sticky_dir/1, pa_pz_option/1, add_del_path/1, dir_disappeared/1, ext_mod_dep/1, clash/1, load_cached/1, start_node_with_cache/1, add_and_rehash/1, @@ -43,6 +44,8 @@ handle_event/2, handle_call/2, handle_info/2, terminate/2]). +-export([compile_load/4]). + suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> @@ -50,6 +53,7 @@ all() -> replace_path, load_file, load_abs, ensure_loaded, delete, purge, soft_purge, is_loaded, all_loaded, load_binary, dir_req, object_code, set_path_file, + upgrade, 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, @@ -450,6 +454,46 @@ load_binary(Config) when is_list(Config) -> code:delete(code_b_test), ok. +upgrade(Config) -> + DataDir = ?config(data_dir, Config), + + %%T = [beam, hipe], + T = [beam], + + [upgrade_do(DataDir, Client, U1, U2, O1, O2) + || Client<-T, U1<-T, U2<-T, O1<-T, O2<-T], + + ok. + +upgrade_do(DataDir, Client, U1, U2, O1, O2) -> + compile_load(upgrade_client, DataDir, undefined, Client), + upgrade_client:run(DataDir, U1, U2, O1, O2), + ok. + +compile_load(Mod, Dir, Ver, CodeType) -> + Version = case Ver of + undefined -> + io:format("Compiling '~p' as ~p\n", [Mod, CodeType]), + []; + _ -> + io:format("Compiling version ~p of '~p' as ~p\n", + [Ver, Mod, CodeType]), + [{d,list_to_atom("VERSION_" ++ integer_to_list(Ver))}] + end, + Target = case CodeType of + beam -> []; + hipe -> [native] + end, + CompOpts = [binary, report] ++ Target ++ Version, + + Src = filename:join(Dir, atom_to_list(Mod) ++ ".erl"), + %io:format("compile:file(~p,~p)\n", [Src, CompOpts]), + {ok,Mod,Code} = compile:file(Src, CompOpts), + ObjFile = filename:basename(Src,".erl") ++ ".beam", + {module,Mod} = code:load_binary(Mod, ObjFile, Code), + %IsNative = code:is_module_native(Mod), + ok. + dir_req(suite) -> []; dir_req(doc) -> []; dir_req(Config) when is_list(Config) -> @@ -535,30 +579,25 @@ sticky_compiler(File) -> pa_pz_option(suite) -> []; pa_pz_option(doc) -> ["Test that the -pa and -pz options work as expected"]; pa_pz_option(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "Slave nodes not supported on VxWorks"}; - _ -> - DDir = ?config(data_dir,Config), - PaDir = filename:join(DDir,"pa"), - PzDir = filename:join(DDir,"pz"), - ?line {ok, Node}=?t:start_node(pa_pz1, slave, - [{args, - "-pa " ++ PaDir - ++ " -pz " ++ PzDir}]), - ?line Ret=rpc:call(Node, code, get_path, []), - ?line [PaDir|Paths] = Ret, - ?line [PzDir|_] = lists:reverse(Paths), - ?t:stop_node(Node), - ?line {ok, Node2}=?t:start_node(pa_pz2, slave, - [{args, - "-mode embedded " ++ "-pa " - ++ PaDir ++ " -pz " ++ PzDir}]), - ?line Ret2=rpc:call(Node2, code, get_path, []), - ?line [PaDir|Paths2] = Ret2, - ?line [PzDir|_] = lists:reverse(Paths2), - ?t:stop_node(Node2) - end. + DDir = ?config(data_dir,Config), + PaDir = filename:join(DDir,"pa"), + PzDir = filename:join(DDir,"pz"), + {ok, Node}=?t:start_node(pa_pz1, slave, + [{args, + "-pa " ++ PaDir + ++ " -pz " ++ PzDir}]), + Ret=rpc:call(Node, code, get_path, []), + [PaDir|Paths] = Ret, + [PzDir|_] = lists:reverse(Paths), + ?t:stop_node(Node), + {ok, Node2}=?t:start_node(pa_pz2, slave, + [{args, + "-mode embedded " ++ "-pa " + ++ PaDir ++ " -pz " ++ PzDir}]), + Ret2=rpc:call(Node2, code, get_path, []), + [PaDir|Paths2] = Ret2, + [PzDir|_] = lists:reverse(Paths2), + ?t:stop_node(Node2). add_del_path(suite) -> []; @@ -645,8 +684,8 @@ ext_mod_dep(Config) when is_list(Config) -> xref:set_default(s, [{verbose,false},{warnings,false}, {builtins,true},{recurse,true}]), xref:set_library_path(s, code:get_path()), - xref:add_directory(s, filename:dirname(code:which(kernel))), - xref:add_directory(s, filename:dirname(code:which(lists))), + xref:add_directory(s, filename:join(code:lib_dir(kernel),"ebin")), + xref:add_directory(s, filename:join(code:lib_dir(stdlib),"ebin")), case catch ext_mod_dep2() of {'EXIT', Reason} -> xref:stop(s), diff --git a/lib/kernel/test/code_SUITE_data/other.erl b/lib/kernel/test/code_SUITE_data/other.erl new file mode 100644 index 0000000000..58ce87f222 --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/other.erl @@ -0,0 +1,38 @@ +-module(other). + +-ifdef(VERSION_1). +-define(VERSION,1). +-export([exp1/0]). +-export([exp1loc2/0]). +-export([exp1exp2/0]). +exp1() -> check([loc1(),exp1loc2(),exp1exp2(),loc1exp2(),loc1loc2()]). +loc1() -> check([exp1loc2(),exp1exp2(),loc1exp2(),loc1loc2()]). +exp1loc2() -> check([exp1exp2(),loc1exp2(),loc1loc2()]). +exp1exp2() -> check([loc1exp2(),loc1loc2()]). +loc1exp2() -> check([loc1loc2()]). +-endif. % VERSION_1 + +-ifdef(VERSION_2). +-define(VERSION,2). +-export([exp2/0]). +-export([loc1exp2/0]). +-export([exp1exp2/0]). +loc1exp2() -> check([exp1exp2(),exp1loc2(),loc2(),exp2(),loc1loc2()]). +exp1exp2() -> check([exp1loc2(),loc2(),exp2(),loc1loc2()]). +exp1loc2() -> check([loc2(),exp2(),loc1loc2()]). +loc2() -> check([exp2(),loc1loc2()]). +exp2() -> check([loc1loc2()]). + +-endif. % VERSION_2 + +loc1loc2() -> ?VERSION. + + +check(VerList) -> + case lists:all(fun(?VERSION) -> true; (_) -> false end, + VerList) of + true -> + ?VERSION; + false -> + VerList + end. diff --git a/lib/kernel/test/code_SUITE_data/upgrade_client.erl b/lib/kernel/test/code_SUITE_data/upgrade_client.erl new file mode 100644 index 0000000000..bb655e01d3 --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/upgrade_client.erl @@ -0,0 +1,259 @@ +-module(upgrade_client). + +-export([run/5]). + +%%-define(line, io:format("~s:~p\n", [?MODULE,?LINE]),). +-define(line,). + +run(Dir, Upgradee1, Upgradee2, Other1, Other2) -> + %% Load version 1 of upgradee + code_SUITE:compile_load(upgradee, Dir, 1, Upgradee1), + + ?line 1 = upgradee:exp1(), + ?line 1 = upgradee:exp1exp2(), + ?line 1 = upgradee:exp1loc2(), + + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:exp2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1exp2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1loc2()), + + P = spawn_link(upgradee,dispatch_loop,[]), + + ?line 1 = proxy_call(P, local, exp1), + ?line 1 = proxy_call(P, local, loc1), + ?line 1 = proxy_call(P, local, exp1exp2), + ?line 1 = proxy_call(P, local, exp1loc2), + ?line 1 = proxy_call(P, local, loc1exp2), + ?line 1 = proxy_call(P, local, loc1loc2), + ?line 1 = proxy_call(P, external, exp1), + ?line 1 = proxy_call(P, external, exp1exp2), + ?line 1 = proxy_call(P, external, exp1loc2), + + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc2), + ?line {cannot_compile,1} = proxy_call(P, local, exp2), + ?line {cannot_compile,1} = proxy_call(P, local, loc2), + + ?line {'EXIT',{undef,_}} = (catch other:exp1()), + ?line {'EXIT',{undef,_}} = (catch other:loc1()), + ?line {'EXIT',{undef,_}} = (catch other:exp1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:exp1exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc11exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc2()), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + + %% + %% Load version 1 of other + %% + code_SUITE:compile_load(other, Dir, 1, Other1), + ?line 1 = other:exp1(), + ?line 1 = other:exp1loc2(), + ?line 1 = other:exp1exp2(), + ?line {'EXIT',{undef,_}} = (catch other:loc1()), + ?line {'EXIT',{undef,_}} = (catch other:loc1exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc2()), + + ?line 1 = proxy_call(P, other, exp1), + ?line 1 = proxy_call(P, other, exp1loc2), + ?line 1 = proxy_call(P, other, exp1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + + %% + %% Load version 2 of upgradee + %% + code_SUITE:compile_load(upgradee, Dir, 2, Upgradee2), + + ?line 2 = upgradee:exp2(), + ?line 2 = upgradee:exp1exp2(), + ?line 2 = upgradee:loc1exp2(), + + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc2()), + + ?line 1 = proxy_call(P, local, exp1), + ?line 1 = proxy_call(P, local, loc1), + ?line 1 = proxy_call(P, local, exp1exp2), + ?line 1 = proxy_call(P, local, exp1loc2), + ?line 1 = proxy_call(P, local, loc1exp2), + ?line 1 = proxy_call(P, local, loc1loc2), + ?line {cannot_compile,1} = proxy_call(P, local, exp2), + ?line {cannot_compile,1} = proxy_call(P, local, loc2), + + ?line 2 = proxy_call(P, external, exp1exp2), + ?line 2 = proxy_call(P, external, loc1exp2), + ?line 2 = proxy_call(P, external, exp2), + + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc2), + + ?line 1 = other:exp1(), + ?line 1 = other:exp1loc2(), + ?line 1 = other:exp1exp2(), + ?line {'EXIT',{undef,_}} = (catch other:loc1()), + ?line {'EXIT',{undef,_}} = (catch other:loc1exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:exp2()), + ?line {'EXIT',{undef,_}} = (catch other:loc2()), + + ?line 1 = proxy_call(P, other, exp1), + ?line 1 = proxy_call(P, other, exp1loc2), + ?line 1 = proxy_call(P, other, exp1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + + %% + %% Load version 2 of other + %% + code_SUITE:compile_load(other, Dir, 2, Other2), + + ?line 2 = upgradee:exp2(), + ?line 2 = upgradee:exp1exp2(), + ?line 2 = upgradee:loc1exp2(), + + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc2()), + + ?line 1 = proxy_call(P, local, exp1), + ?line 1 = proxy_call(P, local, loc1), + ?line 1 = proxy_call(P, local, exp1exp2), + ?line 1 = proxy_call(P, local, exp1loc2), + ?line 1 = proxy_call(P, local, loc1exp2), + ?line 1 = proxy_call(P, local, loc1loc2), + ?line {cannot_compile,1} = proxy_call(P, local, exp2), + ?line {cannot_compile,1} = proxy_call(P, local, loc2), + + ?line 2 = proxy_call(P, external, exp1exp2), + ?line 2 = proxy_call(P, external, loc1exp2), + ?line 2 = proxy_call(P, external, exp2), + + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc2), + + ?line 2 = other:exp2(), + ?line 2 = other:loc1exp2(), + ?line 2 = other:exp1exp2(), + ?line {'EXIT',{undef,_}} = (catch other:exp1()), + ?line {'EXIT',{undef,_}} = (catch other:loc1()), + ?line {'EXIT',{undef,_}} = (catch other:exp1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:loc2()), + + ?line 2 = proxy_call(P, other, exp2), + ?line 2 = proxy_call(P, other, loc1exp2), + ?line 2 = proxy_call(P, other, exp1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + + + %% + %% Upgrade proxy to version 2 + %% + P ! upgrade_order, + + + %% + io:format("Delete version 2 of 'upgradee'\n",[]), + %% + code:purge(upgradee), + code:delete(upgradee), + + ?line {'EXIT',{undef,_}} = (catch upgradee:exp2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1exp2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1exp2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1()), + ?line {'EXIT',{undef,_}} = (catch upgradee:exp1loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch upgradee:loc2()), + + ?line 2 = proxy_call(P, local, exp2), + ?line 2 = proxy_call(P, local, loc2), + ?line 2 = proxy_call(P, local, exp1exp2), + ?line 2 = proxy_call(P, local, exp1loc2), + ?line 2 = proxy_call(P, local, loc1exp2), + ?line 2 = proxy_call(P, local, loc1loc2), + ?line {cannot_compile,2} = proxy_call(P, local, exp1), + ?line {cannot_compile,2} = proxy_call(P, local, loc1), + + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, exp1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, external, loc2), + + ?line 2 = other:exp2(), + ?line 2 = other:loc1exp2(), + ?line 2 = other:exp1exp2(), + ?line {'EXIT',{undef,_}} = (catch other:exp1()), + ?line {'EXIT',{undef,_}} = (catch other:loc1()), + ?line {'EXIT',{undef,_}} = (catch other:exp1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:loc1loc2()), + ?line {'EXIT',{undef,_}} = (catch other:loc2()), + + ?line 2 = proxy_call(P, other, exp2), + ?line 2 = proxy_call(P, other, loc1exp2), + ?line 2 = proxy_call(P, other, exp1exp2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, exp1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc1loc2), + ?line {'EXIT',{undef,_}} = proxy_call(P, other, loc2), + + unlink(P), + exit(P, die_please), + + io:format("Purge 'upgradee'\n",[]), + code:purge(upgradee), + + io:format("Delete and purge 'other'\n",[]), + code:purge(other), + code:delete(other), + code:purge(other), + ok. + +proxy_call(Pid, CallType, Func) -> + Pid ! {self(), CallType, Func}, + receive + {Pid, call_result, Func, Ret} -> Ret + end. diff --git a/lib/kernel/test/code_SUITE_data/upgradee.erl b/lib/kernel/test/code_SUITE_data/upgradee.erl new file mode 100644 index 0000000000..62b1d95e30 --- /dev/null +++ b/lib/kernel/test/code_SUITE_data/upgradee.erl @@ -0,0 +1,123 @@ +-module(upgradee). + +-export([dispatch_loop/0]). + +-ifdef(VERSION_1). +-define(VERSION,1). + +-export([exp1/0]). % only exported in v1 +-export([exp1loc2/0]). % exported in v1, local in v2 +-export([exp1exp2/0]). % exported in v1 and v2 + +exp1() -> ?VERSION. +loc1() -> ?VERSION. + +-endif. % VERSION_1 + +-ifdef(VERSION_2). +-define(VERSION,2). + +-export([exp2/0]). +-export([loc1exp2/0]). +-export([exp1exp2/0]). + +exp2() -> ?VERSION. +loc2() -> ?VERSION. + +-endif. % VERSION_2 + +exp1exp2() -> ?VERSION. +exp1loc2() -> ?VERSION. +loc1exp2() -> ?VERSION. +loc1loc2() -> ?VERSION. + +dispatch_loop() -> + receive + upgrade_order -> + %%erlang:display({"upgradee version", ?VERSION, "got upgrade_order"}), + ?MODULE:dispatch_loop(); + + Msg -> + %%erlang:display({"upgradee version", ?VERSION, "got msg", Msg}), + {Func,Ret} = case Msg of + %% Local calls + {Pid, local, F=exp1} -> + {F, local_exp1()}; + {Pid, local, F=loc1} -> + {F, local_loc1()}; + {Pid, local, F=exp1exp2} -> + {F, catch exp1exp2()}; + {Pid, local, F=exp1loc2} -> + {F, catch exp1loc2()}; + {Pid, local, F=loc1exp2} -> + {F, catch loc1exp2()}; + {Pid, local, F=loc1loc2} -> + {F, catch loc1loc2()}; + {Pid, local, F=exp2} -> + {F, local_exp2()}; + {Pid, local, F=loc2} -> + {F, local_loc2()}; + + %% Extern calls to own module + {Pid, external, F=exp1} -> + {F, catch ?MODULE:exp1()}; + {Pid, external, F=loc1} -> + {F, catch ?MODULE:loc1()}; + {Pid, external, F=exp1exp2} -> + {F, catch ?MODULE:exp1exp2()}; + {Pid, external, F=exp1loc2} -> + {F, catch ?MODULE:exp1loc2()}; + {Pid, external, F=loc1exp2} -> + {F, catch ?MODULE:loc1exp2()}; + {Pid, external, F=loc1loc2} -> + {F, catch ?MODULE:loc1loc2()}; + {Pid, external, F=exp2} -> + {F, catch ?MODULE:exp2()}; + {Pid, external, F=loc2} -> + {F, catch ?MODULE:loc2()}; + + %% External calls to other module + {Pid, other, F=exp1} -> + {F, catch other:exp1()}; + {Pid, other, F=loc1} -> + {F, catch other:loc1()}; + {Pid, other, F=exp1exp2} -> + {F, catch other:exp1exp2()}; + {Pid, other, F=exp1loc2} -> + {F, catch other:exp1loc2()}; + {Pid, other, F=loc1exp2} -> + {F, catch other:loc1exp2()}; + {Pid, other, F=loc1loc2} -> + {F, catch other:loc1loc2()}; + {Pid, other, F=exp2} -> + {F, catch other:exp2()}; + {Pid, other, F=loc2} -> + {F, catch other:loc2()} + end, + Pid ! {self(), call_result, Func, Ret}, + + dispatch_loop() % A local call, we don't want to upgrade the dispatcher + end. + + + +-ifdef(VERSION_1). +local_exp1() -> catch exp1(). +local_loc1() -> catch loc1(). +-else. +local_exp1() -> + %%erlang:display({"upgradee:local_exp1 in version", ?VERSION}), + {cannot_compile,?VERSION}. +local_loc1() -> {cannot_compile,?VERSION}. +-endif. + +-ifdef(VERSION_2). +local_exp2() -> catch exp2(). +local_loc2() -> catch loc2(). +-else. +local_exp2() -> + %%erlang:display({"upgradee:local_exp2 in version", ?VERSION}), + {cannot_compile,?VERSION}. +local_loc2() -> + {cannot_compile,?VERSION}. +-endif. diff --git a/lib/kernel/test/disk_log_SUITE.erl b/lib/kernel/test/disk_log_SUITE.erl index 0c3f5c3514..0f811b8f73 100644 --- a/lib/kernel/test/disk_log_SUITE.erl +++ b/lib/kernel/test/disk_log_SUITE.erl @@ -126,11 +126,6 @@ error, chunk, truncate, many_users, info, change_size, change_attribute, distribution, evil, otp_6278, otp_10131]). -%% The following two lists should be mutually exclusive. To skip a case -%% on VxWorks altogether, use the kernel.spec.vxworks file instead. -%% PLEASE don't skip out of laziness, the goal is to make every -%% testcase runnable on VxWorks. - %% These test cases should be skipped if the VxWorks card is %% configured without NFS cache. -define(SKIP_NO_CACHE,[distribution]). @@ -5126,33 +5121,8 @@ stop_node(Node) -> %% If the board is configured without NFS, the port program will fail to load %% and this will return 0, which may or may not be the wrong thing to do. -check_nfs(Config) -> - case (catch check_cache(Config)) of - N when is_integer(N) -> - N; - _ -> - 0 - end. - -check_cache(Config) -> - ?line Check = filename:join(?datadir(Config), "nfs_check"), - ?line P = open_port({spawn, Check}, [{line,100}, eof]), - ?line Size = receive - {P,{data,{eol,S}}} -> - list_to_integer(S) - after 1000 -> - erlang:display(got_timeout), - exit(timeout) - end, - ?line receive - {P, eof} -> - ok - end, - ?line P ! {self(), close}, - ?line receive - {P, closed} -> ok - end, - Size. +check_nfs(_Config) -> + 0. skip_expand([]) -> []; @@ -5175,13 +5145,8 @@ skip_list(Config) -> skip_expand(?SKIP_LARGE_CACHE) end. -should_skip(Test,Config) -> - case os:type() of - vxworks -> - lists:member(Test, skip_list(Config)); - _ -> - false - end. +should_skip(_Test,_Config) -> + false. %%----------------------------------------------------------------- %% The error_logger handler used. diff --git a/lib/kernel/test/disk_log_SUITE_data/Makefile.src b/lib/kernel/test/disk_log_SUITE_data/Makefile.src deleted file mode 100644 index cae2f23d29..0000000000 --- a/lib/kernel/test/disk_log_SUITE_data/Makefile.src +++ /dev/null @@ -1,15 +0,0 @@ -CC = @CC@ -LD = @LD@ -CFLAGS = @CFLAGS@ -I@erl_include@ @DEFS@ -CROSSLDFLAGS = @CROSSLDFLAGS@ - -PROGS = nfs_check@exe@ - -all: $(PROGS) - -nfs_check@exe@: nfs_check@obj@ - $(LD) $(CROSSLDFLAGS) -o nfs_check nfs_check@obj@ @LIBS@ - -nfs_check@obj@: nfs_check.c - $(CC) -c -o nfs_check@obj@ $(CFLAGS) nfs_check.c - diff --git a/lib/kernel/test/disk_log_SUITE_data/nfs_check.c b/lib/kernel/test/disk_log_SUITE_data/nfs_check.c deleted file mode 100644 index 31e9ba8190..0000000000 --- a/lib/kernel/test/disk_log_SUITE_data/nfs_check.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Author: Patrik Nyblom - * Purpose: A port program to check the NFS cache size on VxWorks (returns 0 - * for other platforms). - */ - -#ifdef VXWORKS -#include <vxWorks.h> -#include <taskVarLib.h> -#include <taskLib.h> -#include <sysLib.h> -#include <string.h> -#include <ioLib.h> -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> - -#ifdef VXWORKS -extern unsigned nfsCacheSize; -#define MAIN(argc, argv) nfs_check(argc, argv) -#else -#define MAIN(argc, argv) main(argc, argv) -#endif - - -MAIN(argc, argv) -int argc; -char *argv[]; -{ -#ifdef VXWORKS - char str[100]; - sprintf(str,"%d\n", nfsCacheSize); - write(1, str, strlen(str)); -#else - fprintf(stdout,"0"); - fflush(stdout); -#endif - return 0; -} - diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl index 72239641e9..35502a1d27 100644 --- a/lib/kernel/test/erl_prim_loader_SUITE.erl +++ b/lib/kernel/test/erl_prim_loader_SUITE.erl @@ -110,56 +110,46 @@ get_file(Config) when is_list(Config) -> inet_existing(doc) -> ["Start a node using the 'inet' loading method, ", "from an already started boot server."]; inet_existing(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "VxWorks: tested separately"}; - _ -> - ?line Name = erl_prim_test_inet_existing, - ?line Host = host(), - ?line Cookie = atom_to_list(erlang:get_cookie()), - ?line IpStr = ip_str(Host), - ?line LFlag = get_loader_flag(os:type()), - ?line Args = LFlag ++ " -hosts " ++ IpStr ++ - " -setcookie " ++ Cookie, - ?line {ok, BootPid} = erl_boot_server:start_link([Host]), - ?line {ok, Node} = start_node(Name, Args), - ?line {ok,[["inet"]]} = rpc:call(Node, init, get_argument, [loader]), - ?line stop_node(Node), - ?line unlink(BootPid), - ?line exit(BootPid, kill), - ok - end. + Name = erl_prim_test_inet_existing, + Host = host(), + Cookie = atom_to_list(erlang:get_cookie()), + IpStr = ip_str(Host), + LFlag = get_loader_flag(os:type()), + Args = LFlag ++ " -hosts " ++ IpStr ++ + " -setcookie " ++ Cookie, + {ok, BootPid} = erl_boot_server:start_link([Host]), + {ok, Node} = start_node(Name, Args), + {ok,[["inet"]]} = rpc:call(Node, init, get_argument, [loader]), + stop_node(Node), + unlink(BootPid), + exit(BootPid, kill), + ok. inet_coming_up(doc) -> ["Start a node using the 'inet' loading method, ", "but start the boot server afterwards."]; inet_coming_up(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "VxWorks: tested separately"}; - _ -> - ?line Name = erl_prim_test_inet_coming_up, - ?line Cookie = atom_to_list(erlang:get_cookie()), - ?line Host = host(), - ?line IpStr = ip_str(Host), - ?line LFlag = get_loader_flag(os:type()), - ?line Args = LFlag ++ - " -hosts " ++ IpStr ++ - " -setcookie " ++ Cookie, - ?line {ok, Node} = start_node(Name, Args, [{wait, false}]), - - %% Wait a while, then start boot server, and wait for node to start. - ?line test_server:sleep(test_server:seconds(6)), - io:format("erl_boot_server:start_link([~p]).", [Host]), - ?line {ok, BootPid} = erl_boot_server:start_link([Host]), - ?line wait_really_started(Node, 25), - - %% Check loader argument, then cleanup. - ?line {ok,[["inet"]]} = rpc:call(Node, init, get_argument, [loader]), - ?line stop_node(Node), - ?line unlink(BootPid), - ?line exit(BootPid, kill), - ok - end. + Name = erl_prim_test_inet_coming_up, + Cookie = atom_to_list(erlang:get_cookie()), + Host = host(), + IpStr = ip_str(Host), + LFlag = get_loader_flag(os:type()), + Args = LFlag ++ + " -hosts " ++ IpStr ++ + " -setcookie " ++ Cookie, + {ok, Node} = start_node(Name, Args, [{wait, false}]), + + %% Wait a while, then start boot server, and wait for node to start. + test_server:sleep(test_server:seconds(6)), + io:format("erl_boot_server:start_link([~p]).", [Host]), + {ok, BootPid} = erl_boot_server:start_link([Host]), + wait_really_started(Node, 25), + + %% Check loader argument, then cleanup. + {ok,[["inet"]]} = rpc:call(Node, init, get_argument, [loader]), + stop_node(Node), + unlink(BootPid), + exit(BootPid, kill), + ok. wait_really_started(Node, 0) -> test_server:fail({not_booted,Node}); @@ -249,8 +239,6 @@ multiple_slaves(doc) -> "verify that the boot server manages"]; multiple_slaves(Config) when is_list(Config) -> case os:type() of - vxworks -> - {comment, "VxWorks: tested separately"}; {ose,_} -> {comment, "OSE: multiple nodes not supported"}; _ -> diff --git a/lib/kernel/test/error_logger_warn_SUITE.erl b/lib/kernel/test/error_logger_warn_SUITE.erl index 265e1ae4c8..2bf467610e 100644 --- a/lib/kernel/test/error_logger_warn_SUITE.erl +++ b/lib/kernel/test/error_logger_warn_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2011. All Rights Reserved. +%% Copyright Ericsson AB 2003-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -310,7 +310,7 @@ nice_stop_node(Name) -> {nodedown,Name} -> ok end. -%rensa rd() f�re varje rapport-test s� man bara f�r en fil... +%clean out rd() before each report test in order to get only one file... clean_rd() -> {ok,L} = file:list_dir(rd()), lists:foreach(fun(F) -> diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 848db06e82..914f0d6127 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -84,6 +84,8 @@ -export([advise/1]). +-export([allocate/1]). + -export([standard_io/1,mini_server/1]). %% Debug exports @@ -116,7 +118,7 @@ groups() -> {files, [], [{group, open}, {group, pos}, {group, file_info}, {group, consult}, {group, eval}, {group, script}, - truncate, sync, datasync, advise]}, + truncate, sync, datasync, advise, allocate]}, {open, [], [open1, old_modes, new_modes, path_open, close, access, read_write, pread_write, append, open_errors, @@ -492,8 +494,6 @@ cur_dir_1(Config) when is_list(Config) -> ?line case os:type() of {unix, _} -> ?line {error, enotsup} = ?FILE_MODULE:get_cwd("d:"); - vxworks -> - ?line {error, enotsup} = ?FILE_MODULE:get_cwd("d:"); {win32, _} -> win_cur_dir_1(Config) end, @@ -1038,32 +1038,29 @@ file_info_basic_file(Config) when is_list(Config) -> file_info_basic_directory(suite) -> []; file_info_basic_directory(doc) -> []; file_info_basic_directory(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(5)), + Dog = test_server:timetrap(test_server:seconds(5)), %% Note: filename:join/1 removes any trailing slash, %% which is essential for ?FILE_MODULE:file_info/1 to work on %% platforms such as Windows95. - ?line RootDir = filename:join([?config(priv_dir, Config)]), + RootDir = filename:join([?config(priv_dir, Config)]), %% Test that the RootDir directory has the expected attributes. - ?line test_directory(RootDir, read_write), + test_directory(RootDir, read_write), %% Note that on Windows file systems, %% "/" or "c:/" are *NOT* directories. %% Therefore, test that ?FILE_MODULE:file_info/1 behaves as if they were %% directories. - ?line case os:type() of - {win32, _} -> - ?line test_directory("/", read_write), - ?line test_directory("c:/", read_write), - ?line test_directory("c:\\", read_write); - {unix, _} -> - ?line test_directory("/", read); - vxworks -> - %% Check is just done for owner - ?line test_directory("/", read_write) - end, - ?line test_server:timetrap_cancel(Dog). + case os:type() of + {win32, _} -> + ?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). test_directory(Name, ExpectedAccess) -> ?line {ok,#file_info{size=Size,type=Type,access=Access, @@ -1622,6 +1619,74 @@ advise(Config) when is_list(Config) -> ?line test_server:timetrap_cancel(Dog), ok. +allocate(suite) -> []; +allocate(doc) -> "Tests that ?FILE_MODULE: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) + ++"_allocate.fil"), + + Line1 = "Hello\n", + Line2 = "World!\n", + + ?line {ok, Fd} = ?FILE_MODULE:open(Allocate, [write, binary]), + allocate_and_assert(Fd, 1, iolist_size([Line1, Line2])), + ?line ok = io:format(Fd, "~s", [Line1]), + ?line ok = io:format(Fd, "~s", [Line2]), + ?line ok = ?FILE_MODULE:close(Fd), + + ?line {ok, Fd2} = ?FILE_MODULE:open(Allocate, [write, binary]), + allocate_and_assert(Fd2, 1, iolist_size(Line1)), + ?line ok = io:format(Fd2, "~s", [Line1]), + ?line ok = io:format(Fd2, "~s", [Line2]), + ?line ok = ?FILE_MODULE:close(Fd2), + + ?line {ok, Fd3} = ?FILE_MODULE:open(Allocate, [write, binary]), + allocate_and_assert(Fd3, 1, iolist_size(Line1) + 1), + ?line ok = io:format(Fd3, "~s", [Line1]), + ?line ok = io:format(Fd3, "~s", [Line2]), + ?line ok = ?FILE_MODULE:close(Fd3), + + ?line {ok, Fd4} = ?FILE_MODULE:open(Allocate, [write, binary]), + allocate_and_assert(Fd4, 1, 4 * iolist_size([Line1, Line2])), + ?line ok = io:format(Fd4, "~s", [Line1]), + ?line ok = io:format(Fd4, "~s", [Line2]), + ?line ok = ?FILE_MODULE:close(Fd4), + + ?line [] = flush(), + ?line test_server:timetrap_cancel(Dog), + ok. + +allocate_and_assert(Fd, Offset, Length) -> + % Just verify that calls to ?PRIM_FILE:allocate/3 don't crash or have + % any other negative side effect. We can't really asssert against a + % specific return value, because support for file space pre-allocation + % depends on the OS, OS version and underlying filesystem. + % + % The Linux kernel added support for fallocate() in version 2.6.23, + % which currently works only for the ext4, ocfs2, xfs and btrfs file + % systems. posix_fallocate() is available in glibc as of version + % 2.1.94, but it was buggy until glibc version 2.7. + % + % Mac OS X, as of version 10.3, supports the fcntl operation F_PREALLOCATE. + % + % Solaris supports posix_fallocate() but only for the UFS file system + % apparently (not supported for ZFS). + % + % FreeBSD 9.0 is the first FreeBSD release supporting posix_fallocate(). + % + % For Windows there's apparently no way to pre-allocate file space, at + % least with same semantics as posix_fallocate(), fallocate() and + % fcntl F_PREALLOCATE. + Result = ?FILE_MODULE:allocate(Fd, Offset, Length), + case os:type() of + {win32, _} -> + ?line {error, enotsup} = Result; + _ -> + ?line _ = Result + end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1784,9 +1849,7 @@ e_delete(Config) when is_list(Config) -> Base, #file_info {mode=8#600}); {win32, _} -> %% Remove a character device. - ?line {error, eacces} = ?FILE_MODULE:delete("nul"); - vxworks -> - ok + ?line {error, eacces} = ?FILE_MODULE:delete("nul") end, ?line [] = flush(), @@ -1801,148 +1864,133 @@ e_delete(Config) when is_list(Config) -> e_rename(suite) -> []; e_rename(doc) -> []; e_rename(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "Windriver: dosFs must be fixed first!"}; - _ -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line RootDir = ?config(priv_dir, Config), - ?line Base = filename:join(RootDir, - atom_to_list(?MODULE)++"_e_rename"), - ?line ok = ?FILE_MODULE:make_dir(Base), - - %% Create an empty directory. - ?line EmptyDir = filename:join(Base, "empty_dir"), - ?line ok = ?FILE_MODULE:make_dir(EmptyDir), - - %% Create a non-empty directory. - ?line NonEmptyDir = filename:join(Base, "non_empty_dir"), - ?line ok = ?FILE_MODULE:make_dir(NonEmptyDir), - ?line ok = ?FILE_MODULE:write_file( - filename:join(NonEmptyDir, "a_file"), - "hello\n"), - - %% Create another non-empty directory. - ?line ADirectory = filename:join(Base, "a_directory"), - ?line ok = ?FILE_MODULE:make_dir(ADirectory), - ?line ok = ?FILE_MODULE:write_file( - filename:join(ADirectory, "a_file"), - "howdy\n\n"), - - %% Create a data file. - ?line File = filename:join(Base, "just_a_file"), - ?line ok = ?FILE_MODULE:write_file(File, "anything goes\n\n"), - - %% Move an existing directory to a non-empty directory. - ?line {error, eexist} = - ?FILE_MODULE:rename(ADirectory, NonEmptyDir), - - %% Move a root directory. - ?line {error, einval} = ?FILE_MODULE:rename("/", "arne"), - - %% Move Base into Base/new_name. - ?line {error, einval} = - ?FILE_MODULE:rename(Base, filename:join(Base, "new_name")), - - %% Overwrite a directory with a file. - ?line expect({error, eexist}, %FreeBSD (?) - {error, eisdir}, - ?FILE_MODULE:rename(File, EmptyDir)), - ?line expect({error, eexist}, %FreeBSD (?) - {error, eisdir}, - ?FILE_MODULE:rename(File, NonEmptyDir)), - - %% Move a non-existing file. - ?line NonExistingFile = - filename:join(Base, "non_existing_file"), - ?line {error, enoent} = - ?FILE_MODULE:rename(NonExistingFile, NonEmptyDir), - - %% Overwrite a file with a directory. - ?line expect({error, eexist}, %FreeBSD (?) - {error, enotdir}, - ?FILE_MODULE:rename(ADirectory, File)), - - %% Move a file to another filesystem. - %% XXX - This test case is bogus. We cannot be guaranteed that - %% the source and destination are on - %% different filesystems. - %% - %% XXX - Gross hack! - ?line Comment = - case os:type() of - {unix, _} -> - OtherFs = "/tmp", - ?line NameOnOtherFs = - filename:join(OtherFs, filename:basename(File)), - ?line {ok, Com} = - case ?FILE_MODULE:rename(File, NameOnOtherFs) of - {error, exdev} -> - %% The file could be in - %% the same filesystem! - {ok, ok}; - ok -> - {ok, {comment, - "Moving between filesystems " - "suceeded, files are probably " - "in the same filesystem!"}}; - {error, eperm} -> - {ok, {comment, "SBS! You don't " - "have the permission to do " - "this test!"}}; - Else -> - Else - end, - Com; - {win32, _} -> - %% At least Windows NT can - %% successfully move a file to - %% another drive. - ok - end, - ?line [] = flush(), - ?line test_server:timetrap_cancel(Dog), - Comment - end. + Dog = test_server:timetrap(test_server:seconds(10)), + RootDir = ?config(priv_dir, Config), + Base = filename:join(RootDir, + atom_to_list(?MODULE)++"_e_rename"), + ok = ?FILE_MODULE:make_dir(Base), + + %% Create an empty directory. + EmptyDir = filename:join(Base, "empty_dir"), + ok = ?FILE_MODULE:make_dir(EmptyDir), + + %% Create a non-empty directory. + NonEmptyDir = filename:join(Base, "non_empty_dir"), + ok = ?FILE_MODULE:make_dir(NonEmptyDir), + ok = ?FILE_MODULE:write_file( + filename:join(NonEmptyDir, "a_file"), + "hello\n"), + + %% Create another non-empty directory. + ADirectory = filename:join(Base, "a_directory"), + ok = ?FILE_MODULE:make_dir(ADirectory), + ok = ?FILE_MODULE:write_file( + filename:join(ADirectory, "a_file"), + "howdy\n\n"), + + %% Create a data file. + File = filename:join(Base, "just_a_file"), + ok = ?FILE_MODULE:write_file(File, "anything goes\n\n"), + + %% Move an existing directory to a non-empty directory. + {error, eexist} = ?FILE_MODULE:rename(ADirectory, NonEmptyDir), + + %% Move a root directory. + {error, einval} = ?FILE_MODULE:rename("/", "arne"), + + %% Move Base into Base/new_name. + {error, einval} = + ?FILE_MODULE:rename(Base, filename:join(Base, "new_name")), + + %% Overwrite a directory with a file. + expect({error, eexist}, %FreeBSD (?) + {error, eisdir}, + ?FILE_MODULE:rename(File, EmptyDir)), + expect({error, eexist}, %FreeBSD (?) + {error, eisdir}, + ?FILE_MODULE:rename(File, NonEmptyDir)), + + %% Move a non-existing file. + NonExistingFile = filename:join(Base, "non_existing_file"), + {error, enoent} = ?FILE_MODULE:rename(NonExistingFile, NonEmptyDir), + + %% Overwrite a file with a directory. + expect({error, eexist}, %FreeBSD (?) + {error, enotdir}, + ?FILE_MODULE:rename(ADirectory, File)), + + %% Move a file to another filesystem. + %% XXX - This test case is bogus. We cannot be guaranteed that + %% the source and destination are on + %% different filesystems. + %% + %% XXX - Gross hack! + Comment = case os:type() of + {unix, _} -> + OtherFs = "/tmp", + NameOnOtherFs = filename:join(OtherFs, filename:basename(File)), + {ok, Com} = case ?FILE_MODULE:rename(File, NameOnOtherFs) of + {error, exdev} -> + %% The file could be in + %% the same filesystem! + {ok, ok}; + ok -> + {ok, {comment, + "Moving between filesystems " + "suceeded, files are probably " + "in the same filesystem!"}}; + {error, eperm} -> + {ok, {comment, "SBS! You don't " + "have the permission to do " + "this test!"}}; + Else -> + Else + end, + Com; + {win32, _} -> + %% At least Windows NT can + %% successfully move a file to + %% another drive. + ok + end, + [] = flush(), + test_server:timetrap_cancel(Dog), + Comment. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% e_make_dir(suite) -> []; e_make_dir(doc) -> []; e_make_dir(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line RootDir = ?config(priv_dir, Config), - ?line Base = filename:join(RootDir, - atom_to_list(?MODULE)++"_e_make_dir"), - ?line ok = ?FILE_MODULE:make_dir(Base), + Dog = test_server:timetrap(test_server:seconds(10)), + RootDir = ?config(priv_dir, Config), + Base = filename:join(RootDir, + atom_to_list(?MODULE)++"_e_make_dir"), + ok = ?FILE_MODULE:make_dir(Base), %% A component of the path does not exist. - ?line {error, enoent} = - ?FILE_MODULE:make_dir(filename:join([Base, "a", "b"])), + {error, enoent} = ?FILE_MODULE:make_dir(filename:join([Base, "a", "b"])), %% Use a path-name with a non-directory component. - ?line Afile = filename:join(Base, "a_directory"), - ?line ok = ?FILE_MODULE:write_file(Afile, "hello\n"), - ?line case ?FILE_MODULE:make_dir( - filename:join(Afile, "another_directory")) of - {error, enotdir} -> io:format("Result: enotdir"); - {error, enoent} -> io:format("Result: enoent") - end, + Afile = filename:join(Base, "a_directory"), + ok = ?FILE_MODULE:write_file(Afile, "hello\n"), + case ?FILE_MODULE:make_dir( + filename:join(Afile, "another_directory")) of + {error, enotdir} -> io:format("Result: enotdir"); + {error, enoent} -> io:format("Result: enoent") + end, %% No permission (on Unix only). case os:type() of {unix, _} -> - ?line ?FILE_MODULE:write_file_info(Base, #file_info {mode=0}), - ?line {error, eacces} = - ?FILE_MODULE:make_dir(filename:join(Base, "xxxx")), - ?line ?FILE_MODULE:write_file_info( + ?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; - vxworks -> ok end, - ?line test_server:timetrap_cancel(Dog), + test_server:timetrap_cancel(Dog), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1950,57 +1998,50 @@ e_make_dir(Config) when is_list(Config) -> e_del_dir(suite) -> []; e_del_dir(doc) -> []; e_del_dir(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line RootDir = ?config(priv_dir, Config), - ?line Base = test_server:temp_name(filename:join(RootDir, "e_del_dir")), - ?line io:format("Base: ~p", [Base]), - ?line ok = ?FILE_MODULE:make_dir(Base), + Dog = test_server:timetrap(test_server:seconds(10)), + RootDir = ?config(priv_dir, Config), + Base = test_server:temp_name(filename:join(RootDir, "e_del_dir")), + io:format("Base: ~p", [Base]), + ok = ?FILE_MODULE:make_dir(Base), %% Delete a non-existent directory. - ?line {error, enoent} = + {error, enoent} = ?FILE_MODULE:del_dir(filename:join(Base, "non_existing")), %% Use a path-name with a non-directory component. - ?line Afile = filename:join(Base, "a_directory"), - ?line ok = ?FILE_MODULE:write_file(Afile, "hello\n"), - ?line {error, E1} = - expect({error, enotdir}, {error, enoent}, - ?FILE_MODULE:del_dir( - filename:join(Afile, "another_directory"))), - ?line io:format("Result: ~p", [E1]), + Afile = filename:join(Base, "a_directory"), + ok = ?FILE_MODULE:write_file(Afile, "hello\n"), + {error, E1} = expect({error, enotdir}, {error, enoent}, + ?FILE_MODULE:del_dir( + filename:join(Afile, "another_directory"))), + io:format("Result: ~p", [E1]), %% Delete a non-empty directory. - ?line {error, E2} = - expect({error, enotempty}, {error, eexist}, {error, eacces}, + {error, E2} = expect({error, enotempty}, {error, eexist}, {error, eacces}, ?FILE_MODULE:del_dir(Base)), - ?line io:format("Result: ~p", [E2]), + io:format("Result: ~p", [E2]), %% Remove the current directory. - ?line {error, E3} = - expect({error, einval}, + {error, E3} = expect({error, einval}, {error, eperm}, % Linux and DUX {error, eacces}, {error, ebusy}, ?FILE_MODULE:del_dir(".")), - ?line io:format("Result: ~p", [E3]), + io:format("Result: ~p", [E3]), %% No permission. case os:type() of {unix, _} -> - ?line ADirectory = filename:join(Base, "no_perm"), - ?line ok = ?FILE_MODULE:make_dir(ADirectory), - ?line ?FILE_MODULE:write_file_info( - Base, #file_info {mode=0}), - ?line {error, eacces} = ?FILE_MODULE:del_dir(ADirectory), - ?line ?FILE_MODULE:write_file_info( - Base, #file_info {mode=8#600}); + 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; - vxworks -> ok end, - ?line [] = flush(), - ?line test_server:timetrap_cancel(Dog), + [] = flush(), + test_server:timetrap_cancel(Dog), ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2564,147 +2605,123 @@ delayed_write(doc) -> ["Tests the file open option {delayed_write, Size, Delay}"]; delayed_write(Config) when is_list(Config) -> - ?line Dog = ?t:timetrap(?t:seconds(20)), - %% - ?line RootDir = ?config(priv_dir, Config), - ?line File = filename:join(RootDir, - atom_to_list(?MODULE)++"_delayed_write.txt"), - ?line Data1 = "asdfghjkl", - ?line Data2 = "qwertyuio", - ?line Data3 = "zxcvbnm,.", - ?line Size = length(Data1), - ?line Size = length(Data2), - ?line Size = length(Data3), - ?line Data1Data1 = Data1++Data1, - ?line Data1Data1Data1 = Data1Data1++Data1, - ?line Data1Data1Data1Data1 = Data1Data1++Data1Data1, + Dog = ?t:timetrap(?t:seconds(20)), + + RootDir = ?config(priv_dir, Config), + File = filename:join(RootDir, + atom_to_list(?MODULE)++"_delayed_write.txt"), + Data1 = "asdfghjkl", + Data2 = "qwertyuio", + Data3 = "zxcvbnm,.", + Size = length(Data1), + Size = length(Data2), + Size = length(Data3), + Data1Data1 = Data1++Data1, + Data1Data1Data1 = Data1Data1++Data1, + Data1Data1Data1Data1 = Data1Data1++Data1Data1, %% %% Test caching and normal close of non-raw file - ?line {ok, Fd1} = + {ok, Fd1} = ?FILE_MODULE:open(File, [write, {delayed_write, Size+1, 2000}]), - ?line ok = ?FILE_MODULE:write(Fd1, Data1), - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line {ok, Fd2} = ?FILE_MODULE:open(File, [read]), - ?line case os:type() of - vxworks -> - io:format("Line ~p skipped on vxworks", [?LINE]); - _ -> - ?line eof = ?FILE_MODULE:read(Fd2, 1) - end, - ?line ok = ?FILE_MODULE:write(Fd1, Data1), % Data flush on size - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line {ok, Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 2*Size+1), - ?line ok = ?FILE_MODULE:write(Fd1, Data1), - ?line ?t:sleep(3000), % Wait until data flush on timeout - ?line {ok, Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 3*Size+1), - ?line ok = ?FILE_MODULE:write(Fd1, Data1), - ?line ok = ?FILE_MODULE:close(Fd1), % Data flush on close - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line {ok, Data1Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 4*Size+1), - ?line ok = ?FILE_MODULE:close(Fd2), + ok = ?FILE_MODULE:write(Fd1, Data1), + ?t:sleep(1000), % Just in case the file system is slow + {ok, Fd2} = ?FILE_MODULE:open(File, [read]), + eof = ?FILE_MODULE:read(Fd2, 1), + ok = ?FILE_MODULE:write(Fd1, Data1), % Data flush on size + ?t:sleep(1000), % Just in case the file system is slow + {ok, Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 2*Size+1), + ok = ?FILE_MODULE:write(Fd1, Data1), + ?t:sleep(3000), % Wait until data flush on timeout + {ok, Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 3*Size+1), + ok = ?FILE_MODULE:write(Fd1, Data1), + ok = ?FILE_MODULE:close(Fd1), % Data flush on close + ?t:sleep(1000), % Just in case the file system is slow + {ok, Data1Data1Data1Data1} = ?FILE_MODULE:pread(Fd2, bof, 4*Size+1), + ok = ?FILE_MODULE:close(Fd2), %% %% Test implicit close through exit by file owning process, %% raw file, default parameters. - ?line Parent = self(), - ?line Fun = - fun () -> - Child = self(), - Test = - fun () -> - ?line {ok, Fd} = - ?FILE_MODULE:open(File, - [raw, write, - delayed_write]), - ?line ok = ?FILE_MODULE:write(Fd, Data1), - ?line Parent ! {Child, wrote}, - ?line receive - {Parent, continue, Reason} -> - {ok, Reason} - end - end, - case (catch Test()) of - {ok, Reason} -> - exit(Reason); - Unknown -> - exit({Unknown, get(test_server_loc)}) - end - end, - ?line Child1 = spawn(Fun), - ?line Mref1 = erlang:monitor(process, Child1), - ?line receive - {Child1, wrote} -> - ok; - {'DOWN', Mref1, _, _, _} = Down1a -> - ?t:fail(Down1a) - end, - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line {ok, Fd3} = ?FILE_MODULE:open(File, [read]), - ?line case os:type() of - vxworks -> - io:format("Line ~p skipped on vxworks", [?LINE]); - _ -> - ?line eof = ?FILE_MODULE:read(Fd3, 1) - end, - ?line Child1 ! {Parent, continue, normal}, - ?line receive - {'DOWN', Mref1, process, Child1, normal} -> - ok; - {'DOWN', Mref1, _, _, _} = Down1b -> - ?t:fail(Down1b) - end, - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line {ok, Data1} = ?FILE_MODULE:pread(Fd3, bof, Size+1), - ?line ok = ?FILE_MODULE:close(Fd3), + Parent = self(), + Fun = fun() -> + Child = self(), + Test = + fun () -> + {ok, Fd} = ?FILE_MODULE:open(File, + [raw, write, delayed_write]), + ok = ?FILE_MODULE:write(Fd, Data1), + Parent ! {Child, wrote}, + receive + {Parent, continue, Reason} -> + {ok, Reason} + end + end, + case (catch Test()) of + {ok, Reason} -> exit(Reason); + Unknown -> + exit({Unknown, get(test_server_loc)}) + end + end, + Child1 = spawn(Fun), + Mref1 = erlang:monitor(process, Child1), + receive + {Child1, wrote} -> + ok; + {'DOWN', Mref1, _, _, _} = Down1a -> + ?t:fail(Down1a) + end, + ?t:sleep(1000), % Just in case the file system is slow + {ok, Fd3} = ?FILE_MODULE:open(File, [read]), + eof = ?FILE_MODULE:read(Fd3, 1), + Child1 ! {Parent, continue, normal}, + receive + {'DOWN', Mref1, process, Child1, normal} -> + ok; + {'DOWN', Mref1, _, _, _} = Down1b -> + ?t:fail(Down1b) + end, + ?t:sleep(1000), % Just in case the file system is slow + {ok, Data1} = ?FILE_MODULE:pread(Fd3, bof, Size+1), + ok = ?FILE_MODULE:close(Fd3), %% %% The same again, but this time with reason 'kill'. - ?line Child2 = spawn(Fun), - ?line Mref2 = erlang:monitor(process, Child2), - ?line receive - {Child2, wrote} -> - ok; - {'DOWN', Mref2, _, _, _} = Down2a -> - ?t:fail(Down2a) - end, - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line {ok, Fd4} = ?FILE_MODULE:open(File, [read]), - ?line case os:type() of - vxworks -> - io:format("Line ~p skipped on vxworks", [?LINE]); - _ -> - ?line eof = ?FILE_MODULE:read(Fd4, 1) - end, - ?line Child2 ! {Parent, continue, kill}, - ?line receive - {'DOWN', Mref2, process, Child2, kill} -> - ok; - {'DOWN', Mref2, _, _, _} = Down2b -> - ?t:fail(Down2b) - end, - ?line ?t:sleep(1000), % Just in case the file system is slow - ?line eof = ?FILE_MODULE:pread(Fd4, bof, 1), - ?line ok = ?FILE_MODULE:close(Fd4), + Child2 = spawn(Fun), + Mref2 = erlang:monitor(process, Child2), + receive + {Child2, wrote} -> + ok; + {'DOWN', Mref2, _, _, _} = Down2a -> + ?t:fail(Down2a) + end, + ?t:sleep(1000), % Just in case the file system is slow + {ok, Fd4} = ?FILE_MODULE:open(File, [read]), + eof = ?FILE_MODULE:read(Fd4, 1), + Child2 ! {Parent, continue, kill}, + receive + {'DOWN', Mref2, process, Child2, kill} -> + ok; + {'DOWN', Mref2, _, _, _} = Down2b -> + ?t:fail(Down2b) + end, + ?t:sleep(1000), % Just in case the file system is slow + eof = ?FILE_MODULE:pread(Fd4, bof, 1), + ok = ?FILE_MODULE:close(Fd4), %% %% Test if file position works with delayed_write - ?line {ok, Fd5} = ?FILE_MODULE:open(File, [raw, read, write, - delayed_write]), - ?line ok = ?FILE_MODULE:truncate(Fd5), - ?line ok = ?FILE_MODULE:write(Fd5, [Data1|Data2]), - ?line {ok, 0} = ?FILE_MODULE:position(Fd5, bof), - ?line ok = ?FILE_MODULE:write(Fd5, [Data3]), - ?line {ok, Data2} = ?FILE_MODULE:read(Fd5, Size+1), - ?line {ok, 0} = ?FILE_MODULE:position(Fd5, bof), - ?line Data3Data2 = Data3++Data2, - ?line {ok, Data3Data2} = ?FILE_MODULE:read(Fd5, 2*Size+1), - ?line ok = ?FILE_MODULE:close(Fd5), + {ok, Fd5} = ?FILE_MODULE:open(File, [raw, read, write, + delayed_write]), + ok = ?FILE_MODULE:truncate(Fd5), + ok = ?FILE_MODULE:write(Fd5, [Data1|Data2]), + {ok, 0} = ?FILE_MODULE:position(Fd5, bof), + ok = ?FILE_MODULE:write(Fd5, [Data3]), + {ok, Data2} = ?FILE_MODULE:read(Fd5, Size+1), + {ok, 0} = ?FILE_MODULE:position(Fd5, bof), + Data3Data2 = Data3++Data2, + {ok, Data3Data2} = ?FILE_MODULE:read(Fd5, 2*Size+1), + ok = ?FILE_MODULE:close(Fd5), %% - ?line [] = flush(), - ?line ?t:timetrap_cancel(Dog), - ?line case os:type() of - vxworks -> - {comment, "Some lines skipped on vxworks"}; - _ -> - ok - end. + [] = flush(), + ?t:timetrap_cancel(Dog), + ok. pid2name(doc) -> "Tests file:pid2name/1."; diff --git a/lib/kernel/test/file_name_SUITE.erl b/lib/kernel/test/file_name_SUITE.erl index 3aa010a708..40bde8a736 100644 --- a/lib/kernel/test/file_name_SUITE.erl +++ b/lib/kernel/test/file_name_SUITE.erl @@ -1,4 +1,5 @@ -module(file_name_SUITE). +%% -*- coding: utf-8 -*- %% %% %CopyrightBegin% %% @@ -336,7 +337,7 @@ check_normal(Mod) -> check_icky(Mod) -> {ok,Dir} = Mod:get_cwd(), try - ?line true=(length("���") =:= 3), + ?line true=(length("åäö") =:= 3), ?line UniMode = file:native_name_encoding() =/= latin1, ?line make_icky_dir(Mod), ?line {ok, L0} = Mod:list_dir("."), @@ -357,42 +358,42 @@ check_icky(Mod) -> || {T,S,Targ} <- icky_dir(), T =:= symlink ], ?line [ {ok, Cont} = Mod:read_file(SymL) || {SymL,_,Cont} <- Syms ], ?line [ {ok, Targ} = fixlink(Mod:read_link(SymL)) || {SymL,Targ,_} <- Syms ], - ?line chk_cre_dir(Mod,[{directory,"���_dir",icky_dir()}]), + ?line chk_cre_dir(Mod,[{directory,"åäö_dir",icky_dir()}]), ?line {ok,BeginAt} = Mod:get_cwd(), ?line true = is_list(BeginAt), - ?line {error,enoent} = Mod:set_cwd("��_dir"), - ?line ok = Mod:set_cwd("���_dir"), + ?line {error,enoent} = Mod:set_cwd("åä_dir"), + ?line ok = Mod:set_cwd("åäö_dir"), ?line {ok, NowAt} = Mod:get_cwd(), ?line true = is_list(NowAt), ?line true = BeginAt =/= NowAt, ?line ok = Mod:set_cwd(".."), ?line {ok,BeginAt} = Mod:get_cwd(), - ?line rm_r2(Mod,"���_dir"), + ?line rm_r2(Mod,"åäö_dir"), {OS,TYPE} = os:type(), % Check that treat_icky really converts to the same as the OS case UniMode of true -> - ?line chk_cre_dir(Mod,[{directory,"���_dir",[]}]), - ?line ok = Mod:set_cwd("���_dir"), - ?line ok = Mod:write_file(<<"���">>,<<"hello">>), - ?line Treated = treat_icky(<<"���">>), + ?line chk_cre_dir(Mod,[{directory,"åäö_dir",[]}]), + ?line ok = Mod:set_cwd("åäö_dir"), + ?line ok = Mod:write_file(<<"ååå">>,<<"hello">>), + ?line Treated = treat_icky(<<"ååå">>), ?line {ok,[Treated]} = Mod:list_dir("."), - ?line ok = Mod:delete(<<"���">>), + ?line ok = Mod:delete(<<"ååå">>), ?line {ok,[]} = Mod:list_dir("."), ?line ok = Mod:set_cwd(".."), - ?line rm_r2(Mod,"���_dir"); + ?line rm_r2(Mod,"åäö_dir"); false -> ok end, - ?line chk_cre_dir(Mod,[{directory,treat_icky(<<"���_dir">>),icky_dir()}]), + ?line chk_cre_dir(Mod,[{directory,treat_icky(<<"åäö_dir">>),icky_dir()}]), if UniMode and (OS =/= win32) -> - ?line {error,enoent} = Mod:set_cwd("���_dir"); + ?line {error,enoent} = Mod:set_cwd("åäö_dir"); true -> ok end, - ?line ok = Mod:set_cwd(treat_icky(<<"���_dir">>)), + ?line ok = Mod:set_cwd(treat_icky(<<"åäö_dir">>)), ?line {ok, NowAt2} = Mod:get_cwd(), io:format("~p~n",[NowAt2]), % Cannot create raw unicode-breaking filenames on windows or macos @@ -400,22 +401,22 @@ check_icky(Mod) -> ?line true = BeginAt =/= NowAt2, ?line ok = Mod:set_cwd(".."), ?line {ok,BeginAt} = Mod:get_cwd(), - ?line rm_r2(Mod,conv(treat_icky(<<"���_dir">>))), + ?line rm_r2(Mod,conv(treat_icky(<<"åäö_dir">>))), case has_links() of true -> - ?line ok = Mod:make_link("fil1","nisse�"), - ?line {ok, <<"fil1">>} = Mod:read_file("nisse�"), - ?line {ok, #file_info{type = regular}} = Mod:read_link_info("nisse�"), - ?line ok = Mod:delete("nisse�"), - ?line ok = Mod:make_link("fil1",treat_icky(<<"nisse�">>)), - ?line {ok, <<"fil1">>} = Mod:read_file(treat_icky(<<"nisse�">>)), - ?line {ok, #file_info{type = regular}} = Mod:read_link_info(treat_icky(<<"nisse�">>)), - ?line ok = Mod:delete(treat_icky(<<"nisse�">>)), + ?line ok = Mod:make_link("fil1","nisseö"), + ?line {ok, <<"fil1">>} = Mod:read_file("nisseö"), + ?line {ok, #file_info{type = regular}} = Mod:read_link_info("nisseö"), + ?line ok = Mod:delete("nisseö"), + ?line ok = Mod:make_link("fil1",treat_icky(<<"nisseö">>)), + ?line {ok, <<"fil1">>} = Mod:read_file(treat_icky(<<"nisseö">>)), + ?line {ok, #file_info{type = regular}} = Mod:read_link_info(treat_icky(<<"nisseö">>)), + ?line ok = Mod:delete(treat_icky(<<"nisseö">>)), ?line {ok, <<"fil1">>} = Mod:read_file("fil1"), - ?line {error,enoent} = Mod:read_file("nisse�"), - ?line {error,enoent} = Mod:read_link_info("nisse�"), - ?line {error,enoent} = Mod:read_file(treat_icky(<<"nisse�">>)), - ?line {error,enoent} = Mod:read_link_info(treat_icky(<<"nisse�">>)); + ?line {error,enoent} = Mod:read_file("nisseö"), + ?line {error,enoent} = Mod:read_link_info("nisseö"), + ?line {error,enoent} = Mod:read_file(treat_icky(<<"nisseö">>)), + ?line {error,enoent} = Mod:read_link_info(treat_icky(<<"nisseö">>)); false -> ok end, @@ -430,42 +431,42 @@ check_icky(Mod) -> ?line {ok, BC} = Mod:read(FD,1024), ?line ok = file:close(FD) end || {regular,Name,Content} <- icky_dir() ], - ?line Mod:rename("���2","���_fil1"), - ?line {ok, <<"���2">>} = Mod:read_file("���_fil1"), - ?line {error,enoent} = Mod:read_file("���2"), - ?line Mod:rename("���_fil1","���2"), - ?line {ok, <<"���2">>} = Mod:read_file("���2"), - ?line {error,enoent} = Mod:read_file("���_fil1"), + ?line Mod:rename("åäö2","åäö_fil1"), + ?line {ok, <<"åäö2">>} = Mod:read_file("åäö_fil1"), + ?line {error,enoent} = Mod:read_file("åäö2"), + ?line Mod:rename("åäö_fil1","åäö2"), + ?line {ok, <<"åäö2">>} = Mod:read_file("åäö2"), + ?line {error,enoent} = Mod:read_file("åäö_fil1"), - ?line Mod:rename("���2",treat_icky(<<"���_fil1">>)), - ?line {ok, <<"���2">>} = Mod:read_file(treat_icky(<<"���_fil1">>)), + ?line Mod:rename("åäö2",treat_icky(<<"åäö_fil1">>)), + ?line {ok, <<"åäö2">>} = Mod:read_file(treat_icky(<<"åäö_fil1">>)), if UniMode and (OS =/= win32) -> - {error,enoent} = Mod:read_file("���_fil1"); + {error,enoent} = Mod:read_file("åäö_fil1"); true -> ok end, - ?line {error,enoent} = Mod:read_file("���2"), - ?line Mod:rename(treat_icky(<<"���_fil1">>),"���2"), - ?line {ok, <<"���2">>} = Mod:read_file("���2"), - ?line {error,enoent} = Mod:read_file("���_fil1"), - ?line {error,enoent} = Mod:read_file(treat_icky(<<"���_fil1">>)), + ?line {error,enoent} = Mod:read_file("åäö2"), + ?line Mod:rename(treat_icky(<<"åäö_fil1">>),"åäö2"), + ?line {ok, <<"åäö2">>} = Mod:read_file("åäö2"), + ?line {error,enoent} = Mod:read_file("åäö_fil1"), + ?line {error,enoent} = Mod:read_file(treat_icky(<<"åäö_fil1">>)), - ?line {ok,FI} = Mod:read_file_info("���2"), + ?line {ok,FI} = Mod:read_file_info("åäö2"), ?line NewMode = FI#file_info.mode band (bnot 8#333), ?line NewMode2 = NewMode bor 8#222, ?line true = NewMode2 =/= NewMode, - ?line ok = Mod:write_file_info("���2",FI#file_info{mode = NewMode}), - ?line {ok,#file_info{mode = NewMode}} = Mod:read_file_info("���2"), - ?line ok = Mod:write_file_info("���2",FI#file_info{mode = NewMode2}), - ?line {ok,#file_info{mode = NewMode2}} = Mod:read_file_info("���2"), + ?line ok = Mod:write_file_info("åäö2",FI#file_info{mode = NewMode}), + ?line {ok,#file_info{mode = NewMode}} = Mod:read_file_info("åäö2"), + ?line ok = Mod:write_file_info("åäö2",FI#file_info{mode = NewMode2}), + ?line {ok,#file_info{mode = NewMode2}} = Mod:read_file_info("åäö2"), - ?line {ok,FII} = Mod:read_file_info(treat_icky(<<"���5">>)), + ?line {ok,FII} = Mod:read_file_info(treat_icky(<<"åäö5">>)), ?line true = NewMode2 =/= NewMode, - ?line ok = Mod:write_file_info(treat_icky(<<"���5">>),FII#file_info{mode = NewMode}), - ?line {ok,#file_info{mode = NewMode}} = Mod:read_file_info(treat_icky(<<"���5">>)), - ?line ok = Mod:write_file_info(<<"���5">>,FII#file_info{mode = NewMode2}), - ?line {ok,#file_info{mode = NewMode2}} = Mod:read_file_info(treat_icky(<<"���5">>)), + ?line ok = Mod:write_file_info(treat_icky(<<"åäö5">>),FII#file_info{mode = NewMode}), + ?line {ok,#file_info{mode = NewMode}} = Mod:read_file_info(treat_icky(<<"åäö5">>)), + ?line ok = Mod:write_file_info(<<"åäö5">>,FII#file_info{mode = NewMode2}), + ?line {ok,#file_info{mode = NewMode2}} = Mod:read_file_info(treat_icky(<<"åäö5">>)), ok after Mod:set_cwd(Dir), @@ -475,7 +476,7 @@ check_icky(Mod) -> check_very_icky(Mod) -> {ok,Dir} = Mod:get_cwd(), try - ?line true=(length("���") =:= 3), + ?line true=(length("åäö") =:= 3), ?line UniMode = file:native_name_encoding() =/= latin1, if not UniMode -> @@ -497,7 +498,7 @@ check_very_icky(Mod) -> ?line chk_cre_dir(Mod,[{directory,[1088,1079,1091]++"_dir",very_icky_dir()}]), ?line {ok,BeginAt} = Mod:get_cwd(), ?line true = is_list(BeginAt), - ?line {error,enoent} = Mod:set_cwd("��_dir"), + ?line {error,enoent} = Mod:set_cwd("åä_dir"), ?line ok = Mod:set_cwd([1088,1079,1091]++"_dir"), ?line {ok, NowAt} = Mod:get_cwd(), ?line true = is_list(NowAt), @@ -514,16 +515,16 @@ check_very_icky(Mod) -> ?line {ok, #file_info{type = regular}} = Mod:read_link_info("nisse"++[1088,1079,1091]), ?line ok = Mod:delete("nisse"++[1088,1079,1091]), - ?line ok = Mod:make_link("fil1",<<"nisse�">>), - ?line {ok, <<"fil1">>} = Mod:read_file(<<"nisse�">>), + ?line ok = Mod:make_link("fil1",<<"nisseö">>), + ?line {ok, <<"fil1">>} = Mod:read_file(<<"nisseö">>), ?line {ok, #file_info{type = regular}} = - Mod:read_link_info(<<"nisse�">>), - ?line ok = Mod:delete(<<"nisse�">>), + Mod:read_link_info(<<"nisseö">>), + ?line ok = Mod:delete(<<"nisseö">>), ?line {ok, <<"fil1">>} = Mod:read_file("fil1"), ?line {error,enoent} = Mod:read_file("nisse"++[1088,1079,1091]), ?line {error,enoent} = Mod:read_link_info("nisse"++[1088,1079,1091]), - ?line {error,enoent} = Mod:read_file(<<"nisse�">>), - ?line {error,enoent} = Mod:read_link_info(<<"nisse�">>); + ?line {error,enoent} = Mod:read_file(<<"nisseö">>), + ?line {error,enoent} = Mod:read_link_info(<<"nisseö">>); false -> ok end, @@ -540,10 +541,10 @@ check_very_icky(Mod) -> end || {regular,Name,Content} <- very_icky_dir() ], ?line Mod:rename([956,965,963,954,959,49], [956,965,963,954,959]++"_fil1"), - ?line {ok, <<"���2">>} = Mod:read_file([956,965,963,954,959]++"_fil1"), + ?line {ok, <<"åäö2">>} = Mod:read_file([956,965,963,954,959]++"_fil1"), ?line {error,enoent} = Mod:read_file([956,965,963,954,959,49]), ?line Mod:rename([956,965,963,954,959]++"_fil1",[956,965,963,954,959,49]), - ?line {ok, <<"���2">>} = Mod:read_file([956,965,963,954,959,49]), + ?line {ok, <<"åäö2">>} = Mod:read_file([956,965,963,954,959,49]), ?line {error,enoent} = Mod:read_file([956,965,963,954,959]++"_fil1"), ?line {ok,FI} = Mod:read_file_info([956,965,963,954,959,49]), @@ -574,9 +575,9 @@ check_very_icky(Mod) -> end, ?line {NumOK,NumNOK} = filelib:fold_files(".",".*",true,fun(_F,{N,M}) when is_list(_F) -> io:format("~ts~n",[_F]),{N+1,M}; (_F,{N,M}) -> io:format("~p~n",[_F]),{N,M+1} end,{0,0}), ?line ok = filelib:fold_files(".",[1076,1089,1072,124,46,42],true,fun(_F,_) -> ok end,false), - ?line SF3 = unicode:characters_to_binary("���subfil3", + ?line SF3 = unicode:characters_to_binary("åäösubfil3", file:native_name_encoding()), - ?line SF2 = case treat_icky(<<"���subfil2">>) of + ?line SF2 = case treat_icky(<<"åäösubfil2">>) of LF2 when is_list(LF2) -> unicode:characters_to_binary(LF2, file:native_name_encoding()); @@ -584,7 +585,7 @@ check_very_icky(Mod) -> BF2 end, ?line Sorted = lists:sort([SF3,SF2]), - ?line Sorted = lists:sort(filelib:wildcard("*",<<"���subdir2">>)), + ?line Sorted = lists:sort(filelib:wildcard("*",<<"åäösubdir2">>)), ok catch throw:need_unicode_mode -> @@ -744,26 +745,26 @@ hopeless_darwin() -> icky_dir() -> [{regular,"fil1","fil1"}, - {regular,"���2","���2"}] ++ + {regular,"åäö2","åäö2"}] ++ case has_links() of true -> - [{regular,"���3","���2"}, - {symlink,"���4","���2"}]; + [{regular,"åäö3","åäö2"}, + {symlink,"åäö4","åäö2"}]; false -> [] end ++ - [{regular,treat_icky(<<"���5">>),"���5"}] ++ + [{regular,treat_icky(<<"åäö5">>),"åäö5"}] ++ case has_links() of true -> - [{symlink,treat_icky(<<"���6">>),treat_icky(<<"���5">>)}]; + [{symlink,treat_icky(<<"åäö6">>),treat_icky(<<"åäö5">>)}]; false -> [] end ++ - [{directory,treat_icky(<<"���subdir2">>), - [{regular,treat_icky(<<"���subfil2">>),"���subfil12"}, - {regular,"���subfil3","���subfil13"}]}, - {directory,"���subdir", - [{regular,"���subfil1","���subfil1"}]}]. + [{directory,treat_icky(<<"åäösubdir2">>), + [{regular,treat_icky(<<"åäösubfil2">>),"åäösubfil12"}, + {regular,"åäösubfil3","åäösubfil13"}]}, + {directory,"åäösubdir", + [{regular,"åäösubfil1","åäösubfil1"}]}]. make_very_icky_dir(Mod) -> rm_rf(Mod,"very_icky_dir"), @@ -774,26 +775,26 @@ make_very_icky_dir(Mod) -> very_icky_dir() -> [{regular,"fil1","fil1"}, - {regular,[956,965,963,954,959,49],"���2"}] ++ + {regular,[956,965,963,954,959,49],"åäö2"}] ++ case has_links() of true -> - [{regular,[956,965,963,954,959,50],"���2"}, + [{regular,[956,965,963,954,959,50],"åäö2"}, {symlink,[956,965,963,954,959,51],[956,965,963,954,959,49]}]; false -> [] end ++ - [{regular,treat_icky(<<"���5">>),"���5"}] ++ + [{regular,treat_icky(<<"åäö5">>),"åäö5"}] ++ case has_links() of true -> - [{symlink,treat_icky(<<"���6">>),treat_icky(<<"���5">>)}]; + [{symlink,treat_icky(<<"åäö6">>),treat_icky(<<"åäö5">>)}]; false -> [] end ++ - [{directory,treat_icky(<<"���subdir2">>), - [{regular,treat_icky(<<"���subfil2">>),"���subfil12"}, - {regular,"���subfil3","���subfil13"}]}, + [{directory,treat_icky(<<"åäösubdir2">>), + [{regular,treat_icky(<<"åäösubfil2">>),"åäösubfil12"}, + {regular,"åäösubfil3","åäösubfil13"}]}, {directory,[956,965,963,954,959]++"subdir1", - [{regular,[956,965,963,954,959]++"subfil1","���subfil1"}]}]. + [{regular,[956,965,963,954,959]++"subfil1","åäösubfil1"}]}]. %% Some OS'es simply do not allow non UTF8 filenames treat_icky(Bin) -> diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index bcc2f0b840..2a886b2efc 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -31,22 +31,24 @@ [basic/1, api_open_close/1,api_listen/1,api_connect_init/1,api_opts/1, xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1, - basic_stream/1, xfer_stream_min/1, peeloff/1, buffers/1, open_multihoming_ipv4_socket/1, open_unihoming_ipv6_socket/1, open_multihoming_ipv6_socket/1, - open_multihoming_ipv4_and_ipv6_socket/1]). + open_multihoming_ipv4_and_ipv6_socket/1, + basic_stream/1, xfer_stream_min/1, peeloff_active_once/1, + peeloff_active_true/1, buffers/1]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [basic, api_open_close, api_listen, api_connect_init, api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6, - basic_stream, xfer_stream_min, peeloff, buffers, open_multihoming_ipv4_socket, open_unihoming_ipv6_socket, open_multihoming_ipv6_socket, - open_multihoming_ipv4_and_ipv6_socket]. + open_multihoming_ipv4_and_ipv6_socket, + basic_stream, xfer_stream_min, peeloff_active_once, + peeloff_active_true, buffers]. groups() -> []. @@ -923,23 +925,34 @@ do_from_other_process(Fun) -> end. +peeloff_active_once(doc) -> + "Peel off an SCTP stream socket ({active,once})"; +peeloff_active_once(suite) -> + []; + +peeloff_active_once(Config) -> + peeloff(Config, [{active,once}]). -peeloff(doc) -> - "Peel off an SCTP stream socket"; -peeloff(suite) -> +peeloff_active_true(doc) -> + "Peel off an SCTP stream socket ({active,true})"; +peeloff_active_true(suite) -> []; -peeloff(Config) when is_list(Config) -> + +peeloff_active_true(Config) -> + peeloff(Config, [{active,true}]). + +peeloff(Config, SockOpts) when is_list(Config) -> ?line Addr = {127,0,0,1}, ?line Stream = 0, ?line Timeout = 333, - ?line S1 = socket_open([{ifaddr,Addr}], Timeout), + ?line S1 = socket_open([{ifaddr,Addr}|SockOpts], Timeout), ?line ?LOGVAR(S1), ?line P1 = socket_call(S1, get_port), ?line ?LOGVAR(P1), ?line Socket1 = socket_call(S1, get_socket), ?line ?LOGVAR(Socket1), ?line socket_call(S1, {listen,true}), - ?line S2 = socket_open([{ifaddr,Addr}], Timeout), + ?line S2 = socket_open([{ifaddr,Addr}|SockOpts], Timeout), ?line ?LOGVAR(S2), ?line P2 = socket_call(S2, get_port), ?line ?LOGVAR(P2), @@ -983,7 +996,7 @@ peeloff(Config) when is_list(Config) -> socket_bailout([S1,S2]) end, %% - ?line S3 = socket_peeloff(Socket1, S1Ai, Timeout), + ?line S3 = socket_peeloff(Socket1, S1Ai, SockOpts, Timeout), ?line ?LOGVAR(S3), ?line P3_X = socket_call(S3, get_port), ?line ?LOGVAR(P3_X), @@ -1302,8 +1315,15 @@ recv_comm_up_eventually(S) -> %%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% socket gen_server ultra light -socket_open(SocketOpts, Timeout) -> - Opts = [{type,seqpacket},{active,once},binary|SocketOpts], +socket_open(SockOpts0, Timeout) -> + SockOpts = + case lists:keyfind(active,1,SockOpts0) of + false -> + [{active,once}|SockOpts0]; + _ -> + SockOpts0 + end, + Opts = [{type,seqpacket},binary|SockOpts], Starter = fun () -> {ok,Socket} = @@ -1312,8 +1332,8 @@ socket_open(SocketOpts, Timeout) -> end, s_start(Starter, Timeout). -socket_peeloff(Socket, AssocId, Timeout) -> - Opts = [{active,once},binary], +socket_peeloff(Socket, AssocId, SocketOpts, Timeout) -> + Opts = [binary|SocketOpts], Starter = fun () -> {ok,NewSocket} = diff --git a/lib/kernel/test/gen_tcp_echo_SUITE.erl b/lib/kernel/test/gen_tcp_echo_SUITE.erl index 5bbaeb02ad..94f95798a0 100644 --- a/lib/kernel/test/gen_tcp_echo_SUITE.erl +++ b/lib/kernel/test/gen_tcp_echo_SUITE.erl @@ -190,24 +190,19 @@ echo_test_1(SockOpts, EchoFun, Config0) -> ok. echo_packet(SockOpts, EchoFun, Opts) -> - ?line Type = - case lists:keysearch(type, 1, Opts) of - {value, {type, T}} -> - T; - _ -> - {value, {packet, T}} = lists:keysearch(packet, 1, SockOpts), - T - end, + Type = case lists:keysearch(type, 1, Opts) of + {value, {type, T}} -> + T; + _ -> + {value, {packet, T}} = lists:keysearch(packet, 1, SockOpts), + T + end, %% Connect to the echo server. - ?line EchoPort = ?config(echo_port, Opts), - ?line {ok, Echo} = gen_tcp:connect(localhost, EchoPort, SockOpts), + EchoPort = ?config(echo_port, Opts), + {ok, Echo} = gen_tcp:connect(localhost, EchoPort, SockOpts), - ?line SlowEcho = - case os:type() of - vxworks -> true; - _ -> lists:member(slow_echo, Opts) - end, + SlowEcho = lists:member(slow_echo, Opts), case Type of http -> diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 1592399996..5d45b91ee5 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -340,39 +340,23 @@ no_accept(doc) -> "a tcp_closed message."]; no_accept(suite) -> []; no_accept(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skip,"Too tough for vxworks"}; - _ -> - no_accept2() + {ok, L} = gen_tcp:listen(0, []), + {ok, {_, Port}} = inet:sockname(L), + {ok, Client} = gen_tcp:connect(localhost, Port, []), + ok = gen_tcp:close(L), + receive + {tcp_closed, Client} -> + ok + after 5000 -> + ?line test_server:fail(never_closed) + end. -no_accept2() -> - ?line {ok, L} = gen_tcp:listen(0, []), - ?line {ok, {_, Port}} = inet:sockname(L), - ?line {ok, Client} = gen_tcp:connect(localhost, Port, []), - ?line ok = gen_tcp:close(L), - ?line receive - {tcp_closed, Client} -> - ok - after 5000 -> - ?line test_server:fail(never_closed) - - end. - close_with_pending_output(doc) -> ["Send several packets to a socket and close it. All packets should arrive ", "to the other end."]; close_with_pending_output(suite) -> []; close_with_pending_output(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skipped,"Too tough for vxworks"}; - _ -> - close_with_pending_output2() - end. - -close_with_pending_output2() -> ?line {ok, L} = gen_tcp:listen(0, [binary, {active, false}]), ?line {ok, {_, Port}} = inet:sockname(L), ?line Packets = 16, @@ -423,22 +407,16 @@ otp_3924(doc) -> otp_3924(suite) -> []; otp_3924(Config) when is_list(Config) -> MaxDelay = (case has_superfluous_schedulers() of - true -> 4; - false -> 1 - end - * case {erlang:system_info(debug_compiled), - erlang:system_info(lock_checking)} of - {true, _} -> 6; - {_, true} -> 2; - _ -> 1 - end * ?OTP_3924_MAX_DELAY), - case os:type() of - vxworks -> -%% {skip,"Too tough for vxworks"}; - otp_3924_1(MaxDelay); - _ -> - otp_3924_1(MaxDelay) - end. + true -> 4; + false -> 1 + end + * case {erlang:system_info(debug_compiled), + erlang:system_info(lock_checking)} of + {true, _} -> 6; + {_, true} -> 2; + _ -> 1 + end * ?OTP_3924_MAX_DELAY), + otp_3924_1(MaxDelay). otp_3924_1(MaxDelay) -> Dog = test_server:timetrap(test_server:seconds(240)), @@ -559,26 +537,18 @@ otp_3924_sender(Receiver, Host, Port, Data) -> data_before_close(doc) -> ["Tests that a huge amount of data can be received before a close."]; data_before_close(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skip,"Too tough for vxworks"}; - _ -> - data_before_close2() - end. - -data_before_close2() -> - ?line {ok, L} = gen_tcp:listen(0, [binary]), - ?line {ok, {_, TcpPort}} = inet:sockname(L), - ?line Bytes = 256*1024, - ?line spawn_link(fun() -> huge_sender(TcpPort, Bytes) end), - ?line {ok, A} = gen_tcp:accept(L), - ?line case count_bytes_recv(A, 0) of - {Bytes, Result} -> - io:format("Result: ~p", [Result]); - {Wrong, Result} -> - io:format("Result: ~p", [Result]), - test_server:fail({wrong_count, Wrong}) - end, + {ok, L} = gen_tcp:listen(0, [binary]), + {ok, {_, TcpPort}} = inet:sockname(L), + Bytes = 256*1024, + spawn_link(fun() -> huge_sender(TcpPort, Bytes) end), + {ok, A} = gen_tcp:accept(L), + case count_bytes_recv(A, 0) of + {Bytes, Result} -> + io:format("Result: ~p", [Result]); + {Wrong, Result} -> + io:format("Result: ~p", [Result]), + test_server:fail({wrong_count, Wrong}) + end, ok. count_bytes_recv(Sock, Total) -> @@ -611,32 +581,18 @@ get_status(Config) when is_list(Config) -> ?line {ok,{socket,Pid,_,_}} = gen_tcp:listen(5678,[]), ?line {status,Pid,_,_} = sys:get_status(Pid). +-define(RECOVER_SLEEP, 60000). +-define(RETRY_SLEEP, 15000). + iter_max_socks(doc) -> ["Open as many sockets as possible. Do this several times and check ", "that we get the same number of sockets every time."]; iter_max_socks(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {skip,"Too tough for vxworks"}; - _ -> - iter_max_socks2() - end. - --define(RECOVER_SLEEP, 60000). --define(RETRY_SLEEP, 15000). - -iter_max_socks2() -> - ?line N = - case os:type() of - vxworks -> - 10; - _ -> - 20 - end, + N = 20, L = do_iter_max_socks(N, initalize), - ?line io:format("Result: ~p",[L]), - ?line all_equal(L), - ?line {comment, "Max sockets: " ++ integer_to_list(hd(L))}. + io:format("Result: ~p",[L]), + all_equal(L), + {comment, "Max sockets: " ++ integer_to_list(hd(L))}. do_iter_max_socks(0, _) -> []; diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index 2354f8accd..cd768813cf 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -1,7 +1,8 @@ +%% -*- coding: utf-8 -*- %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. +%% Copyright Ericsson AB 1998-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -442,7 +443,7 @@ open_fd(suite) -> open_fd(doc) -> ["Test that the 'fd' option works"]; open_fd(Config) when is_list(Config) -> - Msg = "Det g�r ont n�r knoppar brista. Varf�r skulle annars v�ren tveka?", + Msg = "Det gör ont när knoppar brista. Varför skulle annars våren tveka?", Addr = {127,0,0,1}, {ok,S1} = gen_udp:open(0), {ok,P2} = inet:port(S1), diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl index 6eb2134644..b40c50f79f 100644 --- a/lib/kernel/test/global_SUITE.erl +++ b/lib/kernel/test/global_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -3821,7 +3821,7 @@ start_node_rel(Name0, Rel, Config) -> Name = node_name(Name0, Config), {Release, Compat} = case Rel of this -> - {[this], "+R8"}; + {[this], ""}; Rel when is_atom(Rel) -> {[{release, atom_to_list(Rel)}], ""}; RelList -> diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl index e64d2914c4..320b23bea1 100644 --- a/lib/kernel/test/heart_SUITE.erl +++ b/lib/kernel/test/heart_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2011. All Rights Reserved. +%% Copyright Ericsson AB 1996-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -83,10 +83,10 @@ init_per_suite(Config) when is_list(Config) -> {win32, windows} -> {skipped, "No use to run on Windows 95/98"}; _ -> - Config + ignore_cores:init(Config) end. end_per_suite(Config) when is_list(Config) -> - Config. + ignore_cores:fini(Config). start_check(Type, Name) -> @@ -188,8 +188,20 @@ reboot(Config) when is_list(Config) -> %% Check that a node is up and running after a crash. %% This test exhausts the atom table on the remote node. %% ERL_CRASH_DUMP_SECONDS=0 will force beam not to dump an erl_crash.dump. +%% May currently dump core in beam debug build due to lock-order violation +%% This should be removed when a non-lockad information retriever is implemented +%% for crash dumps node_start_immediately_after_crash(suite) -> {req, [{time, 10}]}; node_start_immediately_after_crash(Config) when is_list(Config) -> + Config2 = ignore_cores:setup(?MODULE, node_start_immediately_after_crash, Config, true), + try + node_start_immediately_after_crash_test(Config2) + after + ignore_cores:restore(Config2) + end. + + +node_start_immediately_after_crash_test(Config) when is_list(Config) -> {ok, Node} = start_check(loose, heart_test_imm, [{"ERL_CRASH_DUMP_SECONDS", "0"}]), ok = rpc:call(Node, heart, set_cmd, @@ -228,8 +240,19 @@ node_start_immediately_after_crash(Config) when is_list(Config) -> %% This test exhausts the atom table on the remote node. %% ERL_CRASH_DUMP_SECONDS=10 will force beam %% to only dump an erl_crash.dump for 10 seconds. +%% May currently dump core in beam debug build due to lock-order violation +%% This should be removed when a non-lockad information retriever is implemented +%% for crash dumps node_start_soon_after_crash(suite) -> {req, [{time, 10}]}; node_start_soon_after_crash(Config) when is_list(Config) -> + Config2 = ignore_cores:setup(?MODULE, node_start_soon_after_crash, Config, true), + try + node_start_soon_after_crash_test(Config2) + after + ignore_cores:restore(Config2) + end. + +node_start_soon_after_crash_test(Config) when is_list(Config) -> {ok, Node} = start_check(loose, heart_test_soon, [{"ERL_CRASH_DUMP_SECONDS", "10"}]), ok = rpc:call(Node, heart, set_cmd, @@ -345,13 +368,8 @@ dont_drop(doc) -> "set just before halt on very high I/O load."]; dont_drop(Config) when is_list(Config) -> %%% Have to do it some times to make it happen... - case os:type() of - vxworks -> - {comment, "No use to run with slaves on other nodes..."}; - _ -> - [ok,ok,ok,ok,ok,ok,ok,ok,ok,ok] = do_dont_drop(Config,10), - ok - end. + [ok,ok,ok,ok,ok,ok,ok,ok,ok,ok] = do_dont_drop(Config,10), + ok. do_dont_drop(_,0) -> []; do_dont_drop(Config,N) -> @@ -408,13 +426,7 @@ kill_pid(doc) -> ["Tests that heart kills the old erlang node before executing ", "heart command."]; kill_pid(Config) when is_list(Config) -> - %%% Have to do it some times to make it happen... - case os:type() of - vxworks -> - {comment, "No use to run with slaves on other nodes..."}; - _ -> - ok = do_kill_pid(Config) - end. + ok = do_kill_pid(Config). do_kill_pid(_Config) -> Name = heart_test, diff --git a/lib/kernel/test/heart_SUITE_data/simple_echo.c b/lib/kernel/test/heart_SUITE_data/simple_echo.c index 0093dbce9b..a92bb8af95 100644 --- a/lib/kernel/test/heart_SUITE_data/simple_echo.c +++ b/lib/kernel/test/heart_SUITE_data/simple_echo.c @@ -2,11 +2,7 @@ #include <stdlib.h> #include <string.h> -#ifdef VXWORKS -int simple_echo(void){ -#else int main(void){ -#endif int x; while((x = getchar()) != EOF){ putchar(x); @@ -14,4 +10,3 @@ int main(void){ } return 0; } - diff --git a/lib/kernel/test/ignore_cores.erl b/lib/kernel/test/ignore_cores.erl new file mode 100644 index 0000000000..8b1ac0fe6c --- /dev/null +++ b/lib/kernel/test/ignore_cores.erl @@ -0,0 +1,158 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2010. 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% +%% + +%%%------------------------------------------------------------------- +%%% File : ignore_cores.erl +%%% Author : Rickard Green <[email protected]> +%%% Description : +%%% +%%% Created : 11 Feb 2008 by Rickard Green <[email protected]> +%%%------------------------------------------------------------------- + +-module(ignore_cores). + +-include_lib("test_server/include/test_server.hrl"). + +-export([init/1, fini/1, setup/3, setup/4, restore/1, dir/1]). + +-record(ignore_cores, {org_cwd, + org_path, + org_pwd_env, + ign_dir = false, + cores_dir = false}). + +%% +%% Takes a testcase config +%% + +init(Config) -> + {ok, OrgCWD} = file:get_cwd(), + [{ignore_cores, + #ignore_cores{org_cwd = OrgCWD, + org_path = code:get_path(), + org_pwd_env = os:getenv("PWD")}} + | lists:keydelete(ignore_cores, 1, Config)]. + +fini(Config) -> + #ignore_cores{org_cwd = OrgCWD, + org_path = OrgPath, + org_pwd_env = OrgPWD} = ?config(ignore_cores, Config), + ok = file:set_cwd(OrgCWD), + true = code:set_path(OrgPath), + case OrgPWD of + false -> ok; + _ -> true = os:putenv("PWD", OrgPWD) + end, + lists:keydelete(ignore_cores, 1, Config). + +setup(Suite, Testcase, Config) -> + setup(Suite, Testcase, Config, false). + +setup(Suite, Testcase, Config, SetCwd) when is_atom(Suite), + is_atom(Testcase), + is_list(Config) -> + #ignore_cores{org_cwd = OrgCWD, + org_path = OrgPath, + org_pwd_env = OrgPWD} = ?config(ignore_cores, Config), + Path = lists:map(fun (".") -> OrgCWD; (Dir) -> Dir end, OrgPath), + true = code:set_path(Path), + PrivDir = ?config(priv_dir, Config), + IgnDir = filename:join([PrivDir, + atom_to_list(Suite) + ++ "_" + ++ atom_to_list(Testcase) + ++ "_wd"]), + ok = file:make_dir(IgnDir), + case SetCwd of + false -> + ok; + _ -> + ok = file:set_cwd(IgnDir), + OrgPWD = case os:getenv("PWD") of + false -> false; + PWD -> + os:putenv("PWD", IgnDir), + PWD + end + end, + ok = file:write_file(filename:join([IgnDir, "ignore_core_files"]), <<>>), + %% cores are dumped in /cores on MacOS X + CoresDir = case {?t:os_type(), filelib:is_dir("/cores")} of + {{unix,darwin}, true} -> + filelib:fold_files("/cores", + "^core.*$", + false, + fun (C,Cs) -> [C|Cs] end, + []); + _ -> + false + end, + lists:keyreplace(ignore_cores, + 1, + Config, + {ignore_cores, + #ignore_cores{org_cwd = OrgCWD, + org_path = OrgPath, + org_pwd_env = OrgPWD, + ign_dir = IgnDir, + cores_dir = CoresDir}}). + +restore(Config) -> + #ignore_cores{org_cwd = OrgCWD, + org_path = OrgPath, + org_pwd_env = OrgPWD, + ign_dir = IgnDir, + cores_dir = CoresDir} = ?config(ignore_cores, Config), + try + case CoresDir of + false -> + ok; + _ -> + %% Move cores dumped by these testcases in /cores + %% to cwd. + lists:foreach(fun (C) -> + case lists:member(C, CoresDir) of + true -> ok; + _ -> + Dst = filename:join( + [IgnDir, + filename:basename(C)]), + {ok, _} = file:copy(C, Dst), + file:delete(C) + end + end, + filelib:fold_files("/cores", + "^core.*$", + false, + fun (C,Cs) -> [C|Cs] end, + [])) + end + after + catch file:set_cwd(OrgCWD), + catch code:set_path(OrgPath), + case OrgPWD of + false -> ok; + _ -> catch os:putenv("PWD", OrgPWD) + end + end. + + +dir(Config) -> + #ignore_cores{ign_dir = Dir} = ?config(ignore_cores, Config), + Dir. diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 7241b093d0..e5e1794514 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -37,7 +37,8 @@ gethostnative_soft_restart/0, gethostnative_soft_restart/1, gethostnative_debug_level/0, gethostnative_debug_level/1, getif/1, - getif_ifr_name_overflow/1,getservbyname_overflow/1, getifaddrs/1]). + getif_ifr_name_overflow/1,getservbyname_overflow/1, getifaddrs/1, + parse_strict_address/1]). -export([get_hosts/1, get_ipv6_hosts/1, parse_hosts/1, parse_address/1, kill_gethost/0, parallell_gethost/0]). @@ -52,7 +53,7 @@ all() -> t_gethostnative, gethostnative_parallell, cname_loop, gethostnative_debug_level, gethostnative_soft_restart, getif, getif_ifr_name_overflow, getservbyname_overflow, - getifaddrs]. + getifaddrs, parse_strict_address]. groups() -> [{parse, [], [parse_hosts, parse_address]}]. @@ -66,7 +67,7 @@ required(v6) -> {require, test_dummy_ipv6_host}]; required(hosts) -> case os:type() of - {OS, _} when OS =:= win32; OS =:= vxworks -> + {OS, _} when OS =:= win32 -> [{require, hardcoded_hosts}, {require, hardcoded_ipv6_hosts}]; _Else -> @@ -582,16 +583,16 @@ parse_address(Config) when is_list(Config) -> "fe80::198.168.0.", "fec0::fFfF:127.0.0.1."], t_parse_address - (ipv6_address, + (parse_ipv6_address, V6Strict++V6Sloppy++V6Err++V4Err), t_parse_address - (ipv6strict_address, + (parse_ipv6strict_address, V6Strict++V6Err++V4Err++[S || {_,S} <- V6Sloppy]), t_parse_address - (ipv4_address, + (parse_ipv4_address, V4Strict++V4Sloppy++V4Err++V6Err++[S || {_,S} <- V6Strict]), t_parse_address - (ipv4strict_address, + (parse_ipv4strict_address, V4Strict++V4Err++V6Err++[S || {_,S} <- V4Sloppy++V6Strict]). t_parse_address(Func, []) -> @@ -599,14 +600,16 @@ t_parse_address(Func, []) -> ok; t_parse_address(Func, [{Addr,String}|L]) -> io:format("~p = ~p.~n", [Addr,String]), - {ok,Addr} = inet_parse:Func(String), + {ok,Addr} = inet:Func(String), t_parse_address(Func, L); t_parse_address(Func, [String|L]) -> io:format("~p.~n", [String]), - {error,einval} = inet_parse:Func(String), + {error,einval} = inet:Func(String), t_parse_address(Func, L). - +parse_strict_address(Config) when is_list(Config) -> + {ok, Ipv4} = inet:parse_strict_address("127.0.0.1"), + {ok, Ipv6} = inet:parse_strict_address("c11:0c22:5c33:c440:55c0:c66c:77:0088"). t_gethostnative(suite) ->[]; t_gethostnative(doc) ->[]; @@ -614,17 +617,12 @@ t_gethostnative(Config) when is_list(Config) -> %% this will result in 26 bytes sent which causes problem in Windows %% if the port-program has not assured stdin to be read in BINARY mode %% OTP-2555 - case os:type() of - vxworks -> - {skipped, "VxWorks has no native gethostbyname()"}; - _ -> - ?line case inet_gethost_native:gethostbyname( - "a23456789012345678901234") of - {error,notfound} -> - ?line ok; - {error,no_data} -> - ?line ok - end + ?line case inet_gethost_native:gethostbyname( + "a23456789012345678901234") of + {error,notfound} -> + ?line ok; + {error,no_data} -> + ?line ok end. gethostnative_parallell(suite) -> diff --git a/lib/kernel/test/inet_sockopt_SUITE.erl b/lib/kernel/test/inet_sockopt_SUITE.erl index 0c63a6d653..75496ce745 100644 --- a/lib/kernel/test/inet_sockopt_SUITE.erl +++ b/lib/kernel/test/inet_sockopt_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% Copyright Ericsson AB 2007-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -53,6 +53,8 @@ simple/1, loop_all/1, simple_raw/1, simple_raw_getbin/1, doc_examples_raw/1,doc_examples_raw_getbin/1, large_raw/1,large_raw_getbin/1,combined/1,combined_getbin/1, + ipv6_v6only_udp/1, ipv6_v6only_tcp/1, ipv6_v6only_sctp/1, + use_ipv6_v6only_udp/1, type_errors/1]). -export([init_per_testcase/2, end_per_testcase/2]). @@ -64,6 +66,8 @@ all() -> [simple, loop_all, simple_raw, simple_raw_getbin, doc_examples_raw, doc_examples_raw_getbin, large_raw, large_raw_getbin, combined, combined_getbin, + ipv6_v6only_udp, ipv6_v6only_tcp, ipv6_v6only_sctp, + use_ipv6_v6only_udp, type_errors]. groups() -> @@ -127,7 +131,7 @@ loop_all(Config) when is_list(Config) -> io_lib:format("Non mandatory failed:~w", [Failed]))} end. - + simple_raw(suite) -> []; @@ -461,6 +465,153 @@ do_combined(Config,Binary) when is_list(Config) -> ok end. + + +ipv6_v6only_udp(suite) -> []; +ipv6_v6only_udp(doc) -> "Test socket option ipv6_v6only for UDP"; +ipv6_v6only_udp(Config) when is_list(Config) -> + ipv6_v6only(Config, gen_udp). + +ipv6_v6only_tcp(suite) -> []; +ipv6_v6only_tcp(doc) -> "Test socket option ipv6_v6only for TCP"; +ipv6_v6only_tcp(Config) when is_list(Config) -> + ipv6_v6only(Config, gen_tcp). + +ipv6_v6only_sctp(suite) -> []; +ipv6_v6only_sctp(doc) -> "Test socket option ipv6_v6only for SCTP"; +ipv6_v6only_sctp(Config) when is_list(Config) -> + ipv6_v6only(Config, gen_sctp). + +ipv6_v6only(Config, Module) when is_list(Config) -> + ?line case ipv6_v6only_open(Module, []) of + {ok,S1} -> + ?line case inet:getopts(S1, [ipv6_v6only]) of + {ok,[{ipv6_v6only,Default}]} + when is_boolean(Default) -> + ?line ok = + ipv6_v6only_close(Module, S1), + ?line ipv6_v6only(Config, Module, Default); + {ok,[]} -> + ?line io:format("Not implemented.~n", []), + %% This list of OS:es where the option is + %% supposed to be not implemented is just + %% a guess, and may grow with time. + ?line case {os:type(),os:version()} of + {{unix,linux},{2,M,_}} + when M =< 4 -> ok + end, + %% At least this should work + ?line {ok,S2} = + ipv6_v6only_open( + Module, + [{ipv6_v6only,true}]), + ?line ok = + ipv6_v6only_close(Module, S2) + end; + {error,_} -> + {skipped,"Socket type not supported"} + end. + +ipv6_v6only(Config, Module, Default) when is_list(Config) -> + ?line io:format("Default ~w.~n", [Default]), + ?line {ok,S1} = + ipv6_v6only_open(Module, [{ipv6_v6only,Default}]), + ?line {ok,[{ipv6_v6only,Default}]} = + inet:getopts(S1, [ipv6_v6only]), + ?line ok = + ipv6_v6only_close(Module, S1), + ?line NotDefault = not Default, + ?line case ipv6_v6only_open(Module, [{ipv6_v6only,NotDefault}]) of + {ok,S2} -> + ?line io:format("Read-write.~n", []), + ?line {ok,[{ipv6_v6only,NotDefault}]} = + inet:getopts(S2, [ipv6_v6only]), + ok; + {error,einval} -> + ?line io:format("Read-only.~n", []), + %% This option is known to be read-only and true + %% on Windows and OpenBSD + ?line case os:type() of + {unix,openbsd} when Default =:= true -> ok; + {win32,_} when Default =:= true -> ok + end + end. + +ipv6_v6only_open(Module, Opts) -> + Module:case Module of + gen_tcp -> listen; + _ -> open + end(0, [inet6|Opts]). + +ipv6_v6only_close(Module, Socket) -> + Module:close(Socket). + + +use_ipv6_v6only_udp(suite) -> []; +use_ipv6_v6only_udp(doc) -> "Test using socket option ipv6_v6only for UDP"; +use_ipv6_v6only_udp(Config) when is_list(Config) -> + ?line case gen_udp:open(0, [inet6,{ipv6_v6only,true}]) of + {ok,S6} -> + ?line case inet:getopts(S6, [ipv6_v6only]) of + {ok,[{ipv6_v6only,true}]} -> + use_ipv6_v6only_udp(Config, S6); + {ok,Other} -> + {skipped,{getopts,Other}} + end; + {error,_} -> + {skipped,"Socket type not supported"} + end. + +use_ipv6_v6only_udp(_Config, S6) -> + ?line {ok,Port} = inet:port(S6), + ?line {ok,S4} = gen_udp:open(Port, [inet]), + ?line E6 = " IPv6-echo.", + ?line E4 = " IPv4-echo.", + ?line Sender = + spawn_link(fun () -> use_ipv6_v6only_udp_sender(Port, E6, E4) end), + ?line use_ipv6_v6only_udp_listener( + S6, S4, E6, E4, monitor(process, Sender)). + +use_ipv6_v6only_udp_listener(S6, S4, E6, E4, Mref) -> + ?line receive + {udp,S6,IP,P,Data} -> + ?line ok = gen_udp:send(S6, IP, P, [Data|E6]), + ?line use_ipv6_v6only_udp_listener(S6, S4, E6, E4, Mref); + {udp,S4,IP,P,Data} -> + ?line ok = gen_udp:send(S4, IP, P, [Data|E4]), + ?line use_ipv6_v6only_udp_listener(S6, S4, E6, E4, Mref); + {'DOWN',Mref,_,_,normal} -> + ok; + {'DOWN',Mref,_,_,Result} -> + %% Since we are linked we will never arrive here + Result; + Other -> + ?line exit({failed,{listener_unexpected,Other}}) + end. + +use_ipv6_v6only_udp_sender(Port, E6, E4) -> + D6 = "IPv6-send.", + D4 = "IPv4-send.", + R6 = D6 ++ E6, + R4 = D4 ++ E4, + R6 = sndrcv({0,0,0,0,0,0,0,1}, Port, [inet6], D6), + R4 = sndrcv({127,0,0,1}, Port, [inet], D4), + ok. + +sndrcv(Ip, Port, Opts, Data) -> + {ok,S} = gen_udp:open(0, Opts), + io:format("[~w:~w] ! ~s~n", [Ip,Port,Data]), + ok = gen_udp:send(S, Ip, Port, Data), + receive + {udp,S,Ip,Port,RecData} -> + io:format("[~w:~w] : ~s~n", [Ip,Port,RecData]), + RecData; + Other -> + exit({failed,{sndrcv_unexpectec,Other}}) + end. + + + type_errors(suite) -> []; type_errors(doc) -> @@ -623,7 +774,6 @@ all_listen_options() -> {exit_on_close, true, false, true, true}, %{high_watermark,4096,8192,true,true}, %{low_watermark,2048,4096,true,true}, - {bit8,on,off,true,true}, {send_timeout,infinity,1000,true,true}, {send_timeout_close,false,true,true,true}, {delay_send,false,true,true,true}, @@ -647,7 +797,6 @@ all_connect_options() -> {exit_on_close, true, false, true, true}, {high_watermark,4096,8192,false,true}, {low_watermark,2048,4096,false,true}, - {bit8,on,off,true,true}, {send_timeout,infinity,1000,true,true}, {send_timeout_close,false,true,true,true}, {delay_send,false,true,true,true}, diff --git a/lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c b/lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c index f24c93edf5..9c8f8eb91a 100644 --- a/lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c +++ b/lib/kernel/test/inet_sockopt_SUITE_data/sockopt_helper.c @@ -1,12 +1,3 @@ -#if defined(VXWORKS) -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -int sockopt_helper(void){ - return 0; -} -#else - #if defined(__WIN32__) #define WIN32_LEAN_AND_MEAN #include <winsock2.h> @@ -215,5 +206,3 @@ int main(void){ } while (x != C_QUIT); return 0; } -#endif - diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl index e0b90c5214..6fe97ed04f 100644 --- a/lib/kernel/test/init_SUITE.erl +++ b/lib/kernel/test/init_SUITE.erl @@ -256,47 +256,42 @@ get_plain_arguments(Config) when is_list(Config) -> boot_var(doc) -> []; boot_var(suite) -> {req, [distribution, {local_slave_nodes, 1}]}; boot_var(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "Not run on VxWorks"}; + ?line Dog = ?t:timetrap(?t:seconds(100)), + + {BootScript, TEST_VAR, KernelVsn, StdlibVsn} = create_boot(Config), + + %% Should fail as we have not given -boot_var TEST_VAR + ?line {error, timeout} = + start_node(init_test, "-boot " ++ BootScript), + + case is_real_system(KernelVsn, StdlibVsn) of + true -> + %% Now it should work !! + ?line {ok, Node} = + start_node(init_test, + "-boot " ++ BootScript ++ + " -boot_var TEST_VAR " ++ TEST_VAR), + stop_node(Node), + Res = ok; _ -> - ?line Dog = ?t:timetrap(?t:seconds(100)), - - {BootScript, TEST_VAR, KernelVsn, StdlibVsn} = create_boot(Config), - - %% Should fail as we have not given -boot_var TEST_VAR - ?line {error, timeout} = - start_node(init_test, "-boot " ++ BootScript), - - case is_real_system(KernelVsn, StdlibVsn) of - true -> - %% Now it should work !! - ?line {ok, Node} = - start_node(init_test, - "-boot " ++ BootScript ++ - " -boot_var TEST_VAR " ++ TEST_VAR), - stop_node(Node), - Res = ok; - _ -> -%% What we need is not so much version numbers on the directories, but -%% for the boot var TEST_VAR to appear in the boot script, and it doesn't -%% if we give the 'local' option to systools:make_script. - ?t:format( - "Test case not complete as we are not~n" - "running in a real system!~n" - "Probably this test is performed in a " - "clearcase view or source tree.~n" - "Need version numbers on the kernel and " - "stdlib directories!~n", - []), - Res = {skip, - "Test case only partially run since it is run " - "in a clearcase view or in a source tree. " - "Need an installed system to complete this test."} - end, - ?line ?t:timetrap_cancel(Dog), - Res - end. + %% What we need is not so much version numbers on the directories, but + %% for the boot var TEST_VAR to appear in the boot script, and it doesn't + %% if we give the 'local' option to systools:make_script. + ?t:format( + "Test case not complete as we are not~n" + "running in a real system!~n" + "Probably this test is performed in a " + "clearcase view or source tree.~n" + "Need version numbers on the kernel and " + "stdlib directories!~n", + []), + Res = {skip, + "Test case only partially run since it is run " + "in a clearcase view or in a source tree. " + "Need an installed system to complete this test."} + end, + ?line ?t:timetrap_cancel(Dog), + Res. create_boot(Config) -> ?line {ok, OldDir} = file:get_cwd(), @@ -579,55 +574,47 @@ script_id(Config) when is_list(Config) -> boot1(doc) -> []; boot1(suite) -> {req, [distribution, {local_slave_nodes, 1}, {time, 35}]}; boot1(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "Not run on VxWorks"}; - _ -> - ?line Dog = ?t:timetrap(?t:seconds(80)), - Args = args() ++ " -boot start_sasl", - ?line {ok, Node} = start_node(init_test, Args), - ?line stop_node(Node), - - %% Try to start with non existing boot file. - Args1 = args() ++ " -boot dummy_script", - ?line {error, timeout} = start_node(init_test, Args1), - - ?line ?t:timetrap_cancel(Dog), - ok - end. + ?line Dog = ?t:timetrap(?t:seconds(80)), + Args = args() ++ " -boot start_sasl", + ?line {ok, Node} = start_node(init_test, Args), + ?line stop_node(Node), + + %% Try to start with non existing boot file. + Args1 = args() ++ " -boot dummy_script", + ?line {error, timeout} = start_node(init_test, Args1), + + ?line ?t:timetrap_cancel(Dog), + ok. boot2(doc) -> []; boot2(suite) -> {req, [distribution, {local_slave_nodes, 1}, {time, 35}]}; boot2(Config) when is_list(Config) -> + Dog = ?t:timetrap(?t:seconds(80)), + + %% Absolute boot file name + Boot = filename:join([code:root_dir(), "bin", "start_sasl"]), + + Args = args() ++ " -boot \"" ++ Boot++"\"", + {ok, Node} = start_node(init_test, Args), + stop_node(Node), + case os:type() of - vxworks -> - {comment, "Not run on VxWorks"}; + {win32, _} -> + %% Absolute boot file name for Windows -- all slashes are + %% converted to backslashes. + Win_boot = lists:map(fun + ($/) -> $\\; + (C) -> C + end, Boot), + Args2 = args() ++ " -boot \"" ++ Win_boot ++ "\"", + {ok, Node2} = start_node(init_test, Args2), + stop_node(Node2); _ -> - ?line Dog = ?t:timetrap(?t:seconds(80)), - - %% Absolute boot file name - Boot = filename:join([code:root_dir(), "bin", "start_sasl"]), - - Args = args() ++ " -boot \"" ++ Boot++"\"", - ?line {ok, Node} = start_node(init_test, Args), - ?line stop_node(Node), - - case os:type() of - {win32, _} -> - %% Absolute boot file name for Windows -- all slashes are - %% converted to backslashes. - Win_boot = lists:map(fun($/) -> $\\; (C) -> C end, - Boot), - Args2 = args() ++ " -boot \"" ++ Win_boot ++ "\"", - ?line {ok, Node2} = start_node(init_test, Args2), - ?line stop_node(Node2); - _ -> - ok - end, - - ?line ?t:timetrap_cancel(Dog), ok - end. + end, + + ?t:timetrap_cancel(Dog), + ok. %% Misc. functions diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl index 7549e2c83e..36e13cec26 100644 --- a/lib/kernel/test/interactive_shell_SUITE.erl +++ b/lib/kernel/test/interactive_shell_SUITE.erl @@ -29,7 +29,7 @@ -export([toerl_server/3]). init_per_testcase(_Func, Config) -> - Dog = test_server:timetrap(test_server:seconds(60)), + Dog = test_server:timetrap(test_server:minutes(3)), [{watchdog,Dog}|Config]. end_per_testcase(_Func, Config) -> diff --git a/lib/kernel/test/kernel.cover b/lib/kernel/test/kernel.cover index f6967ca651..af1dd7eaad 100644 --- a/lib/kernel/test/kernel.cover +++ b/lib/kernel/test/kernel.cover @@ -1,3 +1,3 @@ %% -*- erlang -*- -{incl_mods,[gen_udp,inet6_udp,inet_res,inet_dns]}. +{incl_app,kernel,details}. diff --git a/lib/kernel/test/kernel.spec.wxworks b/lib/kernel/test/kernel.spec.wxworks deleted file mode 100644 index 370e474e64..0000000000 --- a/lib/kernel/test/kernel.spec.wxworks +++ /dev/null @@ -1,63 +0,0 @@ -%% -*- erlang -*- -{suites,"kernel_test",all}. -{skip_cases,"kernel_test",bif_SUITE,[spawn_link_race1],"Known bug."}. -{skip_cases,"kernel_test",file_SUITE, - [read_write_file], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [cur_dir_0], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [open1], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [file_info_times], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [file_write_file_info], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [truncate], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [rename], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [e_delete], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [e_rename], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [delayed_write], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [read_ahead], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",file_SUITE, - [segment_write], - "VxWorks filesystem would overload"}. -{skip_cases,"kernel_test",file_SUITE, - [segment_read], - "VxWorks filesystem would overload"}. -{skip_cases,"kernel_test",file_SUITE, - [compress_errors], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",init_SUITE,[restart],"Uses peer nodes"}. -{skip_cases,"kernel_test",os_SUITE,[space_in_cwd],"VxWorks can't handle this"}. -{skip_cases,"kernel_test",os_SUITE, - [space_in_name], - "VxWorks can't handle this"}. -{skip_cases,"kernel_test",os_SUITE,[quoting],"VxWorks can't handle this"}. -{skip_cases,"kernel_test",prim_file_SUITE, - [open1], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",prim_file_SUITE, - [compress_errors], - "VxWorks filesystem can't handle this"}. -{skip_cases,"kernel_test",seq_trace_SUITE, - [distributed_recv], - "Test not adopted to slaves on different machine"}. -{skip_cases,"kernel_test",seq_trace_SUITE, - [distributed_exit], - "Test not adopted to slaves on different machine"}. diff --git a/lib/kernel/test/os_SUITE.erl b/lib/kernel/test/os_SUITE.erl index ae3410d13f..3f2195b609 100644 --- a/lib/kernel/test/os_SUITE.erl +++ b/lib/kernel/test/os_SUITE.erl @@ -202,8 +202,6 @@ find_executable(Config) when is_list(Config) -> %% Never return a directory name. ?line false = os:find_executable("unix", [DataDir]), - ok; - vxworks -> ok end. diff --git a/lib/kernel/test/pdict_SUITE.erl b/lib/kernel/test/pdict_SUITE.erl index 8afdfc8a47..60b818cbe3 100644 --- a/lib/kernel/test/pdict_SUITE.erl +++ b/lib/kernel/test/pdict_SUITE.erl @@ -152,7 +152,6 @@ heavy(Config) when is_list(Config) -> time(5000), ?M([],get()), case {os:type(),?t:is_debug()} of - {vxworks,_} -> ok; {_,true} -> ok; _ -> time(50000), diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index 3e2202922c..4e93a593b3 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -57,6 +57,8 @@ %% System probe functions that might be handy to check from the shell -export([unix_free/1]). +-export([allocate/1]). + -include_lib("test_server/include/test_server.hrl"). -include_lib("kernel/include/file.hrl"). @@ -87,7 +89,7 @@ groups() -> cur_dir_1a, cur_dir_1b]}, {files, [], [{group, open}, {group, pos}, {group, file_info}, - truncate, sync, datasync, advise, large_write]}, + truncate, sync, datasync, advise, large_write, allocate]}, {open, [], [open1, modes, close, access, read_write, pread_write, append, exclusive]}, @@ -406,9 +408,6 @@ cur_dir_1(Config, Handle) -> {unix, _} -> ?line {error, enotsup} = ?PRIM_FILE_call(get_cwd, Handle, ["d:"]); - vxworks -> - ?line {error, enotsup} = - ?PRIM_FILE_call(get_cwd, Handle, ["d:"]); {win32, _} -> win_cur_dir_1(Config, Handle) end, @@ -843,10 +842,7 @@ file_info_basic_directory(Config, Handle) -> ?line test_directory("c:/", read_write, Handle), ?line test_directory("c:\\", read_write, Handle); {unix, _} -> - ?line test_directory("/", read, Handle); - vxworks -> - %% Check is just done for owner - ?line test_directory("/", read_write, Handle) + ?line test_directory("/", read, Handle) end, ?line test_server:timetrap_cancel(Dog). @@ -1365,6 +1361,76 @@ 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) + ++"_allocate.fil"), + + Line1 = "Hello\n", + Line2 = "World!\n", + + ?line {ok, Fd} = ?PRIM_FILE:open(Allocate, [write, binary]), + allocate_and_assert(Fd, 1, iolist_size([Line1, Line2])), + ?line ok = ?PRIM_FILE:write(Fd, Line1), + ?line ok = ?PRIM_FILE:write(Fd, Line2), + ?line ok = ?PRIM_FILE:close(Fd), + + ?line {ok, Fd2} = ?PRIM_FILE:open(Allocate, [write, binary]), + allocate_and_assert(Fd2, 1, iolist_size(Line1)), + ?line ok = ?PRIM_FILE:write(Fd2, Line1), + ?line ok = ?PRIM_FILE:write(Fd2, Line2), + ?line ok = ?PRIM_FILE:close(Fd2), + + ?line {ok, Fd3} = ?PRIM_FILE:open(Allocate, [write, binary]), + allocate_and_assert(Fd3, 1, iolist_size(Line1) + 1), + ?line ok = ?PRIM_FILE:write(Fd3, Line1), + ?line ok = ?PRIM_FILE:write(Fd3, Line2), + ?line ok = ?PRIM_FILE:close(Fd3), + + ?line {ok, Fd4} = ?PRIM_FILE:open(Allocate, [write, binary]), + allocate_and_assert(Fd4, 1, 4 * iolist_size([Line1, Line2])), + ?line ok = ?PRIM_FILE:write(Fd4, Line1), + ?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) -> + % Just verify that calls to ?PRIM_FILE:allocate/3 don't crash or have + % any other negative side effect. We can't really asssert against a + % specific return value, because support for file space pre-allocation + % depends on the OS, OS version and underlying filesystem. + % + % The Linux kernel added support for fallocate() in version 2.6.23, + % which currently works only for the ext4, ocfs2, xfs and btrfs file + % systems. posix_fallocate() is available in glibc as of version + % 2.1.94, but it was buggy until glibc version 2.7. + % + % Mac OS X, as of version 10.3, supports the fcntl operation F_PREALLOCATE. + % + % Solaris supports posix_fallocate() but only for the UFS file system + % apparently (not supported for ZFS). + % + % FreeBSD 9.0 is the first FreeBSD release supporting posix_fallocate(). + % + % For Windows there's apparently no way to pre-allocate file space, at + % least with similar API/semantics as posix_fallocate(), fallocate() or + % fcntl F_PREALLOCATE. + Result = ?PRIM_FILE:allocate(Fd, Offset, Length), + case os:type() of + {win32, _} -> + ?line {error, enotsup} = Result; + _ -> + ?line _ = Result + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + delete_a(suite) -> []; delete_a(doc) -> []; delete_a(Config) when is_list(Config) -> @@ -1508,9 +1574,7 @@ e_delete(Config) when is_list(Config) -> Base, #file_info {mode=8#600}); {win32, _} -> %% Remove a character device. - ?line {error, eacces} = ?PRIM_FILE:delete("nul"); - vxworks -> - ok + ?line {error, eacces} = ?PRIM_FILE:delete("nul") end, ?line test_server:timetrap_cancel(Dog), @@ -1524,110 +1588,105 @@ e_delete(Config) when is_list(Config) -> e_rename(suite) -> []; e_rename(doc) -> []; e_rename(Config) when is_list(Config) -> - case os:type() of - vxworks -> - {comment, "Windriver: dosFs must be fixed first!"}; - _ -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), - ?line RootDir = ?config(priv_dir, Config), - ?line Base = filename:join(RootDir, - atom_to_list(?MODULE)++"_e_rename"), - ?line ok = ?PRIM_FILE:make_dir(Base), - - %% Create an empty directory. - ?line EmptyDir = filename:join(Base, "empty_dir"), - ?line ok = ?PRIM_FILE:make_dir(EmptyDir), - - %% Create a non-empty directory. - ?line NonEmptyDir = filename:join(Base, "non_empty_dir"), - ?line ok = ?PRIM_FILE:make_dir(NonEmptyDir), - ?line ok = ?PRIM_FILE:write_file( - filename:join(NonEmptyDir, "a_file"), - "hello\n"), - - %% Create another non-empty directory. - ?line ADirectory = filename:join(Base, "a_directory"), - ?line ok = ?PRIM_FILE:make_dir(ADirectory), - ?line ok = ?PRIM_FILE:write_file( - filename:join(ADirectory, "a_file"), - "howdy\n\n"), + ?line Dog = test_server:timetrap(test_server:seconds(10)), + ?line RootDir = ?config(priv_dir, Config), + ?line Base = filename:join(RootDir, + atom_to_list(?MODULE)++"_e_rename"), + ?line ok = ?PRIM_FILE:make_dir(Base), - %% Create a data file. - ?line File = filename:join(Base, "just_a_file"), - ?line ok = ?PRIM_FILE:write_file(File, "anything goes\n\n"), - - %% Move an existing directory to a non-empty directory. - ?line {error, eexist} = - ?PRIM_FILE:rename(ADirectory, NonEmptyDir), - - %% Move a root directory. - ?line {error, einval} = ?PRIM_FILE:rename("/", "arne"), - - %% Move Base into Base/new_name. - ?line {error, einval} = - ?PRIM_FILE:rename(Base, filename:join(Base, "new_name")), - - %% Overwrite a directory with a file. - ?line expect({error, eexist}, % FreeBSD (?) - {error, eisdir}, - ?PRIM_FILE:rename(File, EmptyDir)), - ?line expect({error, eexist}, % FreeBSD (?) - {error, eisdir}, - ?PRIM_FILE:rename(File, NonEmptyDir)), - - %% Move a non-existing file. - ?line NonExistingFile = filename:join( - Base, "non_existing_file"), - ?line {error, enoent} = - ?PRIM_FILE:rename(NonExistingFile, NonEmptyDir), - - %% Overwrite a file with a directory. - ?line expect({error, eexist}, % FreeBSD (?) - {error, enotdir}, - ?PRIM_FILE:rename(ADirectory, File)), - - %% Move a file to another filesystem. - %% XXX - This test case is bogus. We cannot be guaranteed that - %% the source and destination are on - %% different filesystems. - %% - %% XXX - Gross hack! - ?line Comment = - case os:type() of - {unix, _} -> - OtherFs = "/tmp", - ?line NameOnOtherFs = - filename:join(OtherFs, - filename:basename(File)), - ?line {ok, Com} = - case ?PRIM_FILE:rename( - File, NameOnOtherFs) of - {error, exdev} -> - %% The file could be in - %% the same filesystem! - {ok, ok}; - ok -> - {ok, {comment, - "Moving between filesystems " - "suceeded, files are probably " - "in the same filesystem!"}}; - {error, eperm} -> - {ok, {comment, "SBS! You don't " - "have the permission to do " - "this test!"}}; - Else -> - Else - end, - Com; - {win32, _} -> - %% At least Windows NT can - %% successfully move a file to - %% another drive. - ok - end, - ?line test_server:timetrap_cancel(Dog), - Comment - end. + %% Create an empty directory. + ?line EmptyDir = filename:join(Base, "empty_dir"), + ?line ok = ?PRIM_FILE:make_dir(EmptyDir), + + %% Create a non-empty directory. + ?line NonEmptyDir = filename:join(Base, "non_empty_dir"), + ?line ok = ?PRIM_FILE:make_dir(NonEmptyDir), + ?line ok = ?PRIM_FILE:write_file( + filename:join(NonEmptyDir, "a_file"), + "hello\n"), + + %% Create another non-empty directory. + ?line ADirectory = filename:join(Base, "a_directory"), + ?line ok = ?PRIM_FILE:make_dir(ADirectory), + ?line ok = ?PRIM_FILE:write_file( + filename:join(ADirectory, "a_file"), + "howdy\n\n"), + + %% Create a data file. + ?line File = filename:join(Base, "just_a_file"), + ?line ok = ?PRIM_FILE:write_file(File, "anything goes\n\n"), + + %% Move an existing directory to a non-empty directory. + ?line {error, eexist} = + ?PRIM_FILE:rename(ADirectory, NonEmptyDir), + + %% Move a root directory. + ?line {error, einval} = ?PRIM_FILE:rename("/", "arne"), + + %% Move Base into Base/new_name. + ?line {error, einval} = + ?PRIM_FILE:rename(Base, filename:join(Base, "new_name")), + + %% Overwrite a directory with a file. + ?line expect({error, eexist}, % FreeBSD (?) + {error, eisdir}, + ?PRIM_FILE:rename(File, EmptyDir)), + ?line expect({error, eexist}, % FreeBSD (?) + {error, eisdir}, + ?PRIM_FILE:rename(File, NonEmptyDir)), + + %% Move a non-existing file. + ?line NonExistingFile = filename:join( + Base, "non_existing_file"), + ?line {error, enoent} = + ?PRIM_FILE:rename(NonExistingFile, NonEmptyDir), + + %% Overwrite a file with a directory. + ?line expect({error, eexist}, % FreeBSD (?) + {error, enotdir}, + ?PRIM_FILE:rename(ADirectory, File)), + + %% Move a file to another filesystem. + %% XXX - This test case is bogus. We cannot be guaranteed that + %% the source and destination are on + %% different filesystems. + %% + %% XXX - Gross hack! + ?line Comment = + case os:type() of + {unix, _} -> + OtherFs = "/tmp", + ?line NameOnOtherFs = + filename:join(OtherFs, + filename:basename(File)), + ?line {ok, Com} = + case ?PRIM_FILE:rename( + File, NameOnOtherFs) of + {error, exdev} -> + %% The file could be in + %% the same filesystem! + {ok, ok}; + ok -> + {ok, {comment, + "Moving between filesystems " + "suceeded, files are probably " + "in the same filesystem!"}}; + {error, eperm} -> + {ok, {comment, "SBS! You don't " + "have the permission to do " + "this test!"}}; + Else -> + Else + end, + Com; + {win32, _} -> + %% At least Windows NT can + %% successfully move a file to + %% another drive. + ok + end, + ?line test_server:timetrap_cancel(Dog), + Comment. e_make_dir(suite) -> []; e_make_dir(doc) -> []; @@ -1660,8 +1719,6 @@ e_make_dir(Config) when is_list(Config) -> ?line ?PRIM_FILE:write_file_info(Base, #file_info {mode=8#600}); {win32, _} -> - ok; - vxworks -> ok end, ?line test_server:timetrap_cancel(Dog), @@ -1716,8 +1773,6 @@ e_del_dir(Config) when is_list(Config) -> ?line ?PRIM_FILE:write_file_info( Base, #file_info {mode=8#600}); {win32, _} -> - ok; - vxworks -> ok end, ?line test_server:timetrap_cancel(Dog), diff --git a/lib/kernel/test/ram_file_SUITE.erl b/lib/kernel/test/ram_file_SUITE.erl index ab95a3ff5f..5c4437d4d3 100644 --- a/lib/kernel/test/ram_file_SUITE.erl +++ b/lib/kernel/test/ram_file_SUITE.erl @@ -1,7 +1,8 @@ +%% -*- coding: utf-8 -*- %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2011. All Rights Reserved. +%% Copyright Ericsson AB 2001-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -167,7 +168,7 @@ pread_pwrite(suite) -> pread_pwrite(doc) -> ["Test that pread/2,3 and pwrite/2,3 works."]; pread_pwrite(Config) when is_list(Config) -> - ?line Str = "Flygande b�ckaziner s�ka hwila p� mjuqa tuvor x", + ?line Str = "Flygande bäckaziner söka hwila på mjuqa tuvor x", ?line Bin = list_to_binary(Str), %% pread_pwrite_test(?FILE_MODULE, Str, [ram, read, write]), @@ -206,7 +207,7 @@ position(suite) -> position(doc) -> ["Test that position/2 works."]; position(Config) when is_list(Config) -> - ?line Str = "Att vara eller icke vara, det �r fr�gan. ", + ?line Str = "Att vara eller icke vara, det är frågan. ", ?line Bin = list_to_binary(Str), %% position_test(?FILE_MODULE, Str, [ram, read]), @@ -287,8 +288,8 @@ truncate(suite) -> truncate(doc) -> ["Test that truncate/1 works."]; truncate(Config) when is_list(Config) -> - ?line Str = "M�n �dlare att lida och f�rdraga " - ++ "ett bittert �des stygn av pilar, ", + ?line Str = "Mån ädlare att lida och fördraga " + ++ "ett bittert ödes stygn av pilar, ", ?line Bin = list_to_binary(Str), %% ok = truncate_test(?FILE_MODULE, Str, [ram, read, write]), @@ -331,7 +332,7 @@ sync(suite) -> sync(doc) -> ["Test that sync/1 at least does not crash."]; sync(Config) when is_list(Config) -> - ?line Str = "�n att ta till vapen mot ett hav av kval. ", + ?line Str = "än att ta till vapen mot ett hav av kval. ", ?line Bin = list_to_binary(Str), %% sync_test(?FILE_MODULE, Str, [ram, read, write]), @@ -365,8 +366,8 @@ get_set_file(doc) -> ["Tests get_file/1, set_file/2, get_file_close/1 and get_size/1."]; get_set_file(Config) when is_list(Config) -> %% These two strings should not be of equal length. - ?line Str = "N�r h�gan nord blir sn�bet�ckt, ", - ?line Str2 = "f�r alla harar byta dr�kt. ", + ?line Str = "När högan nord blir snöbetäckt, ", + ?line Str2 = "får alla harar byta dräkt. ", ?line Bin = list_to_binary(Str), ?line Bin2 = list_to_binary(Str2), %% diff --git a/lib/kernel/test/wrap_log_reader_SUITE.erl b/lib/kernel/test/wrap_log_reader_SUITE.erl index 6c47fda9c5..16b3a7cc1e 100644 --- a/lib/kernel/test/wrap_log_reader_SUITE.erl +++ b/lib/kernel/test/wrap_log_reader_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2011. All Rights Reserved. +%% Copyright Ericsson AB 1998-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index 7254d714eb..46a991eb38 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 2.15.3 +KERNEL_VSN = 2.16 |