diff options
Diffstat (limited to 'lib/kernel')
-rw-r--r-- | lib/kernel/doc/src/application.xml | 9 | ||||
-rw-r--r-- | lib/kernel/doc/src/file.xml | 12 | ||||
-rw-r--r-- | lib/kernel/doc/src/packages.xml | 208 | ||||
-rw-r--r-- | lib/kernel/doc/src/ref_man.xml | 1 | ||||
-rw-r--r-- | lib/kernel/src/application.erl | 16 | ||||
-rw-r--r-- | lib/kernel/src/file.erl | 14 | ||||
-rw-r--r-- | lib/kernel/src/file_io_server.erl | 4 | ||||
-rw-r--r-- | lib/kernel/src/ram_file.erl | 7 | ||||
-rw-r--r-- | lib/kernel/test/application_SUITE.erl | 13 | ||||
-rw-r--r-- | lib/kernel/test/file_SUITE.erl | 72 | ||||
-rw-r--r-- | lib/kernel/test/global_SUITE.erl | 35 | ||||
-rw-r--r-- | lib/kernel/test/prim_file_SUITE.erl | 74 |
12 files changed, 223 insertions, 242 deletions
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml index 51a3311ec2..9f19efc793 100644 --- a/lib/kernel/doc/src/application.xml +++ b/lib/kernel/doc/src/application.xml @@ -121,6 +121,15 @@ </desc> </func> <func> + <name name="get_env" arity="3"/> + <fsummary>Get the value of a configuration parameter using a default</fsummary> + <desc> + <p>Works like <seealso marker="#get_env/2">get_env/2</seealso> but returns + <c><anno>Def</anno></c> value when configuration parameter + <c><anno>Par</anno></c> does not exist.</p> + </desc> + </func> + <func> <name name="get_key" arity="1"/> <name name="get_key" arity="2"/> <fsummary>Get the value of an application specification key</fsummary> diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 536b98b5f5..e30ade1bd2 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -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> diff --git a/lib/kernel/doc/src/packages.xml b/lib/kernel/doc/src/packages.xml deleted file mode 100644 index 8a82b91a90..0000000000 --- a/lib/kernel/doc/src/packages.xml +++ /dev/null @@ -1,208 +0,0 @@ -<?xml version="1.0" encoding="latin1" ?> -<!DOCTYPE erlref SYSTEM "erlref.dtd"> - -<erlref> - <header> - <copyright> - <year>2004</year><year>2012</year> - <holder>Ericsson AB. All Rights Reserved.</holder> - </copyright> - <legalnotice> - The contents of this file are subject to the Erlang Public License, - Version 1.1, (the "License"); you may not use this file except in - compliance with the License. You should have received a copy of the - Erlang Public License along with this software. If not, it can be - retrieved online at http://www.erlang.org/. - - Software distributed under the License is distributed on an "AS IS" - basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See - the License for the specific language governing rights and limitations - under the License. - - </legalnotice> - - <title>packages</title> - <prepared>Kenneth Lundin</prepared> - <responsible>Kenneth Lundin</responsible> - <docno>1</docno> - <approved>Kenneth Lundin</approved> - <checked></checked> - <date>2004-09-07</date> - <rev>A</rev> - <file>packages.sgml</file> - </header> - <module>packages</module> - <modulesummary>Packages in Erlang</modulesummary> - <description> - <warning><p> - Packages has since it was introduced more than 5 years ago been an - experimental feature. Use it at your own risk, we do not - actively maintain and develop this feature. It might however be - supported some - day. - </p> - <p> - In spite of this packages work quite well, but there are some - known issues in tools and other parts where packages don't work well. - </p> - </warning> - <p><em>Introduction</em></p> - <p>Packages are simply namespaces for modules. - All old Erlang modules automatically belong to the top level - ("empty-string") namespace, and do not need any changes.</p> - <p>The full name of a packaged module is written as e.g. - "<c>fee.fie.foe.foo</c>", - i.e., as atoms separated by periods, - where the package name is the part up to - but not including the last period; - in this case "<c>fee.fie.foe</c>". - A more concrete example is the module <c>erl.lang.term</c>, - which is in the - package <c>erl.lang</c>. - Package names can have any number of segments, as in - <c>erl.lang.list.sort</c>. - The atoms in the name can be quoted, as in <c>foo.'Bar'.baz</c>, - or even the - whole name, as in <c>'foo.bar.baz'</c> but the concatenation of - atoms and - periods must not contain two consecutive period characters or - end with a period, - as in <c>'foo..bar'</c>, <c>foo.'.bar'</c>, or <c>foo.'bar.'</c>. - The periods must not be followed by whitespace.</p> - <p>The code loader maps module names onto the file system directory - structure. - E.g., the module <c>erl.lang.term</c> corresponds to a file - <c>.../erl/lang/term.beam</c> - in the search path. - Note that the name of the actual object file corresponds to - the last part only of the full module name. - (Thus, old existing modules such as <c>lists</c> - simply map to <c>.../lists.beam</c>, exactly as before.)</p> - <p>A packaged module in a file "<c>foo/bar/fred.erl</c>" is declared - as:</p> - <code type="none"> --module(foo.bar.fred).</code> - <p>This can be compiled and loaded from the Erlang shell using - <c>c(fred)</c>, if - your current directory is the same as that of the file. - The object file will be named <c>fred.beam</c>.</p> - <p>The Erlang search path works exactly as before, - except that the package segments will be appended to each - directory in the path in order to find the - file. E.g., assume the path is <c>["/usr/lib/erl", "/usr/local/lib/otp/legacy/ebin", "/home/barney/erl"]</c>. - Then, the code for a module named <c>foo.bar.fred</c> will be - searched for - first as <c>"/usr/lib/erl/foo/bar/fred.beam"</c>, then - <c>"/usr/local/lib/otp/legacy/ebin/foo/bar/fred.beam"</c> - and lastly <c>"/home/barney/erl/foo/bar/fred.beam"</c>. - A module - like <c>lists</c>, which is in the top-level package, - will be looked for as <c>"/usr/lib/erl/lists.beam"</c>, - <c>"/usr/local/lib/otp/legacy/ebin/lists.beam"</c> and - <c>"/home/barney/erl/lists.beam"</c>.</p> - <p><em>Programming</em></p> - <p>Normally, if a call is made from one module to another, - it is assumed that the - called module belongs to the same package as the source module. - The compiler - automatically expands such calls. E.g., in:</p> - <code type="none"> --module(foo.bar.m1). --export([f/1]). - -f(X) -> m2:g(X).</code> - <p><c>m2:g(X)</c> becomes a call to <c>foo.bar.m2</c> - If this is not what was intended, the call can be written - explicitly, as in</p> - <code type="none"> --module(foo.bar.m1). --export([f/1]). - -f(X) -> fee.fie.foe.m2:g(X).</code> - <p>Because the called module is given with an explicit package name, - no expansion is done in this case.</p> - <p>If a module from another package is used repeatedly in a module, - an import declaration can make life easier:</p> - <code type="none"> --module(foo.bar.m1). --export([f/1, g/1]). --import(fee.fie.foe.m2). - -f(X) -> m2:g(X). -g(X) -> m2:h(X).</code> - <p>will make the calls to <c>m2</c> refer to <c>fee.fie.foe.m2</c>. - More generally, a declaration <c>-import(Package.Module).</c> - will cause calls to <c>Module</c> - to be expanded to <c>Package.Module</c>.</p> - <p>Old-style function imports work as normal (but full module - names must be - used); e.g.:</p> - <code type="none"> --import(fee.fie.foe.m2, [g/1, h/1]).</code> - <p>however, it is probably better to avoid this form of import - altogether in new - code, since it makes it hard to see what calls are really "remote".</p> - <p>If it is necessary to call a module in the top-level package - from within a - named package, the module name can be written either with an - initial period as - in e.g. "<c>.lists</c>", or with an empty initial atom, as in - "<c>''.lists</c>". - However, the best way is to use an import declaration - - this is most obvious to - the eye, and makes sure we don't forget adding a period somewhere:</p> - <code type="none"> --module(foo.bar.fred). --export([f/1]). --import(lists). - -f(X) -> lists:reverse(X).</code> - <p>The dot-syntax for module names can be used in any expression. - All segments must - be constant atoms, and the result must be a well-formed - package/module name. - E.g.:</p> - <code type="none"> -spawn(foo.bar.fred, f, [X])</code> - <p>is equivalent to <c>spawn('foo.bar.fred', f, [X])</c>.</p> - <p><em>The Erlang Shell</em></p> - <p>The shell also automatically expands remote calls, - however currently no - expansions are made by default. - The user can change the behaviour by using the <c>import/1</c> - shell command (or its abbreviation <c>use/1</c>). E.g.:</p> - <pre> -1> <input>import(foo.bar.m).</input> -ok -2> <input>m:f().</input></pre> - <p>will evaluate <c>foo.bar.m:f()</c>. - If a new import is made of the same name, - this overrides any previous import. - (It is likely that in the future, some - system packages will be pre-imported.)</p> - <p>In addition, the shell command <c>import_all/1</c> - (and its alias <c>use_all/1</c>) - imports all modules currently found in the path for a given - package name. E.g., - assuming the files "<c>.../foo/bar/fred.beam</c>", - "<c>.../foo/bar/barney.beam</c>" - and "<c>.../foo/bar/bambam.beam</c>" can be found from our current - path,</p> - <pre> -1> <input>import_all(foo.bar).</input></pre> - <p>will make <c>fred</c>, <c>barney</c> and <c>bambam</c> - expand to <c>foo.bar.fred</c>, - <c>foo.bar.barney</c> and <c>foo.bar.bambam</c>, respectively.</p> - <p>Note: The compiler does not have an "import all" directive, for the - reason that Erlang has no compile time type checking. - E.g. if the wrong search - path is used at compile time, a call <c>m:f(...)</c> - could be expanded to <c>foo.bar.m:f(...)</c> - without any warning, instead of the intended - <c>frob.ozz.m:f(...)</c>, if - package <c>foo.bar</c> happens to be found first in the path. - Explicitly - declaring each use of a module makes for safe code.</p> - </description> -</erlref> - diff --git a/lib/kernel/doc/src/ref_man.xml b/lib/kernel/doc/src/ref_man.xml index 9ef0959271..67d91ba585 100644 --- a/lib/kernel/doc/src/ref_man.xml +++ b/lib/kernel/doc/src/ref_man.xml @@ -64,6 +64,5 @@ <xi:include href="zlib_stub.xml"/> <xi:include href="app.xml"/> <xi:include href="config.xml"/> - <xi:include href="packages.xml"/> </application> diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl index 9b7c4aa7b8..4e65883be7 100644 --- a/lib/kernel/src/application.erl +++ b/lib/kernel/src/application.erl @@ -23,7 +23,7 @@ which_applications/0, which_applications/1, loaded_applications/0, permit/2]). -export([set_env/3, set_env/4, unset_env/2, unset_env/3]). --export([get_env/1, get_env/2, get_all_env/0, get_all_env/1]). +-export([get_env/1, get_env/2, get_env/3, get_all_env/0, get_all_env/1]). -export([get_key/1, get_key/2, get_all_key/0, get_all_key/1]). -export([get_application/0, get_application/1, info/0]). -export([start_type/0]). @@ -264,6 +264,20 @@ get_env(Key) -> get_env(Application, Key) -> application_controller:get_env(Application, Key). +-spec get_env(Application, Par, Def) -> Val when + Application :: atom(), + Par :: atom(), + Def :: term(), + Val :: term(). + +get_env(Application, Key, Def) -> + case get_env(Application, Key) of + {ok, Val} -> + Val; + undefined -> + Def + end. + -spec get_all_env() -> Env when Env :: [{Par :: atom(), Val :: term()}]. diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index de3eaad5a1..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, @@ -490,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(), diff --git a/lib/kernel/src/file_io_server.erl b/lib/kernel/src/file_io_server.erl index acaffe1e41..fad2ed7fb3 100644 --- a/lib/kernel/src/file_io_server.erl +++ b/lib/kernel/src/file_io_server.erl @@ -211,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 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/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl index f469a0af98..2ca8840e1f 100644 --- a/lib/kernel/test/application_SUITE.erl +++ b/lib/kernel/test/application_SUITE.erl @@ -27,7 +27,7 @@ otp_1586/1, otp_2078/1, otp_2012/1, otp_2718/1, otp_2973/1, otp_3002/1, otp_3184/1, otp_4066/1, otp_4227/1, otp_5363/1, otp_5606/1, - start_phases/1, get_key/1, + start_phases/1, get_key/1, get_env/1, permit_false_start_local/1, permit_false_start_dist/1, script_start/1, nodedown_start/1, init2973/0, loop2973/0, loop5606/1]). @@ -49,7 +49,7 @@ all() -> [failover, failover_comp, permissions, load, load_use_cache, {group, reported_bugs}, start_phases, script_start, nodedown_start, permit_false_start_local, - permit_false_start_dist, get_key, + permit_false_start_dist, get_key, get_env, {group, distr_changed}, config_change, shutdown_func, shutdown_timeout]. groups() -> @@ -1503,6 +1503,15 @@ loop5606(Pid) -> Pid ! {self(), Res} end. +get_env(suite) -> []; +get_env(doc) -> + ["Tests get_env/* functions"]; +get_env(Conf) when is_list(Conf) -> + {ok, _} = application:get_env(kernel, error_logger), + undefined = application:get_env(undefined_app, a), + undefined = application:get_env(kernel, error_logger_xyz), + default = application:get_env(kernel, error_logger_xyz, default), + ok. %%----------------------------------------------------------------- %% Should be started in a CC view with: diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 9c507fd437..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, @@ -1617,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. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl index b40c50f79f..9428a38660 100644 --- a/lib/kernel/test/global_SUITE.erl +++ b/lib/kernel/test/global_SUITE.erl @@ -91,27 +91,9 @@ end_per_group(_GroupName, Config) -> Config. init_per_suite(Config) -> - - %% Copied from test_server_ctrl ln 647, we have to do this here as - %% the test_server only does this when run without common_test - global:sync(), - case global:whereis_name(test_server) of - undefined -> - io:format(user, "Registering test_server globally!~n",[]), - global:register_name(test_server, whereis(test_server_ctrl)); - Pid -> - case node() of - N when N == node(Pid) -> - io:format(user, "Warning: test_server already running!\n", []), - global:re_register_name(test_server,self()); - _ -> - ok - end - end, Config. end_per_suite(_Config) -> - global:unregister_name(test_server), ok. @@ -135,8 +117,7 @@ end_per_testcase(_Case, Config) -> ?line write_high_level_trace(Config), ?line _ = gen_server:call(global_name_server, high_level_trace_stop, infinity), - ?line[global:unregister_name(N) || N <- global:registered_names(), - N =/= test_server], + [global:unregister_name(N) || N <- global:registered_names()], ?line InitRegistered = ?registered, ?line Registered = registered(), ?line [io:format("~s local names: ~p~n", [What, N]) || @@ -1840,16 +1821,16 @@ do_otp_3162(StartFun, Config) -> ?line ?UNTIL ([Cp3] =:= lists:sort(rpc:call(Cp1, erlang, nodes, [])) -- [node()]), - ?line ?UNTIL([kalle, test_server, vera] =:= + ?UNTIL([kalle, vera] =:= lists:sort(rpc:call(Cp1, global, registered_names, []))), ?line ?UNTIL ([Cp3] =:= lists:sort(rpc:call(Cp2, erlang, nodes, [])) -- [node()]), - ?line ?UNTIL([stina, test_server, vera] =:= + ?UNTIL([stina, vera] =:= lists:sort(rpc:call(Cp2, global, registered_names, []))), ?line ?UNTIL ([Cp1, Cp2] =:= lists:sort(rpc:call(Cp3, erlang, nodes, [])) -- [node()]), - ?line ?UNTIL([kalle, stina, test_server, vera] =:= + ?UNTIL([kalle, stina, vera] =:= lists:sort(rpc:call(Cp3, global, registered_names, []))), ?line pong = rpc:call(Cp2, net_adm, ping, [Cp1]), @@ -1860,17 +1841,17 @@ do_otp_3162(StartFun, Config) -> ?line ?UNTIL(begin NN = lists:sort(rpc:call(Cp1, global, registered_names, [])), - [kalle, stina, test_server, vera] =:= NN + [kalle, stina, vera] =:= NN end), ?line ?UNTIL ([Cp1, Cp3] =:= lists:sort(rpc:call(Cp2, erlang, nodes, [])) -- [node()]), - ?line ?UNTIL([kalle, stina, test_server, vera] =:= + ?UNTIL([kalle, stina, vera] =:= lists:sort(rpc:call(Cp2, global, registered_names, []))), ?line ?UNTIL ([Cp1, Cp2] =:= lists:sort(rpc:call(Cp3, erlang, nodes, [])) -- [node()]), - ?line ?UNTIL([kalle, stina, test_server, vera] =:= + ?UNTIL([kalle, stina, vera] =:= lists:sort(rpc:call(Cp3, global, registered_names, []))), write_high_level_trace(Config), @@ -4154,7 +4135,7 @@ init_condition(Config) -> {"Global Locks (ETS)", global_locks}, {"Global Pid Names (ETS)", global_pid_names}, {"Global Pid Ids (ETS)", global_pid_ids}]], - ?UNTIL([test_server] =:= global:registered_names()), + ?UNTIL([] =:= global:registered_names()), ?UNTIL([] =:= nodes()), ?UNTIL([node()] =:= get_known(node())), ok. diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index a56746bbc4..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]}, @@ -1359,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) -> |