diff options
Diffstat (limited to 'lib/kernel')
99 files changed, 5615 insertions, 4180 deletions
diff --git a/lib/kernel/doc/specs/.gitignore b/lib/kernel/doc/specs/.gitignore new file mode 100644 index 0000000000..322eebcb06 --- /dev/null +++ b/lib/kernel/doc/specs/.gitignore @@ -0,0 +1 @@ +specs_*.xml diff --git a/lib/kernel/doc/src/Makefile b/lib/kernel/doc/src/Makefile index f8c1cac8b3..214e994889 100644 --- a/lib/kernel/doc/src/Makefile +++ b/lib/kernel/doc/src/Makefile @@ -1,19 +1,20 @@ -# ``The contents of this file are subject to the Erlang Public License, +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in # 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 via the world wide web at http://www.erlang.org/. -# +# 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. -# -# The Initial Developer of the Original Code is Ericsson Utvecklings AB. -# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings -# AB. All Rights Reserved.'' -# -# $Id$ +# +# %CopyrightEnd% # include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk @@ -94,19 +95,26 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf +SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml) + +TOP_SPECS_FILE = specs.xml # ---------------------------------------------------- # FLAGS # ---------------------------------------------------- XML_FLAGS += +SPECS_ESRC = ../../src + +SPECS_FLAGS = -I../../include + # ---------------------------------------------------- # Targets # ---------------------------------------------------- $(HTMLDIR)/%.gif: %.gif $(INSTALL_DATA) $< $@ -docs: pdf html man +docs: man pdf html $(TOP_PDF_FILE): $(XML_FILES) @@ -125,8 +133,22 @@ clean clean_docs: rm -f $(MAN4DIR)/* rm -f $(MAN6DIR)/* rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo) + rm -f $(SPECDIR)/* rm -f errs core *~ +$(SPECDIR)/specs_erl_prim_loader_stub.xml: + escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ + -o$(dir $@) -module erl_prim_loader_stub +$(SPECDIR)/specs_erlang_stub.xml: + escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ + -o$(dir $@) -module erlang_stub +$(SPECDIR)/specs_init_stub.xml: + escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ + -o$(dir $@) -module init_stub +$(SPECDIR)/specs_zlib_stub.xml: + escript $(SPECS_EXTRACTOR) $(SPECS_FLAGS) \ + -o$(dir $@) -module zlib_stub + # ---------------------------------------------------- # Release Target # ---------------------------------------------------- diff --git a/lib/kernel/doc/src/app.xml b/lib/kernel/doc/src/app.xml index ef1f5985f4..ff8a12fe97 100644 --- a/lib/kernel/doc/src/app.xml +++ b/lib/kernel/doc/src/app.xml @@ -4,7 +4,7 @@ <fileref> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -170,7 +170,6 @@ Phases [{Phase,PhaseArgs}] undefined start phase defined by the <c>start_phases</c> key, and only after this extended start procedure will <c>application:start(Application)</c> return.</p> - <p></p> <p>Start phases may be used to synchronize startup of an application and its included applications. In this case, the <c>mod</c> key must be specified as:</p> @@ -182,7 +181,6 @@ Phases [{Phase,PhaseArgs}] undefined for the primary application) both for the primary application and for each of its included application, for which the start phase is defined.</p> - <p></p> <p>This implies that for an included application, the set of start phases must be a subset of the set of phases defined for the primary application. Refer to <em>OTP Design Principles</em> for more information.</p> diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml index 47d578a339..51a3311ec2 100644 --- a/lib/kernel/doc/src/application.xml +++ b/lib/kernel/doc/src/application.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2010</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -50,20 +50,27 @@ <p>Refer to <seealso marker="doc/design_principles:des_princ">OTP Design Principles</seealso> for more information about applications and behaviours.</p> </description> + <datatypes> + <datatype> + <name name="start_type"/> + </datatype> + <datatype> + <name name="restart_type"/> + </datatype> + <datatype> + <!-- Parameterized opaque types are NYI: --> + <name><marker id="type-tuple_of">tuple_of(T)</marker></name> + <desc><p>A tuple where the elements are of type <c>T</c>.</p></desc> + </datatype> + </datatypes> <funcs> <func> - <name>get_all_env() -> Env</name> - <name>get_all_env(Application) -> Env</name> + <name name="get_all_env" arity="0"/> + <name name="get_all_env" arity="1"/> <fsummary>Get the configuration parameters for an application</fsummary> - <type> - <v>Application = atom()</v> - <v>Env = [{Par,Val}]</v> - <v> Par = atom()</v> - <v> Val = term()</v> - </type> <desc> <p>Returns the configuration parameters and their values for - <c>Application</c>. If the argument is omitted, it defaults to + <c><anno>Application</anno></c>. If the argument is omitted, it defaults to the application of the calling process.</p> <p>If the specified application is not loaded, or if the process executing the call does not belong to any application, @@ -71,18 +78,12 @@ </desc> </func> <func> - <name>get_all_key() -> {ok, Keys} | []</name> - <name>get_all_key(Application) -> {ok, Keys} | undefined </name> + <name name="get_all_key" arity="0"/> + <name name="get_all_key" arity="1"/> <fsummary>Get the application specification keys</fsummary> - <type> - <v>Application = atom()</v> - <v>Keys = [{Key,Val}]</v> - <v> Key = atom()</v> - <v> Val = term()</v> - </type> <desc> <p>Returns the application specification keys and their values - for <c>Application</c>. If the argument is omitted, it + for <c><anno>Application</anno></c>. If the argument is omitted, it defaults to the application of the calling process.</p> <p>If the specified application is not loaded, the function returns <c>undefined</c>. If the process executing the call @@ -91,17 +92,12 @@ </desc> </func> <func> - <name>get_application() -> {ok, Application} | undefined</name> - <name>get_application(Pid | Module) -> {ok, Application} | undefined</name> + <name name="get_application" arity="0"/> + <name name="get_application" arity="1"/> <fsummary>Get the name of an application containing a certain process or module</fsummary> - <type> - <v>Pid = pid()</v> - <v>Module = atom()</v> - <v>Application = atom()</v> - </type> <desc> <p>Returns the name of the application to which the process - <c>Pid</c> or the module <c>Module</c> belongs. Providing no + <c><anno>Pid</anno></c> or the module <c><anno>Module</anno></c> belongs. Providing no argument is the same as calling <c>get_application(self())</c>.</p> <p>If the specified process does not belong to any application, @@ -110,17 +106,12 @@ </desc> </func> <func> - <name>get_env(Par) -> {ok, Val} | undefined</name> - <name>get_env(Application, Par) -> {ok, Val} | undefined</name> + <name name="get_env" arity="1"/> + <name name="get_env" arity="2"/> <fsummary>Get the value of a configuration parameter</fsummary> - <type> - <v>Application = atom()</v> - <v>Par = atom()</v> - <v>Val = term()</v> - </type> <desc> - <p>Returns the value of the configuration parameter <c>Par</c> - for <c>Application</c>. If the application argument is + <p>Returns the value of the configuration parameter <c><anno>Par</anno></c> + for <c><anno>Application</anno></c>. If the application argument is omitted, it defaults to the application of the calling process.</p> <p>If the specified application is not loaded, or @@ -130,17 +121,12 @@ </desc> </func> <func> - <name>get_key(Key) -> {ok, Val} | undefined</name> - <name>get_key(Application, Key) -> {ok, Val} | undefined</name> + <name name="get_key" arity="1"/> + <name name="get_key" arity="2"/> <fsummary>Get the value of an application specification key</fsummary> - <type> - <v>Application = atom()</v> - <v>Key = atom()</v> - <v>Val = term()</v> - </type> <desc> <p>Returns the value of the application specification key - <c>Key</c> for <c>Application</c>. If the application + <c><anno>Key</anno></c> for <c><anno>Application</anno></c>. If the application argument is omitted, it defaults to the application of the calling process.</p> <p>If the specified application is not loaded, or @@ -150,45 +136,35 @@ </desc> </func> <func> - <name>load(AppDescr) -> ok | {error, Reason}</name> - <name>load(AppDescr, Distributed) -> ok | {error, Reason}</name> + <name name="load" arity="1"/> + <name name="load" arity="2"/> <fsummary>Load an application</fsummary> - <type> - <v>AppDescr = Application | AppSpec</v> - <v> Application = atom()</v> - <v> AppSpec = {application,Application,AppSpecKeys}</v> - <v> AppSpec = [{Key,Val}]</v> - <v> Key = atom()</v> - <v> Val = term()</v> - <v>Distributed = {Application,Nodes} | {Application,Time,Nodes} | default</v> - <v> Nodes = [node() | {node(),..,node()}]</v> - <v> Time = integer() > 0</v> - <v>Reason = term()</v> - </type> + <type name="application_spec"/> + <type name="application_opt"/> <desc> <p>Loads the application specification for an application into the application controller. It will also load the application specifications for any included applications. Note that the function does not load the actual Erlang object code.</p> - <p>The application can be given by its name <c>Application</c>. + <p>The application can be given by its name <c><anno>Application</anno></c>. In this case the application controller will search the code - path for the application resource file <c>Application.app</c> + path for the application resource file <c><anno>Application</anno>.app</c> and load the specification it contains.</p> <p>The application specification can also be given directly as a - tuple <c>AppSpec</c>. This tuple should have the format and + tuple <c><anno>AppSpec</anno></c>. This tuple should have the format and contents as described in <c>app(4)</c>.</p> - <p>If <c>Distributed == {Application,[Time,]Nodes}</c>, + <p>If <c><anno>Distributed</anno> == {<anno>Application</anno>,[<anno>Time</anno>,]<anno>Nodes</anno>}</c>, the application will be distributed. The argument overrides the value for the application in the Kernel configuration - parameter <c>distributed</c>. <c>Application</c> must be + parameter <c>distributed</c>. <c><anno>Application</anno></c> must be the name of the application (same as in the first argument). - If a node crashes and <c>Time</c> has been specified, then - the application controller will wait for <c>Time</c> + If a node crashes and <c><anno>Time</anno></c> has been specified, then + the application controller will wait for <c><anno>Time</anno></c> milliseconds before attempting to restart the application on - another node. If <c>Time</c> is not specified, it will + another node. If <c><anno>Time</anno></c> is not specified, it will default to 0 and the application will be restarted immediately.</p> - <p><c>Nodes</c> is a list of node names where the application + <p><c><anno>Nodes</anno></c> is a list of node names where the application may run, in priority from left to right. Node names can be grouped using tuples to indicate that they have the same priority. Example:</p> @@ -204,32 +180,22 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>loaded_applications() -> [{Application, Description, Vsn}]</name> + <name name="loaded_applications" arity="0"/> <fsummary>Get the currently loaded applications</fsummary> - <type> - <v>Application = atom()</v> - <v>Description = string()</v> - <v>Vsn = string()</v> - </type> <desc> <p>Returns a list with information about the applications which have been loaded using <c>load/1,2</c>, also included - applications. <c>Application</c> is the application name. - <c>Description</c> and <c>Vsn</c> are the values of its + applications. <c><anno>Application</anno></c> is the application name. + <c><anno>Description</anno></c> and <c><anno>Vsn</anno></c> are the values of its <c>description</c> and <c>vsn</c> application specification keys, respectively.</p> </desc> </func> <func> - <name>permit(Application, Bool) -> ok | {error, Reason}</name> + <name name="permit" arity="2"/> <fsummary>Change an application's permission to run on a node.</fsummary> - <type> - <v>Application = atom()</v> - <v>Bool = bool()</v> - <v>Reason = term()</v> - </type> <desc> - <p>Changes the permission for <c>Application</c> to run at + <p>Changes the permission for <c><anno>Application</anno></c> to run at the current node. The application must have been loaded using <c>load/1,2</c> for the function to have effect.</p> <p>If the permission of a loaded, but not started, application @@ -258,20 +224,14 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>set_env(Application, Par, Val) -> ok</name> - <name>set_env(Application, Par, Val, Timeout) -> ok</name> + <name name="set_env" arity="3"/> + <name name="set_env" arity="4"/> <fsummary>Set the value of a configuration parameter</fsummary> - <type> - <v>Application = atom()</v> - <v>Par = atom()</v> - <v>Val = term()</v> - <v>Timeout = int() | infinity</v> - </type> <desc> - <p>Sets the value of the configuration parameter <c>Par</c> for - <c>Application</c>.</p> + <p>Sets the value of the configuration parameter <c><anno>Par</anno></c> for + <c><anno>Application</anno></c>.</p> <p><c>set_env/3</c> uses the standard <c>gen_server</c> timeout - value (5000 ms). A <c>Timeout</c> argument can be provided + value (5000 ms). A <c><anno>Timeout</anno></c> argument can be provided if another timeout value is useful, for example, in situations where the application controller is heavily loaded.</p> <warning> @@ -285,20 +245,15 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>start(Application) -> ok | {error, Reason}</name> - <name>start(Application, Type) -> ok | {error, Reason}</name> + <name name="start" arity="1"/> + <name name="start" arity="2"/> <fsummary>Load and start an application</fsummary> - <type> - <v>Application = atom()</v> - <v>Type = permanent | transient | temporary</v> - <v>Reason = term()</v> - </type> <desc> - <p>Starts <c>Application</c>. If it is not loaded, + <p>Starts <c><anno>Application</anno></c>. If it is not loaded, the application controller will first load it using <c>load/1</c>. It will make sure any included applications are loaded, but will not start them. That is assumed to be - taken care of in the code for <c>Application</c>.</p> + taken care of in the code for <c><anno>Application</anno></c>.</p> <p>The application controller checks the value of the application specification key <c>applications</c>, to ensure that all applications that should be started before @@ -310,7 +265,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> The application master starts the application by calling the application callback function <c>Module:start/2</c> as defined by the application specification key <c>mod</c>.</p> - <p>The <c>Type</c> argument specifies the type of + <p>The <c><anno>Type</anno></c> argument specifies the type of the application. If omitted, it defaults to <c>temporary</c>.</p> <list type="bulleted"> <item>If a permanent application terminates, all other @@ -331,19 +286,15 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>start_type() -> StartType | local | undefined</name> + <name name="start_type" arity="0"/> <fsummary>Get the start type of an ongoing application startup.</fsummary> - <type> - <v>StartType = normal | {takeover,Node} | {failover,Node}</v> - <v> Node = node()</v> - </type> <desc> <p>This function is intended to be called by a process belonging to an application, when the application is being started, to - determine the start type which is either <c>StartType</c> or + determine the start type which is either <c><anno>StartType</anno></c> or <c>local</c>.</p> - <p>See <c>Module:start/2</c> for a description of - <c>StartType</c>.</p> + <p>See <seealso marker="#start_type"><c>Module:start/2</c></seealso> for a description of + <c><anno>StartType</anno></c>.</p> <p><c>local</c> is returned if only parts of the application is being restarted (by a supervisor), or if the function is called outside a startup.</p> @@ -352,14 +303,10 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>stop(Application) -> ok | {error, Reason}</name> + <name name="stop" arity="1"/> <fsummary>Stop an application</fsummary> - <type> - <v>Application = atom()</v> - <v>Reason = term()</v> - </type> <desc> - <p>Stops <c>Application</c>. The application master calls + <p>Stops <c><anno>Application</anno></c>. The application master calls <c>Module:prep_stop/1</c>, if such a function is defined, and then tells the top supervisor of the application to shutdown (see <c>supervisor(3)</c>). This means that the entire @@ -384,16 +331,11 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>takeover(Application, Type) -> ok | {error, Reason}</name> + <name name="takeover" arity="2"/> <fsummary>Take over a distributed application</fsummary> - <type> - <v>Application = atom()</v> - <v>Type = permanent | transient | temporary</v> - <v>Reason = term()</v> - </type> <desc> <p>Performs a takeover of the distributed application - <c>Application</c>, which executes at another node + <c><anno>Application</anno></c>, which executes at another node <c>Node</c>. At the current node, the application is restarted by calling <c>Module:start({takeover,Node},StartArgs)</c>. <c>Module</c> @@ -413,14 +355,10 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>unload(Application) -> ok | {error, Reason}</name> + <name name="unload" arity="1"/> <fsummary>Unload an application</fsummary> - <type> - <v>Application = atom()</v> - <v>Reason = term()</v> - </type> <desc> - <p>Unloads the application specification for <c>Application</c> + <p>Unloads the application specification for <c><anno>Application</anno></c> from the application controller. It will also unload the application specifications for any included applications. Note that the function does not purge the actual Erlang @@ -428,19 +366,14 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>unset_env(Application, Par) -> ok</name> - <name>unset_env(Application, Par, Timeout) -> ok</name> + <name name="unset_env" arity="2"/> + <name name="unset_env" arity="3"/> <fsummary>Unset the value of a configuration parameter</fsummary> - <type> - <v>Application = atom()</v> - <v>Par = atom()</v> - <v>Timeout = int() | infinity</v> - </type> <desc> - <p>Removes the configuration parameter <c>Par</c> and its value - for <c>Application</c>.</p> + <p>Removes the configuration parameter <c><anno>Par</anno></c> and its value + for <c><anno>Application</anno></c>.</p> <p><c>unset_env/2</c> uses the standard <c>gen_server</c> - timeout value (5000 ms). A <c>Timeout</c> argument can be + timeout value (5000 ms). A <c><anno>Timeout</anno></c> argument can be provided if another timeout value is useful, for example, in situations where the application controller is heavily loaded.</p> <warning> @@ -454,23 +387,17 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>which_applications() -> [{Application, Description, Vsn}]</name> - <name>which_applications(Timeout) -> [{Application, Description, Vsn}]</name> + <name name="which_applications" arity="0"/> + <name name="which_applications" arity="1"/> <fsummary>Get the currently running applications</fsummary> - <type> - <v>Application = atom()</v> - <v>Description = string()</v> - <v>Vsn = string()</v> - <v>Timeout = int() | infinity</v> - </type> <desc> <p>Returns a list with information about the applications which - are currently running. <c>Application</c> is the application - name. <c>Description</c> and <c>Vsn</c> are the values of its + are currently running. <c><anno>Application</anno></c> is the application + name. <c><anno>Description</anno></c> and <c><anno>Vsn</anno></c> are the values of its <c>description</c> and <c>vsn</c> application specification keys, respectively.</p> <p><c>which_applications/0</c> uses the standard - <c>gen_server</c> timeout value (5000 ms). A <c>Timeout</c> + <c>gen_server</c> timeout value (5000 ms). A <c><anno>Timeout</anno></c> argument can be provided if another timeout value is useful, for example, in situations where the application controller is heavily loaded.</p> @@ -501,7 +428,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> structured according to the OTP design principles as a supervision tree, this means starting the top supervisor of the tree.</p> - <p><c>StartType</c> defines the type of start:</p> + <p><marker id="start_type"/><c>StartType</c> defines the type of start:</p> <list type="bulleted"> <item><c>normal</c> if it's a normal startup.</item> <item><c>normal</c> also if the application is distributed and @@ -532,8 +459,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> <fsummary>Extended start of an application</fsummary> <type> <v>Phase = atom()</v> - <v>StartType = normal | {takeover,Node} | {failover,Node}</v> - <v> Node = node()</v> + <v>StartType = <seealso marker="#type-start_type">start_type()</seealso></v> <v>PhaseArgs = term()</v> <v>Pid = pid()</v> <v>State = state()</v> diff --git a/lib/kernel/doc/src/auth.xml b/lib/kernel/doc/src/auth.xml index f53fc8b29a..15d9ef0fe4 100644 --- a/lib/kernel/doc/src/auth.xml +++ b/lib/kernel/doc/src/auth.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2009</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -34,29 +34,28 @@ Cookie system, refer to <seealso marker="doc/reference_manual:distributed">Distributed Erlang</seealso> in the Erlang Reference Manual.</p> </description> + <datatypes> + <datatype> + <name name="cookie"/> + </datatype> + </datatypes> <funcs> <func> - <name>is_auth(Node) -> yes | no</name> + <name name="is_auth" arity="1"/> <fsummary>Status of communication authorization (deprecated)</fsummary> - <type> - <v>Node = node()</v> - </type> <desc> - <p>Returns <c>yes</c> if communication with <c>Node</c> is - authorized. Note that a connection to <c>Node</c> will - be established in this case. Returns <c>no</c> if <c>Node</c> + <p>Returns <c>yes</c> if communication with <c><anno>Node</anno></c> is + authorized. Note that a connection to <c><anno>Node</anno></c> will + be established in this case. Returns <c>no</c> if <c><anno>Node</anno></c> does not exist or communication is not authorized (it has another cookie than <c>auth</c> thinks it has).</p> - <p>Use <seealso marker="net_adm#ping/1">net_adm:ping(Node)</seealso> + <p>Use <seealso marker="net_adm#ping/1">net_adm:ping(<anno>Node</anno>)</seealso> instead.</p> </desc> </func> <func> - <name>cookie() -> Cookie</name> + <name name="cookie" arity="0"/> <fsummary>Magic cookie for local node (deprecated)</fsummary> - <type> - <v>Cookie = atom()</v> - </type> <desc> <p>Use <seealso marker="erts:erlang#erlang:get_cookie/0">erlang:get_cookie()</seealso> @@ -64,16 +63,14 @@ </desc> </func> <func> - <name>cookie(TheCookie) -> true</name> + <name name="cookie" arity="1"/> <fsummary>Set the magic for the local node (deprecated)</fsummary> - <type> - <v>TheCookie = Cookie | [Cookie]</v> - <d>The cookie may also be given as a list with a single atom element</d> - <v> Cookie = atom()</v> - </type> + <type_desc variable="TheCookie"> + The cookie may also be given as a list with a single atom element. + </type_desc> <desc> <p>Use - <seealso marker="erts:erlang#erlang:set_cookie/2">erlang:set_cookie(node(), Cookie)</seealso> + <seealso marker="erts:erlang#erlang:set_cookie/2">erlang:set_cookie(node(), <anno>Cookie</anno>)</seealso> instead.</p> </desc> </func> @@ -82,7 +79,7 @@ <fsummary>Set the magic cookie for a node and verify authorization (deprecated)</fsummary> <type> <v>Node = node()</v> - <v>Cookie = atom()</v> + <v>Cookie = <seealso marker="#type-cookie">cookie()</seealso></v> </type> <desc> <p>Equivalent to @@ -90,18 +87,14 @@ </desc> </func> <func> - <name>node_cookie(Node, Cookie) -> yes | no</name> + <name name="node_cookie" arity="2"/> <fsummary>Set the magic cookie for a node and verify authorization (deprecated)</fsummary> - <type> - <v>Node = node()</v> - <v>Cookie = atom()</v> - </type> <desc> - <p>Sets the magic cookie of <c>Node</c> to <c>Cookie</c>, and + <p>Sets the magic cookie of <c><anno>Node</anno></c> to <c><anno>Cookie</anno></c>, and verifies the status of the authorization. Equivalent to calling - <seealso marker="erts:erlang#erlang:set_cookie/2">erlang:set_cookie(Node, Cookie)</seealso>, followed by - <seealso marker="#is_auth/1">auth:is_auth(Node)</seealso>.</p> + <seealso marker="erts:erlang#erlang:set_cookie/2">erlang:set_cookie(<anno>Node</anno>, <anno>Cookie</anno>)</seealso>, followed by + <seealso marker="#is_auth/1">auth:is_auth(<anno>Node</anno>)</seealso>.</p> </desc> </func> </funcs> diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml index 4b8f934df1..6b89711924 100644 --- a/lib/kernel/doc/src/code.xml +++ b/lib/kernel/doc/src/code.xml @@ -177,9 +177,9 @@ archives. But the functions in <c>erl_prim_loader</c> may also be used by other applications to read files from archives. For example, the call - <c>erl_prim_loader:list_dir("/otp/root/lib/mnesia-4.4.7.ez/mnesia-4.4.7/examples/bench)"</c> + <c>erl_prim_loader:list_dir( "/otp/root/lib/mnesia-4.4.7.ez/mnesia-4.4.7/examples/bench)"</c> would list the contents of a directory inside an archive. - See <seealso marker="erts:erl_prim_loader">erl_prim_loader(3)</seealso></p> + See <seealso marker="erts:erl_prim_loader">erl_prim_loader(3)</seealso></p>. <p>An application archive file and a regular application directory may coexist. This may be useful when there is a need of having @@ -286,192 +286,158 @@ given to <c>set_path/1</c>.</p> </section> + <datatypes> + <datatype> + <name name="load_ret"/> + </datatype> + <datatype> + <name name="load_error_rsn"/> + </datatype> + </datatypes> + <funcs> <func> - <name>set_path(Path) -> true | {error, What}</name> + <name name="set_path" arity="1"/> <fsummary>Set the code server search path</fsummary> - <type> - <v>Path = [Dir]</v> - <v>Dir = string()</v> - <v>What = bad_directory | bad_path</v> - </type> <desc> - <p>Sets the code path to the list of directories <c>Path</c>.</p> + <p>Sets the code path to the list of directories <c><anno>Path</anno></c>.</p> <p>Returns <c>true</c> if successful, or - <c>{error, bad_directory}</c> if any <c>Dir</c> is not + <c>{error, bad_directory}</c> if any <c><anno>Dir</anno></c> is not the name of a directory, or <c>{error, bad_path}</c> if the argument is invalid.</p> </desc> </func> <func> - <name>get_path() -> Path</name> + <name name="get_path" arity="0"/> <fsummary>Return the code server search path</fsummary> - <type> - <v>Path = [Dir]</v> - <v>Dir = string()</v> - </type> <desc> <p>Returns the code path</p> </desc> </func> <func> - <name>add_path(Dir) -> true | {error, What}</name> - <name>add_pathz(Dir) -> true | {error, What}</name> + <name name="add_path" arity="1"/> + <name name="add_pathz" arity="1"/> <fsummary>Add a directory to the end of the code path</fsummary> - <type> - <v>Dir = string()</v> - <v>What = bad_directory</v> - </type> + <type name="add_path_ret"/> <desc> - <p>Adds <c>Dir</c> to the code path. The directory is added as - the last directory in the new path. If <c>Dir</c> already + <p>Adds <c><anno>Dir</anno></c> to the code path. The directory is added as + the last directory in the new path. If <c><anno>Dir</anno></c> already exists in the path, it is not added.</p> <p>Returns <c>true</c> if successful, or - <c>{error, bad_directory}</c> if <c>Dir</c> is not the name + <c>{error, bad_directory}</c> if <c><anno>Dir</anno></c> is not the name of a directory.</p> </desc> </func> <func> - <name>add_patha(Dir) -> true | {error, What}</name> + <name name="add_patha" arity="1"/> <fsummary>Add a directory to the beginning of the code path</fsummary> - <type> - <v>Dir = string()</v> - <v>What = bad_directory</v> - </type> + <type name="add_path_ret"/> <desc> - <p>Adds <c>Dir</c> to the beginning of the code path. If - <c>Dir</c> already exists, it is removed from the old + <p>Adds <c><anno>Dir</anno></c> to the beginning of the code path. If + <c><anno>Dir</anno></c> already exists, it is removed from the old position in the code path.</p> <p>Returns <c>true</c> if successful, or - <c>{error, bad_directory}</c> if <c>Dir</c> is not the name + <c>{error, bad_directory}</c> if <c><anno>Dir</anno></c> is not the name of a directory.</p> </desc> </func> <func> - <name>add_paths(Dirs) -> ok</name> - <name>add_pathsz(Dirs) -> ok</name> + <name name="add_paths" arity="1"/> + <name name="add_pathsz" arity="1"/> <fsummary>Add directories to the end of the code path</fsummary> - <type> - <v>Dirs = [Dir]</v> - <v>Dir = string()</v> - </type> <desc> - <p>Adds the directories in <c>Dirs</c> to the end of the code - path. If a <c>Dir</c> already exists, it is not added. This + <p>Adds the directories in <c><anno>Dirs</anno></c> to the end of the code + path. If a <c><anno>Dir</anno></c> already exists, it is not added. This function always returns <c>ok</c>, regardless of the validity - of each individual <c>Dir</c>.</p> + of each individual <c><anno>Dir</anno></c>.</p> </desc> </func> <func> - <name>add_pathsa(Dirs) -> ok</name> + <name name="add_pathsa" arity="1"/> <fsummary>Add directories to the beginning of the code path</fsummary> - <type> - <v>Dirs = [Dir]</v> - <v>Dir = string()</v> - </type> <desc> - <p>Adds the directories in <c>Dirs</c> to the beginning of - the code path. If a <c>Dir</c> already exists, it is removed + <p>Adds the directories in <c><anno>Dirs</anno></c> to the beginning of + the code path. If a <c><anno>Dir</anno></c> already exists, it is removed from the old position in the code path. This function always returns <c>ok</c>, regardless of the validity of each - individual <c>Dir</c>.</p> + individual <c><anno>Dir</anno></c>.</p> </desc> </func> <func> - <name>del_path(Name | Dir) -> true | false | {error, What}</name> + <name name="del_path" arity="1"/> <fsummary>Delete a directory from the code path</fsummary> - <type> - <v>Name = atom()</v> - <v>Dir = string()</v> - <v>What = bad_name</v> - </type> <desc> <p>Deletes a directory from the code path. The argument can be - an atom <c>Name</c>, in which case the directory with - the name <c>.../Name[-Vsn][/ebin]</c> is deleted from the code + an atom <c><anno>Name</anno></c>, in which case the directory with + the name <c>.../<anno>Name</anno>[-Vsn][/ebin]</c> is deleted from the code path. It is also possible to give the complete directory name - <c>Dir</c> as argument.</p> + <c><anno>Dir</anno></c> as argument.</p> <p>Returns <c>true</c> if successful, or <c>false</c> if the directory is not found, or <c>{error, bad_name}</c> if the argument is invalid.</p> </desc> </func> <func> - <name>replace_path(Name, Dir) -> true | {error, What}</name> + <name name="replace_path" arity="2"/> <fsummary>Replace a directory with another in the code path</fsummary> - <type> - <v>Name = atom()</v> - <v>Dir = string()</v> - <v>What = bad_name | bad_directory | {badarg, term()}</v> - </type> <desc> <p>This function replaces an old occurrence of a directory - named <c>.../Name[-Vsn][/ebin]</c>, in the code path, with - <c>Dir</c>. If <c>Name</c> does not exist, it adds the new - directory <c>Dir</c> last in the code path. The new directory - must also be named <c>.../Name[-Vsn][/ebin]</c>. This function + named <c>.../<anno>Name</anno>[-Vsn][/ebin]</c>, in the code path, with + <c><anno>Dir</anno></c>. If <c><anno>Name</anno></c> does not exist, it adds the new + directory <c><anno>Dir</anno></c> last in the code path. The new directory + must also be named <c>.../<anno>Name</anno>[-Vsn][/ebin]</c>. This function should be used if a new version of the directory (library) is added to a running system.</p> <p>Returns <c>true</c> if successful, or - <c>{error, bad_name}</c> if <c>Name</c> is not found, or - <c>{error, bad_directory}</c> if <c>Dir</c> does not exist, or - <c>{error, {badarg, [Name, Dir]}}</c> if <c>Name</c> or - <c>Dir</c> is invalid.</p> + <c>{error, bad_name}</c> if <c><anno>Name</anno></c> is not found, or + <c>{error, bad_directory}</c> if <c><anno>Dir</anno></c> does not exist, or + <c>{error, {badarg, [<anno>Name</anno>, <anno>Dir</anno>]}}</c> if <c><anno>Name</anno></c> or + <c><anno>Dir</anno></c> is invalid.</p> </desc> </func> <func> - <name>load_file(Module) -> {module, Module} | {error, What}</name> + <name name="load_file" arity="1"/> <fsummary>Load a module</fsummary> - <type> - <v>Module = atom()</v> - <v>What = nofile | sticky_directory | badarg | term()</v> - </type> + <type name="load_ret"/> <desc> - <p>Tries to load the Erlang module <c>Module</c>, using + <p>Tries to load the Erlang module <c><anno>Module</anno></c>, using the code path. It looks for the object code file with an extension that corresponds to the Erlang machine used, for - example <c>Module.beam</c>. The loading fails if the module + example <c><anno>Module</anno>.beam</c>. The loading fails if the module name found in the object code differs from the name - <c>Module</c>. + <c><anno>Module</anno></c>. <seealso marker="#load_binary/3">load_binary/3</seealso> must be used to load object code with a module name that is different from the file name.</p> - <p>Returns <c>{module, Module}</c> if successful, or + <p>Returns <c>{module, <anno>Module</anno>}</c> if successful, or <c>{error, nofile}</c> if no object code is found, or <c>{error, sticky_directory}</c> if the object code resides in - a sticky directory, or <c>{error, badarg}</c> if the argument - is invalid. Also if the loading fails, an error tuple is + a sticky directory. Also if the loading fails, an error tuple is returned. See <seealso marker="erts:erlang#load_module/2">erlang:load_module/2</seealso> - for possible values of <c>What</c>.</p> + for possible values of <c><anno>What</anno></c>.</p> </desc> </func> <func> - <name>load_abs(Filename) -> {module, Module} | {error, What}</name> + <name name="load_abs" arity="1"/> <fsummary>Load a module, residing in a given file</fsummary> - <type> - <v>Filename = string()</v> - <v>Module = atom()</v> - <v>What = nofile | sticky_directory | badarg | term()</v> - </type> + <type name="load_ret"/> + <type name="loaded_filename"/> + <type name="loaded_ret_atoms"/> <desc> - <p>Does the same as <c>load_file(Module)</c>, but - <c>Filename</c> is either an absolute file name, or a + <p>Does the same as <c>load_file(<anno>Module</anno>)</c>, but + <c><anno>Filename</anno></c> is either an absolute file name, or a relative file name. The code path is not searched. It returns a value in the same way as <seealso marker="#load_file/1">load_file/1</seealso>. Note - that <c>Filename</c> should not contain the extension (for + that <c><anno>Filename</anno></c> should not contain the extension (for example <c>".beam"</c>); <c>load_abs/1</c> adds the correct extension itself.</p> </desc> </func> <func> - <name>ensure_loaded(Module) -> {module, Module} | {error, What}</name> + <name name="ensure_loaded" arity="1"/> <fsummary>Ensure that a module is loaded</fsummary> - <type> - <v>Module = atom()</v> - <v>What = nofile | sticky_directory | embedded | badarg | term()</v> - </type> <desc> <p>Tries to to load a module in the same way as <seealso marker="#load_file/1">load_file/1</seealso>, @@ -481,54 +447,45 @@ </desc> </func> <func> - <name>load_binary(Module, Filename, Binary) -> {module, Module} | {error, What}</name> + <name name="load_binary" arity="3"/> <fsummary>Load object code for a module</fsummary> - <type> - <v>Module = atom()</v> - <v>Filename = string()</v> - <v>What = sticky_directory | badarg | term()</v> - </type> + <type name="loaded_filename"/> + <type name="loaded_ret_atoms"/> <desc> <p>This function can be used to load object code on remote - Erlang nodes. The argument <c>Binary</c> must contain - object code for <c>Module</c>. - <c>Filename</c> is only used by the code server to keep a - record of from which file the object code for <c>Module</c> - comes. Accordingly, <c>Filename</c> is not opened and read by + Erlang nodes. The argument <c><anno>Binary</anno></c> must contain + object code for <c><anno>Module</anno></c>. + <c><anno>Filename</anno></c> is only used by the code server to keep a + record of from which file the object code for <c><anno>Module</anno></c> + comes. Accordingly, <c><anno>Filename</anno></c> is not opened and read by the code server.</p> - <p>Returns <c>{module, Module}</c> if successful, or + <p>Returns <c>{module, <anno>Module</anno>}</c> if successful, or <c>{error, sticky_directory}</c> if the object code resides in a sticky directory, or <c>{error, badarg}</c> if any argument is invalid. Also if the loading fails, an error tuple is returned. See <seealso marker="erts:erlang#load_module/2">erlang:load_module/2</seealso> - for possible values of <c>What</c>.</p> + for possible values of <c><anno>What</anno></c>.</p> </desc> </func> <func> - <name>delete(Module) -> true | false</name> + <name name="delete" arity="1"/> <fsummary>Removes current code for a module</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> - <p>Removes the current code for <c>Module</c>, that is, - the current code for <c>Module</c> is made old. This means + <p>Removes the current code for <c><anno>Module</anno></c>, that is, + the current code for <c><anno>Module</anno></c> is made old. This means that processes can continue to execute the code in the module, but that no external function calls can be made to it.</p> <p>Returns <c>true</c> if successful, or <c>false</c> if there - is old code for <c>Module</c> which must be purged first, or - if <c>Module</c> is not a (loaded) module.</p> + is old code for <c><anno>Module</anno></c> which must be purged first, or + if <c><anno>Module</anno></c> is not a (loaded) module.</p> </desc> </func> <func> - <name>purge(Module) -> true | false</name> + <name name="purge" arity="1"/> <fsummary>Removes old code for a module</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> - <p>Purges the code for <c>Module</c>, that is, removes code + <p>Purges the code for <c><anno>Module</anno></c>, that is, removes code marked as old. If some processes still linger in the old code, these processes are killed before the code is removed.</p> <p>Returns <c>true</c> if successful and any process needed to @@ -536,31 +493,26 @@ </desc> </func> <func> - <name>soft_purge(Module) -> true | false</name> + <name name="soft_purge" arity="1"/> <fsummary>Removes old code for a module, unless no process uses it</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> - <p>Purges the code for <c>Module</c>, that is, removes code + <p>Purges the code for <c><anno>Module</anno></c>, that is, removes code marked as old, but only if no processes linger in it.</p> <p>Returns <c>false</c> if the module could not be purged due to processes lingering in old code, otherwise <c>true</c>.</p> </desc> </func> <func> - <name>is_loaded(Module) -> {file, Loaded} | false</name> + <name name="is_loaded" arity="1"/> <fsummary>Check if a module is loaded</fsummary> - <type> - <v>Module = atom()</v> - <v>Loaded = Absname | preloaded | cover_compiled</v> - <v>Absname = string()</v> - </type> - <desc> - <p>Checks if <c>Module</c> is loaded. If it is, - <c>{file, Loaded}</c> is returned, otherwise <c>false</c>.</p> - <p>Normally, <c>Loaded</c> is the absolute file name - <c>Absname</c> from which the code was obtained. If the module + <type name="loaded_filename"/> + <type name="loaded_ret_atoms"/> + <type_desc name="loaded_filename"><c><anno>Filename</anno></c> is an absolute filename</type_desc> + <desc> + <p>Checks if <c><anno>Module</anno></c> is loaded. If it is, + <c>{file, <anno>Loaded</anno>}</c> is returned, otherwise <c>false</c>.</p> + <p>Normally, <c><anno>Loaded</anno></c> is the absolute file name + <c>Filename</c> from which the code was obtained. If the module is preloaded (see <seealso marker="sasl:script">script(4)</seealso>), <c>Loaded==preloaded</c>. If the module is Cover compiled (see @@ -569,32 +521,26 @@ </desc> </func> <func> - <name>all_loaded() -> [{Module, Loaded}]</name> + <name name="all_loaded" arity="0"/> <fsummary>Get all loaded modules</fsummary> - <type> - <v>Module = atom()</v> - <v>Loaded = Absname | preloaded | cover_compiled</v> - <v>Absname = string()</v> - </type> + <type name="loaded_filename"/> + <type name="loaded_ret_atoms"/> + <type_desc name="loaded_filename"><c><anno>Filename</anno></c> is an absolute filename</type_desc> <desc> - <p>Returns a list of tuples <c>{Module, Loaded}</c> for all - loaded modules. <c>Loaded</c> is normally the absolute file + <p>Returns a list of tuples <c>{<anno>Module</anno>, <anno>Loaded</anno>}</c> for all + loaded modules. <c><anno>Loaded</anno></c> is normally the absolute file name, as described for <seealso marker="#is_loaded/1">is_loaded/1</seealso>.</p> </desc> </func> <func> - <name>which(Module) -> Which</name> + <name name="which" arity="1"/> <fsummary>The object code file of a module</fsummary> - <type> - <v>Module = atom()</v> - <v>Which = Filename | non_existing | preloaded | cover_compiled</v> - <v>Filename = string()</v> - </type> + <type name="loaded_ret_atoms"/> <desc> <p>If the module is not loaded, this function searches the code path for the first file which contains object code for - <c>Module</c> and returns the absolute file name. If + <c><anno>Module</anno></c> and returns the absolute file name. If the module is loaded, it returns the name of the file which contained the loaded object code. If the module is pre-loaded, <c>preloaded</c> is returned. If the module is Cover compiled, @@ -603,21 +549,16 @@ </desc> </func> <func> - <name>get_object_code(Module) -> {Module, Binary, Filename} | error</name> + <name name="get_object_code" arity="1"/> <fsummary>Get the object code for a module</fsummary> - <type> - <v>Module = atom()</v> - <v>Binary = binary()</v> - <v>Filename = string()</v> - </type> <desc> <p>Searches the code path for the object code of the module - <c>Module</c>. It returns <c>{Module, Binary, Filename}</c> - if successful, and <c>error</c> if not. <c>Binary</c> is a + <c><anno>Module</anno></c>. It returns <c>{<anno>Module</anno>, <anno>Binary</anno>, <anno>Filename</anno>}</c> + if successful, and <c>error</c> if not. <c><anno>Binary</anno></c> is a binary data object which contains the object code for the module. This can be useful if code is to be loaded on a remote node in a distributed system. For example, loading - module <c>Module</c> on a node <c>Node</c> is done as + module <c><anno>Module</anno></c> on a node <c>Node</c> is done as follows:</p> <code type="none"> ... @@ -627,7 +568,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name>root_dir() -> string()</name> + <name name="root_dir" arity="0"/> <fsummary>Root directory of Erlang/OTP</fsummary> <desc> <p>Returns the root directory of Erlang/OTP, which is @@ -638,7 +579,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name>lib_dir() -> string()</name> + <name name="lib_dir" arity="0"/> <fsummary>Library directory of Erlang/OTP</fsummary> <desc> <p>Returns the library directory, <c>$OTPROOT/lib</c>, where @@ -649,19 +590,16 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name>lib_dir(Name) -> string() | {error, bad_name}</name> + <name name="lib_dir" arity="1"/> <fsummary>Library directory for an application</fsummary> - <type> - <v>Name = atom()</v> - </type> <desc> <p>This function is mainly intended for finding out the path for the "library directory", the top directory, for an - application <c>Name</c> located under <c>$OTPROOT/lib</c> or + application <c><anno>Name</anno></c> located under <c>$OTPROOT/lib</c> or on a directory referred to via the <c>ERL_LIBS</c> environment variable.</p> - <p>If there is a regular directory called <c>Name</c> or - <c>Name-Vsn</c> in the code path with an <c>ebin</c> + <p>If there is a regular directory called <c><anno>Name</anno></c> or + <c><anno>Name</anno>-Vsn</c> in the code path with an <c>ebin</c> subdirectory, the path to this directory is returned (not the <c>ebin</c> directory). If the directory refers to a directory in an archive, the archive name is stripped away @@ -675,23 +613,19 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), <pre> > <input>code:lib_dir(mnesia).</input> "/usr/local/otp/lib/mnesia-4.2.2"</pre> - <p>Returns <c>{error, bad_name}</c> if <c>Name</c> + <p>Returns <c>{error, bad_name}</c> if <c><anno>Name</anno></c> is not the name of an application under <c>$OTPROOT/lib</c> or on a directory referred to via the <c>ERL_LIBS</c> environment variable. Fails with an exception if <c>Name</c> has the wrong type.</p> - <warning><p>For backward compatibility, <c>Name</c> is also allowed to + <warning><p>For backward compatibility, <c><anno>Name</anno></c> is also allowed to be a string. That will probably change in a future release.</p></warning> </desc> </func> <func> - <name>lib_dir(Name, SubDir) -> string() | {error, bad_name}</name> + <name name="lib_dir" arity="2"/> <fsummary>subdirectory for an application</fsummary> - <type> - <v>Name = atom()</v> - <v>SubDir = atom()</v> - </type> <desc> <p>Returns the path to a subdirectory directly under the top directory of an application. Normally the subdirectories @@ -705,12 +639,12 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), > <input>code:lib_dir(megaco, priv).</input> "/usr/local/otp/lib/megaco-3.9.1.1/priv"</pre> - <p>Fails with an exception if <c>Name</c> or <c>SubDir</c> has + <p>Fails with an exception if <c><anno>Name</anno></c> or <c><anno>SubDir</anno></c> has the wrong type.</p> </desc> </func> <func> - <name>compiler_dir() -> string()</name> + <name name="compiler_dir" arity="0"/> <fsummary>Library directory for the compiler</fsummary> <desc> <p>Returns the compiler library directory. Equivalent to @@ -718,21 +652,18 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name>priv_dir(Name) -> string() | {error, bad_name}</name> + <name name="priv_dir" arity="1"/> <fsummary>Priv directory for an application</fsummary> - <type> - <v>Name = atom()</v> - </type> <desc> <p>Returns the path to the <c>priv</c> directory in an - application. Equivalent to <c>code:lib_dir(Name,priv).</c>.</p> + application. Equivalent to <c>code:lib_dir(<anno>Name</anno>, priv).</c>.</p> - <warning><p>For backward compatibility, <c>Name</c> is also allowed to + <warning><p>For backward compatibility, <c><anno>Name</anno></c> is also allowed to be a string. That will probably change in a future release.</p></warning> </desc> </func> <func> - <name>objfile_extension() -> ".beam"</name> + <name name="objfile_extension" arity="0"/> <fsummary>Object code file extension</fsummary> <desc> <p>Returns the object code file extension that corresponds to @@ -740,24 +671,16 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name>stick_dir(Dir) -> ok | error</name> + <name name="stick_dir" arity="1"/> <fsummary>Mark a directory as sticky</fsummary> - <type> - <v>Dir = string()</v> - <v>What = term()</v> - </type> <desc> - <p>This function marks <c>Dir</c> as sticky.</p> + <p>This function marks <c><anno>Dir</anno></c> as sticky.</p> <p>Returns <c>ok</c> if successful or <c>error</c> if not.</p> </desc> </func> <func> - <name>unstick_dir(Dir) -> ok | error</name> + <name name="unstick_dir" arity="1"/> <fsummary>Remove a sticky directory mark</fsummary> - <type> - <v>Dir = string()</v> - <v>What = term()</v> - </type> <desc> <p>This function unsticks a directory which has been marked as sticky.</p> @@ -765,45 +688,39 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name>is_sticky(Module) -> true | false</name> + <name name="is_sticky" arity="1"/> <fsummary>Test whether a module is sticky</fsummary> - <type> - <v>Module = atom()</v> - </type> <desc> - <p>This function returns <c>true</c> if <c>Module</c> is the + <p>This function returns <c>true</c> if <c><anno>Module</anno></c> is the name of a module that has been loaded from a sticky directory (or in other words: an attempt to reload the module will fail), - or <c>false</c> if <c>Module</c> is not a loaded module or is + or <c>false</c> if <c><anno>Module</anno></c> is not a loaded module or is not sticky.</p> </desc> </func> <func> - <name>rehash() -> ok</name> + <name name="rehash" arity="0"/> <fsummary>Rehash or create code path cache</fsummary> <desc> <p>This function creates or rehashes the code path cache.</p> </desc> </func> <func> - <name>where_is_file(Filename) -> Absname | non_existing</name> + <name name="where_is_file" arity="1"/> <fsummary>Full name of a file located in the code path</fsummary> - <type> - <v>Filename = Absname = string()</v> - </type> <desc> - <p>Searches the code path for <c>Filename</c>, a file of + <p>Searches the code path for <c><anno>Filename</anno></c>, a file of arbitrary type. If found, the full name is returned. <c>non_existing</c> is returned if the file cannot be found. The function can be useful, for example, to locate application resource files. If the code path cache is used, the code server will efficiently read the full name from - the cache, provided that <c>Filename</c> is an object code + the cache, provided that <c><anno>Filename</anno></c> is an object code file or an <c>.app</c> file.</p> </desc> </func> <func> - <name>clash() -> ok</name> + <name name="clash" arity="0"/> <fsummary>Search for modules with identical names.</fsummary> <desc> <p>Searches the entire code space for module names with @@ -811,10 +728,10 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name>is_module_native(Module) -> true | false | undefined</name> + <name>is_module_native(Module) -> boolean() | undefined</name> <fsummary>Test whether a module has native code</fsummary> <type> - <v>Module = atom()</v> + <v>Module = module()</v> </type> <desc> <p>This function returns <c>true</c> if <c>Module</c> is diff --git a/lib/kernel/doc/src/disk_log.xml b/lib/kernel/doc/src/disk_log.xml index 324d4264cf..d278d54d93 100644 --- a/lib/kernel/doc/src/disk_log.xml +++ b/lib/kernel/doc/src/disk_log.xml @@ -179,13 +179,48 @@ reopen the log simultaneously.</p> </note> </description> + <datatypes> + <datatype> + <name name="log"/> + </datatype> + <datatype> + <name name="dlog_size"/> + </datatype> + <datatype> + <name name="dlog_format"/> + </datatype> + <datatype> + <name name="dlog_head_opt"/> + </datatype> + <datatype> + <name name="dlog_byte"/> + </datatype> + <datatype> + <name name="dlog_mode"/> + </datatype> + <datatype> + <name name="dlog_type"/> + </datatype> + <datatype> + <name name="continuation"/> + <desc><p>Chunk continuation returned by + <c>chunk/2,3</c>, <c>bchunk/2,3</c>, or <c>chunk_step/3</c>.</p> + </desc> + </datatype> + <datatype> + <name name="bytes"/> + </datatype> + <datatype> + <name name="invalid_header"/> + </datatype> + <datatype> + <name name="file_error"/> + </datatype> + </datatypes> <funcs> <func> - <name>accessible_logs() -> {[LocalLog], [DistributedLog]}</name> + <name name="accessible_logs" arity="0"/> <fsummary>Return the accessible disk logs on the current node.</fsummary> - <type> - <v>LocalLog = DistributedLog = term()</v> - </type> <desc> <p>The <c>accessible_logs/0</c> function returns the names of the disk logs accessible on the current node. @@ -195,16 +230,13 @@ </desc> </func> <func> - <name>alog(Log, Term)</name> - <name>balog(Log, Bytes) -> ok | {error, Reason}</name> + <name name="alog" arity="2"/> + <name name="balog" arity="2"/> + <type variable="Log"/> + <type variable="Term" name_i="1"/> + <type variable="Bytes"/> + <type name="notify_ret"/> <fsummary>Asynchronously log an item onto a disk log.</fsummary> - <type> - <v>Log = term()</v> - <v>Term = term()</v> - <v>Bytes = binary() | [Byte]</v> - <v>Byte = [Byte] | 0 =< integer() =< 255</v> - <v>Reason = no_such_log</v> - </type> <desc> <p>The <c>alog/2</c> and <c>balog/2</c> functions asynchronously append an item to a disk log. The function <c>alog/2</c> is @@ -225,17 +257,13 @@ </desc> </func> <func> - <name>alog_terms(Log, TermList)</name> - <name>balog_terms(Log, BytesList) -> ok | {error, Reason}</name> + <name name="alog_terms" arity="2"/> + <name name="balog_terms" arity="2"/> <fsummary>Asynchronously log several items onto a disk log.</fsummary> - <type> - <v>Log = term()</v> - <v>TermList = [term()]</v> - <v>BytesList = [Bytes]</v> - <v>Bytes = binary() | [Byte]</v> - <v>Byte = [Byte] | 0 =< integer() =< 255</v> - <v>Reason = no_such_log</v> - </type> + <type variable="Log"/> + <type variable="TermList" name_i="1"/> + <type variable="ByteList"/> + <type name="notify_ret"/> <desc> <p>The <c>alog_terms/2</c> and <c>balog_terms/2</c> functions asynchronously append a list of items to a disk log. @@ -257,14 +285,10 @@ </desc> </func> <func> - <name>block(Log)</name> - <name>block(Log, QueueLogRecords) -> ok | {error, Reason}</name> + <name name="block" arity="1"/> + <name name="block" arity="2"/> + <type name="block_error_rsn"/> <fsummary>Block a disk log.</fsummary> - <type> - <v>Log = term()</v> - <v>QueueLogRecords = bool()</v> - <v>Reason = no_such_log | nonode | {blocked_log, Log}</v> - </type> <desc> <p>With a call to <c>block/1,2</c> a process can block a log. If the blocking process is not an owner of the log, a temporary @@ -280,52 +304,32 @@ affected by the block. Any other attempt than those hitherto mentioned to update or read a blocked log suspends the calling process until the log is unblocked or returns an - error message <c>{blocked_log, Log}</c>, depending on - whether the value of <c>QueueLogRecords</c> is <c>true</c> - or <c>false</c>. The default value of <c>QueueLogRecords</c> + error message <c>{blocked_log, <anno>Log</anno>}</c>, depending on + whether the value of <c><anno>QueueLogRecords</anno></c> is <c>true</c> + or <c>false</c>. The default value of <c><anno>QueueLogRecords</anno></c> is <c>true</c>, which is used by <c>block/1</c>. </p> </desc> </func> <func> - <name>change_header(Log, Header) -> ok | {error, Reason}</name> + <name name="change_header" arity="2"/> <fsummary>Change the head or head_func option for an owner of a disk log.</fsummary> - <type> - <v>Log = term()</v> - <v>Header = {head, Head} | {head_func, {M,F,A}}</v> - <v>Head = none | term() | binary() | [Byte]</v> - <v>Byte = [Byte] | 0 =< integer() =< 255</v> - <v>Reason = no_such_log | nonode | {read_only_mode, Log} | {blocked_log, Log} | {badarg, head}</v> - </type> <desc> <p>The <c>change_header/2</c> function changes the value of the <c>head</c> or <c>head_func</c> option of a disk log.</p> </desc> </func> <func> - <name>change_notify(Log, Owner, Notify) -> ok | {error, Reason}</name> + <name name="change_notify" arity="3"/> <fsummary>Change the notify option for an owner of a disk log.</fsummary> - <type> - <v>Log = term()</v> - <v>Owner = pid()</v> - <v>Notify = bool()</v> - <v>Reason = no_such_log | nonode | {blocked_log, Log} | {badarg, notify} | {not_owner, Owner}</v> - </type> <desc> <p>The <c>change_notify/3</c> function changes the value of the <c>notify</c> option for an owner of a disk log. </p> </desc> </func> <func> - <name>change_size(Log, Size) -> ok | {error, Reason}</name> + <name name="change_size" arity="2"/> <fsummary>Change the size of an open disk log.</fsummary> - <type> - <v>Log = term()</v> - <v>Size = integer() > 0 | infinity | {MaxNoBytes, MaxNoFiles}</v> - <v>MaxNoBytes = integer() > 0</v> - <v>MaxNoFiles = integer() > 0</v> - <v>Reason = no_such_log | nonode | {read_only_mode, Log} | {blocked_log, Log} | {new_size_too_small, CurrentSize} | {badarg, size} | {file_error, FileName, FileError}</v> - </type> <desc> <p>The <c>change_size/2</c> function changes the size of an open log. For a halt log it is always possible to increase the size, @@ -363,21 +367,17 @@ </desc> </func> <func> - <name>chunk(Log, Continuation)</name> - <name>chunk(Log, Continuation, N) -> {Continuation2, Terms} | {Continuation2, Terms, Badbytes} | eof | {error, Reason}</name> - <name>bchunk(Log, Continuation)</name> - <name>bchunk(Log, Continuation, N) -> {Continuation2, Binaries} | {Continuation2, Binaries, Badbytes} | eof | {error, Reason}</name> + <name name="chunk" arity="2"/> + <name name="chunk" arity="3"/> + <name name="bchunk" arity="2"/> + <name name="bchunk" arity="3"/> <fsummary>Read a chunk of items written to a disk log.</fsummary> - <type> - <v>Log = term()</v> - <v>Continuation = start | cont()</v> - <v>N = integer() > 0 | infinity</v> - <v>Continuation2 = cont()</v> - <v>Terms = [term()]</v> - <v>Badbytes = integer()</v> - <v>Reason = no_such_log | {format_external, Log} | {blocked_log, Log} | {badarg, continuation} | {not_internal_wrap, Log} | {corrupt_log_file, FileName} | {file_error, FileName, FileError}</v> - <v>Binaries = [binary()]</v> - </type> + <type variable="Log"/> + <type variable="Continuation"/> + <type variable="N"/> + <type name="chunk_ret"/> + <type name="bchunk_ret"/> + <type name="chunk_error_rsn"/> <desc> <p>The <c>chunk/2,3</c> and <c>bchunk/2,3</c> functions make it possible to efficiently read the terms which have been @@ -394,31 +394,31 @@ individual distributed log on some other node is chosen, if such a log exists. </p> - <p>When <c>chunk/3</c> is called, <c>N</c> controls the + <p>When <c>chunk/3</c> is called, <c><anno>N</anno></c> controls the maximum number of terms that are read from the log in each chunk. Default is <c>infinity</c>, which means that all the terms contained in the 64 kilobyte chunk are read. If less than - <c>N</c> terms are returned, this does not necessarily mean + <c><anno>N</anno></c> terms are returned, this does not necessarily mean that the end of the file has been reached. </p> <p>The <c>chunk</c> function returns a tuple - <c>{Continuation2, Terms}</c>, where <c>Terms</c> is a list - of terms found in the log. <c>Continuation2</c> is yet + <c>{<anno>Continuation2</anno>, <anno>Terms</anno>}</c>, where <c><anno>Terms</anno></c> is a list + of terms found in the log. <c><anno>Continuation2</anno></c> is yet another continuation which must be passed on to any subsequent calls to <c>chunk</c>. With a series of calls to <c>chunk</c> it is possible to extract all terms from a log. </p> <p>The <c>chunk</c> function returns a tuple - <c>{Continuation2, Terms, Badbytes}</c> if the log is opened - in read-only mode and the read chunk is corrupt. <c>Badbytes</c> + <c>{<anno>Continuation2</anno>, <anno>Terms</anno>, <anno>Badbytes</anno>}</c> if the log is opened + in read-only mode and the read chunk is corrupt. <c><anno>Badbytes</anno></c> is the number of bytes in the file which were found not to be Erlang terms in the chunk. Note also that the log is not repaired. When trying to read chunks from a log opened in read-write mode, - the tuple <c>{corrupt_log_file, FileName}</c> is returned if the + the tuple <c>{corrupt_log_file, <anno>FileName</anno>}</c> is returned if the read chunk is corrupt. </p> <p><c>chunk</c> returns <c>eof</c> when the end of the log is - reached, or <c>{error, Reason}</c> if an error occurs. Should + reached, or <c>{error, <anno>Reason</anno>}</c> if an error occurs. Should a wrap log file be missing, a message is output on the error log. </p> <p>When <c>chunk/2,3</c> is used with wrap logs, the returned @@ -431,12 +431,8 @@ </desc> </func> <func> - <name>chunk_info(Continuation) -> InfoList | {error, Reason}</name> + <name name="chunk_info" arity="1"/> <fsummary>Return information about a chunk continuation of a disk log.</fsummary> - <type> - <v>Continuation = cont()</v> - <v>Reason = {no_continuation, Continuation}</v> - </type> <desc> <p>The <c>chunk_info/1</c> function returns the following pair describing the chunk continuation returned by @@ -444,29 +440,22 @@ </p> <list type="bulleted"> <item> - <p><c>{node, Node}</c>. Terms are read from - the disk log running on <c>Node</c>.</p> + <p><c>{node, <anno>Node</anno>}</c>. Terms are read from + the disk log running on <c><anno>Node</anno></c>.</p> </item> </list> </desc> </func> <func> - <name>chunk_step(Log, Continuation, Step) -> {ok, Continuation2} | {error, Reason}</name> + <name name="chunk_step" arity="3"/> <fsummary>Step forward or backward among the wrap log files of a disk log.</fsummary> - <type> - <v>Log = term()</v> - <v>Continuation = start | cont()</v> - <v>Step = integer()</v> - <v>Continuation2 = cont()</v> - <v>Reason = no_such_log | end_of_log | {format_external, Log} | {blocked_log, Log} | {badarg, continuation} | {file_error, FileName, FileError}</v> - </type> <desc> <p>The function <c>chunk_step</c> can be used in conjunction with <c>chunk/2,3</c> and <c>bchunk/2,3</c> to search through an internally formatted wrap log. It takes as argument a continuation as returned by <c>chunk/2,3</c>, <c>bchunk/2,3</c>, or <c>chunk_step/3</c>, and steps forward - (or backward) <c>Step</c> files in the wrap log. The + (or backward) <c><anno>Step</anno></c> files in the wrap log. The continuation returned points to the first log item in the new current file. </p> @@ -482,14 +471,11 @@ </desc> </func> <func> - <name>close(Log) -> ok | {error, Reason}</name> + <name name="close" arity="1"/> <fsummary>Close a disk log.</fsummary> - <type> - <v>Reason = no_such_log | nonode | {file_error, FileName, FileError}</v> - </type> + <type name="close_error_rsn"/> <desc> - <p> <marker id="close_1"></marker> -The function <c>close/1</c> closes a + <p><marker id="close_1"></marker>The function <c>close/1</c> closes a local or distributed disk log properly. An internally formatted log must be closed before the Erlang system is stopped, otherwise the log is regarded as unclosed and the @@ -511,11 +497,8 @@ The function <c>close/1</c> closes a </desc> </func> <func> - <name>format_error(Error) -> Chars</name> + <name name="format_error" arity="1"/> <fsummary>Return an English description of a disk log error reply.</fsummary> - <type> - <v>Chars = [char() | Chars]</v> - </type> <desc> <p>Given the error returned by any function in this module, the function <c>format_error</c> returns a descriptive string @@ -524,11 +507,10 @@ The function <c>close/1</c> closes a </desc> </func> <func> - <name>inc_wrap_file(Log) -> ok | {error, Reason}</name> + <name name="inc_wrap_file" arity="1"/> <fsummary>Change to the next wrap log file of a disk log.</fsummary> - <type> - <v>Reason = no_such_log | nonode | {read_only_mode, Log} | {blocked_log, Log} | {halt_log, Log} | {invalid_header, InvalidHeader} | {file_error, FileName, FileError}</v> - </type> + <type name="inc_wrap_error_rsn"/> + <type name="invalid_header"/> <desc> <p>The <c>inc_wrap_file/1</c> function forces the internally formatted disk log to start logging to the @@ -543,8 +525,9 @@ The function <c>close/1</c> closes a </desc> </func> <func> - <name>info(Log) -> InfoList | {error, no_such_log}</name> + <name name="info" arity="1"/> <fsummary>Return information about a disk log.</fsummary> + <type name="dlog_info"/> <desc> <p>The <c>info/1</c> function returns a list of <c>{Tag, Value}</c> pairs describing the log. If there is a disk log process running @@ -556,55 +539,55 @@ The function <c>close/1</c> closes a </p> <list type="bulleted"> <item> - <p><c>{name, Log}</c>, where <c>Log</c> is the name of + <p><c>{name, <anno>Log</anno>}</c>, where <c><anno>Log</anno></c> is the name of the log as given by the <c>open/1</c> option <c>name</c>.</p> </item> <item> - <p><c>{file, File}</c>. For halt logs <c>File</c> is the - filename, and for wrap logs <c>File</c> is the base name.</p> + <p><c>{file, <anno>File</anno>}</c>. For halt logs <c><anno>File</anno></c> is the + filename, and for wrap logs <c><anno>File</anno></c> is the base name.</p> </item> <item> - <p><c>{type, Type}</c>, where <c>Type</c> is the type of + <p><c>{type, <anno>Type</anno>}</c>, where <c><anno>Type</anno></c> is the type of the log as given by the <c>open/1</c> option <c>type</c>.</p> </item> <item> - <p><c>{format, Format}</c>, where <c>Format</c> is the format + <p><c>{format, <anno>Format</anno>}</c>, where <c><anno>Format</anno></c> is the format of the log as given by the <c>open/1</c> option <c>format</c>.</p> </item> <item> - <p><c>{size, Size}</c>, where <c>Size</c> is the size + <p><c>{size, <anno>Size</anno>}</c>, where <c><anno>Size</anno></c> is the size of the log as given by the <c>open/1</c> option <c>size</c>, or the size set by <c>change_size/2</c>. The value set by <c>change_size/2</c> is reflected immediately.</p> </item> <item> - <p><c>{mode, Mode}</c>, where <c>Mode</c> is the mode + <p><c>{mode, <anno>Mode</anno>}</c>, where <c><anno>Mode</anno></c> is the mode of the log as given by the <c>open/1</c> option <c>mode</c>.</p> </item> <item> - <p><c>{owners, [{pid(), Notify}]}</c> where <c>Notify</c> + <p><c>{owners, [{pid(), <anno>Notify</anno>}]}</c> where <c><anno>Notify</anno></c> is the value set by the <c>open/1</c> option <c>notify</c> or the function <c>change_notify/3</c> for the owners of the log.</p> </item> <item> - <p><c>{users, Users}</c> where <c>Users</c> is the number + <p><c>{users, <anno>Users</anno>}</c> where <c><anno>Users</anno></c> is the number of anonymous users of the log, see the <c>open/1</c> option <seealso marker="#linkto">linkto</seealso>.</p> </item> <item> - <p><c>{status, Status}</c>, where <c>Status</c> is <c>ok</c> - or <c>{blocked, QueueLogRecords}</c> as set by the functions + <p><c>{status, <anno>Status</anno>}</c>, where <c><anno>Status</anno></c> is <c>ok</c> + or <c>{blocked, <anno>QueueLogRecords</anno>}</c> as set by the functions <c>block/1,2</c> and <c>unblock/1</c>.</p> </item> <item> - <p><c>{node, Node}</c>. The information returned by the + <p><c>{node, <anno>Node</anno>}</c>. The information returned by the current invocation of the <c>info/1</c> function has been - gathered from the disk log process running on <c>Node</c>.</p> + gathered from the disk log process running on <c><anno>Node</anno></c>.</p> </item> <item> - <p><c>{distributed, Dist}</c>. If the log is local on - the current node, then <c>Dist</c> has the value <c>local</c>, + <p><c>{distributed, <anno>Dist</anno>}</c>. If the log is local on + the current node, then <c><anno>Dist</anno></c> has the value <c>local</c>, otherwise all nodes where the log is distributed are returned as a list.</p> </item> @@ -614,16 +597,16 @@ The function <c>close/1</c> closes a </p> <list type="bulleted"> <item> - <p><c>{head, Head}</c>. Depending of the value of + <p><c>{head, <anno>Head</anno>}</c>. Depending of the value of the <c>open/1</c> options <c>head</c> and <c>head_func</c> or set by the function <c>change_header/2</c>, the value - of <c>Head</c> is <c>none</c> (default), + of <c><anno>Head</anno></c> is <c>none</c> (default), <c>{head, H}</c> (<c>head</c> option) or <c>{M,F,A}</c> (<c>head_func</c> option).</p> </item> <item> - <p><c>{no_written_items, NoWrittenItems}</c>, where - <c>NoWrittenItems</c> is the number of items + <p><c>{no_written_items, <anno>NoWrittenItems</anno>}</c>, where + <c><anno>NoWrittenItems</anno></c> is the number of items written to the log since the disk log process was created.</p> </item> </list> @@ -632,7 +615,7 @@ The function <c>close/1</c> closes a </p> <list type="bulleted"> <item> - <p><c>{full, Full}</c>, where <c>Full</c> is <c>true</c> or + <p><c>{full, <anno>Full</anno>}</c>, where <c><anno>Full</anno></c> is <c>true</c> or <c>false</c> depending on whether the halt log is full or not.</p> </item> </list> @@ -660,8 +643,8 @@ The function <c>close/1</c> closes a <c>size</c> or set by <c>change_size/2</c>.</p> </item> <item> - <p><c>{no_overflows, {SinceLogWasOpened, SinceLastInfo}}</c>, - where <c>SinceLogWasOpened</c> (<c>SinceLastInfo</c>) is + <p><c>{no_overflows, {<anno>SinceLogWasOpened</anno>, <anno>SinceLastInfo</anno>}}</c>, + where <c><anno>SinceLogWasOpened</anno></c> (<c><anno>SinceLastInfo</anno></c>) is the number of times a wrap log file has been filled up and a new one opened or <c>inc_wrap_file/1</c> has been called since the disk log was last opened (<c>info/1</c> @@ -677,21 +660,18 @@ The function <c>close/1</c> closes a </desc> </func> <func> - <name>lclose(Log)</name> - <name>lclose(Log, Node) -> ok | {error, Reason}</name> + <name name="lclose" arity="1"/> + <name name="lclose" arity="2"/> + <type name="lclose_error_rsn"/> <fsummary>Close a disk log on one node.</fsummary> - <type> - <v>Node = node()</v> - <v>Reason = no_such_log | {file_error, FileName, FileError}</v> - </type> <desc> <p>The function <c>lclose/1</c> closes a local log or an individual distributed log on the current node. The function <c>lclose/2</c> closes an individual distributed log on the specified node if the node is not the current one. - <c>lclose(Log)</c> is equivalent to - <c>lclose(Log, node())</c>. + <c>lclose(<anno>Log</anno>)</c> is equivalent to + <c>lclose(<anno>Log</anno>, node())</c>. See also <seealso marker="#close_1">close/1</seealso>. </p> <p>If there is no log with the given name @@ -700,20 +680,17 @@ The function <c>close/1</c> closes a </desc> </func> <func> - <name>log(Log, Term)</name> - <name>blog(Log, Bytes) -> ok | {error, Reason}</name> + <name name="log" arity="2"/> + <name name="blog" arity="2"/> <fsummary>Log an item onto a disk log.</fsummary> - <type> - <v>Log = term()</v> - <v>Term = term()</v> - <v>Bytes = binary() | [Byte]</v> - <v>Byte = [Byte] | 0 =< integer() =< 255</v> - <v>Reason = no_such_log | nonode | {read_only_mode, Log} | {format_external, Log} | {blocked_log, Log} | {full, Log} | {invalid_header, InvalidHeader} | {file_error, FileName, FileError}</v> - </type> + <type variable="Log"/> + <type variable="Term" name_i="1"/> + <type variable="Bytes"/> + <type name="log_error_rsn"/> <desc> <p>The <c>log/2</c> and <c>blog/2</c> functions synchronously append a term to a disk log. They return <c>ok</c> or - <c>{error, Reason}</c> when the term has been written to + <c>{error, <anno>Reason</anno>}</c> when the term has been written to disk. If the log is distributed, <c>ok</c> is always returned, unless all nodes are down. Terms are written by means of the ordinary <c>write()</c> function of the @@ -736,17 +713,13 @@ The function <c>close/1</c> closes a </desc> </func> <func> - <name>log_terms(Log, TermList)</name> - <name>blog_terms(Log, BytesList) -> ok | {error, Reason}</name> + <name name="log_terms" arity="2"/> + <name name="blog_terms" arity="2"/> <fsummary>Log several items onto a disk log.</fsummary> - <type> - <v>Log = term()</v> - <v>TermList = [term()]</v> - <v>BytesList = [Bytes]</v> - <v>Bytes = binary() | [Byte]</v> - <v>Byte = [Byte] | 0 =< integer() =< 255</v> - <v>Reason = no_such_log | nonode | {read_only_mode, Log} | {format_external, Log} | {blocked_log, Log} | {full, Log} | {invalid_header, InvalidHeader} | {file_error, FileName, FileError}</v> - </type> + <type variable="Log"/> + <type variable="TermList" name_i="1"/> + <type variable="BytesList"/> + <type name="log_error_rsn"/> <desc> <p>The <c>log_terms/2</c> and <c>blog_terms/2</c> functions synchronously append a list of items to the log. The benefit @@ -769,47 +742,33 @@ The function <c>close/1</c> closes a </desc> </func> <func> - <name>open(ArgL) -> OpenRet | DistOpenRet</name> + <name name="open" arity="1"/> + <type name="dlog_options"/> + <type name="dlog_option"/> + <type name="open_ret"/> + <type name="ret"/> + <type name="dist_open_ret"/> + <type name="dist_error_rsn"/> + <type name="open_error_rsn"/> + <type name="dlog_optattr"/> + <type name="dlog_size"/> <fsummary>Open a disk log file.</fsummary> - <type> - <v>ArgL = [Opt]</v> - <v>Opt = {name, term()} | {file, FileName}, {linkto, LinkTo} | {repair, Repair} | {type, Type} | {format, Format} | {size, Size} | {distributed, [Node]} | {notify, bool()} | {head, Head} | {head_func, {M,F,A}} | {mode, Mode}</v> - <v>FileName = string() | atom()</v> - <v>LinkTo = pid() | none</v> - <v>Repair = true | false | truncate</v> - <v>Type = halt | wrap</v> - <v>Format = internal | external</v> - <v>Size = integer() > 0 | infinity | {MaxNoBytes, MaxNoFiles}</v> - <v>MaxNoBytes = integer() > 0</v> - <v>MaxNoFiles = 0 < integer() < 65000</v> - <v>Rec = integer()</v> - <v>Bad = integer()</v> - <v>Head = none | term() | binary() | [Byte]</v> - <v>Byte = [Byte] | 0 =< integer() =< 255</v> - <v>Mode = read_write | read_only</v> - <v>OpenRet = Ret | {error, Reason}</v> - <v>DistOpenRet = {[{Node, Ret}], [{BadNode, {error, DistReason}}]}</v> - <v>Node = BadNode = atom()</v> - <v>Ret = {ok, Log} | {repaired, Log, {recovered, Rec}, {badbytes, Bad}}</v> - <v>DistReason = nodedown | Reason</v> - <v>Reason = no_such_log | {badarg, Arg} | {size_mismatch, CurrentSize, NewSize} | {arg_mismatch, OptionName, CurrentValue, Value} | {name_already_open, Log} | {open_read_write, Log} | {open_read_only, Log} | {need_repair, Log} | {not_a_log_file, FileName} | {invalid_index_file, FileName} | {invalid_header, InvalidHeader} | {file_error, FileName, FileError} | {node_already_open, Log}</v> - </type> <desc> - <p>The <c>ArgL</c> parameter is a list of options which have + <p>The <c><anno>ArgL</anno></c> parameter is a list of options which have the following meanings:</p> <list type="bulleted"> <item> - <p><c>{name, Log}</c> specifies the name of the log. + <p><c>{name, <anno>Log</anno>}</c> specifies the name of the log. This is the name which must be passed on as a parameter in all subsequent logging operations. A name must always be supplied. </p> </item> <item> - <p><c>{file, FileName}</c> specifies the name of the + <p><c>{file, <anno>FileName</anno>}</c> specifies the name of the file which will be used for logged terms. If this value is omitted and the name of the log is either an atom or a string, - the file name will default to <c>lists:concat([Log, ".LOG"])</c> for halt logs. For wrap logs, this will be + the file name will default to <c>lists:concat([<anno>Log</anno>, ".LOG"])</c> for halt logs. For wrap logs, this will be the base name of the files. Each file in a wrap log will be called <c><![CDATA[<base_name>.N]]></c>, where <c>N</c> is an integer. Each wrap log will also have two files called @@ -817,22 +776,22 @@ The function <c>close/1</c> closes a </p> </item> <item> - <p><c>{linkto, LinkTo}</c>. <marker id="linkto"></marker> + <p><c>{linkto, <anno>LinkTo</anno>}</c>. <marker id="linkto"></marker> If - <c>LinkTo</c> is a pid, that pid becomes an owner of the - log. If <c>LinkTo</c> is <c>none</c> the log records + <c><anno>LinkTo</anno></c> is a pid, that pid becomes an owner of the + log. If <c><anno>LinkTo</anno></c> is <c>none</c> the log records that it is used anonymously by some process by incrementing the <c>users</c> counter. By default, the process which calls <c>open/1</c> owns the log. </p> </item> <item> - <p><c>{repair, Repair}</c>. If <c>Repair</c> is <c>true</c>, + <p><c>{repair, <anno>Repair</anno>}</c>. If <c><anno>Repair</anno></c> is <c>true</c>, the current log file will be repaired, if needed. As the restoration is initiated, a message is output on the error log. If <c>false</c> is given, no automatic repair will be attempted. Instead, the - tuple <c>{error, {need_repair, Log}}</c> is returned if an + tuple <c>{error, {need_repair, <anno>Log</anno>}}</c> is returned if an attempt is made to open a corrupt log file. If <c>truncate</c> is given, the log file will be truncated, creating an empty log. Default is @@ -841,41 +800,41 @@ If </p> </item> <item> - <p><c>{type, Type}</c> is the type of the log. Default + <p><c>{type, <anno>Type</anno>}</c> is the type of the log. Default is <c>halt</c>. </p> </item> <item> - <p><c>{format, Format}</c> specifies the format of the + <p><c>{format, <anno>Format</anno>}</c> specifies the format of the disk log. Default is <c>internal</c>. </p> </item> <item> - <p><c>{size, Size}</c> specifies the size of the log. + <p><c>{size, <anno>Size</anno>}</c> specifies the size of the log. When a halt log has reached its maximum size, all attempts to log more items are rejected. The default size is <c>infinity</c>, which for halt implies that there is no - maximum size. For wrap logs, the <c>Size</c> parameter + maximum size. For wrap logs, the <c><anno>Size</anno></c> parameter may be either a pair - <c>{MaxNoBytes, MaxNoFiles}</c> or <c>infinity</c>. In the + <c>{<anno>MaxNoBytes</anno>, <anno>MaxNoFiles</anno>}</c> or <c>infinity</c>. In the latter case, if the files of an already existing wrap log with the same name can be found, the size is read from the existing wrap log, otherwise an error is returned. - Wrap logs write at most <c>MaxNoBytes</c> bytes on each file - and use <c>MaxNoFiles</c> files before starting all over with - the first wrap log file. Regardless of <c>MaxNoBytes</c>, + Wrap logs write at most <c><anno>MaxNoBytes</anno></c> bytes on each file + and use <c><anno>MaxNoFiles</anno></c> files before starting all over with + the first wrap log file. Regardless of <c><anno>MaxNoBytes</anno></c>, at least the header (if there is one) and one item is written on each wrap log file before wrapping to the next file. When opening an existing wrap log, it is not necessary to supply a value for the option <c>Size</c>, but any supplied value must equal the current size of the log, otherwise - the tuple <c>{error, {size_mismatch, CurrentSize, NewSize}}</c> + the tuple <c>{error, {size_mismatch, <anno>CurrentSize</anno>, <anno>NewSize</anno>}}</c> is returned. </p> </item> <item> - <p><c>{distributed, Nodes}</c>. This option can be used for + <p><c>{distributed, <anno>Nodes</anno>}</c>. This option can be used for adding members to a distributed disk log. The default value is <c>[]</c>, which means that the log is local on the current node. @@ -946,10 +905,10 @@ If </list> </item> <item> - <p><c>{head, Head}</c> specifies a header to be + <p><c>{head, <anno>Head</anno>}</c> specifies a header to be written first on the log file. If the log is a wrap - log, the item <c>Head</c> is written first in each new file. - <c>Head</c> should be a term if the format is + log, the item <c><anno>Head</anno></c> is written first in each new file. + <c><anno>Head</anno></c> should be a term if the format is <c>internal</c>, and a deep list of bytes (or a binary) otherwise. Default is <c>none</c>, which means that no header is written first on the file. @@ -966,17 +925,17 @@ If </p> </item> <item> - <p><c>{mode, Mode}</c> specifies if the log is to be + <p><c>{mode, <anno>Mode</anno>}</c> specifies if the log is to be opened in read-only or read-write mode. It defaults to <c>read_write</c>. </p> </item> </list> - <p>The <c>open/1</c> function returns <c>{ok, Log}</c> if the + <p>The <c>open/1</c> function returns <c>{ok, <anno>Log</anno>}</c> if the log file was successfully opened. If the file was - successfully repaired, the tuple <c>{repaired, Log, {recovered, Rec}, {badbytes, Bad}}</c> is returned, where - <c>Rec</c> is the number of whole Erlang terms found in the - file and <c>Bad</c> is the number of bytes in the file which + successfully repaired, the tuple <c>{repaired, <anno>Log</anno>, {recovered, <anno>Rec</anno>}, {badbytes, <anno>Bad</anno>}}</c> is returned, where + <c><anno>Rec</anno></c> is the number of whole Erlang terms found in the + file and <c><anno>Bad</anno></c> is the number of bytes in the file which were non-Erlang terms. If the <c>distributed</c> parameter was given, <c>open/1</c> returns a list of successful replies and a list of erroneous replies. Each @@ -988,7 +947,7 @@ If position after the last logged item, and the logging of items will commence from there. If the format is <c>internal</c> and the existing file is not recognized as an internally - formatted log, a tuple <c>{error, {not_a_log_file, FileName}}</c> + formatted log, a tuple <c>{error, {not_a_log_file, <anno>FileName</anno>}}</c> is returned. </p> <p>The <c>open/1</c> function cannot be used for changing the @@ -1000,15 +959,15 @@ If or <c>change_size/2</c>. As a consequence, none of the options except <c>name</c> is mandatory. If some given value differs from the current value, a tuple - <c>{error, {arg_mismatch, OptionName, CurrentValue, Value}}</c> + <c>{error, {arg_mismatch, <anno>OptionName</anno>, <anno>CurrentValue</anno>, <anno>Value</anno>}}</c> is returned. Caution: an owner's attempt to open a log as owner once again is acknowledged with the return value - <c>{ok, Log}</c>, but the state of the disk log is not + <c>{ok, <anno>Log</anno>}</c>, but the state of the disk log is not affected in any way. </p> <p>If a log with a given name is local on some node, and one tries to open the log distributed on the same node, - then the tuple <c>{error, {node_already_open, Name}}</c> is + then the tuple <c>{error, {node_already_open, <anno>Log</anno>}}</c> is returned. The same tuple is returned if the log is distributed on some node, and one tries to open the log locally on the same node. Opening individual distributed disk logs for the first time @@ -1036,12 +995,8 @@ If </desc> </func> <func> - <name>pid2name(Pid) -> {ok, Log} | undefined</name> + <name name="pid2name" arity="1"/> <fsummary>Return the name of the disk log handled by a pid.</fsummary> - <type> - <v>Log = term()</v> - <v>Pid = pid()</v> - </type> <desc> <p>The <c>pid2name/1</c> function returns the name of the log given the pid of a disk log process on the current node, or @@ -1052,26 +1007,23 @@ If </desc> </func> <func> - <name>reopen(Log, File)</name> - <name>reopen(Log, File, Head)</name> - <name>breopen(Log, File, BHead) -> ok | {error, Reason}</name> + <name name="reopen" arity="2"/> + <name name="reopen" arity="3"/> + <name name="breopen" arity="3"/> <fsummary>Reopen a disk log and save the old log.</fsummary> - <type> - <v>Log = term()</v> - <v>File = string()</v> - <v>Head = term()</v> - <v>BHead = binary() | [Byte]</v> - <v>Byte = [Byte] | 0 =< integer() =< 255</v> - <v>Reason = no_such_log | nonode | {read_only_mode, Log} | {blocked_log, Log} | {same_file_name, Log} | {invalid_index_file, FileName} | {invalid_header, InvalidHeader} | {file_error, FileName, FileError}</v> - </type> + <type variable="Log"/> + <type variable="File" name_i="1"/> + <type variable="Head" name_i="2"/> + <type variable="BHead"/> + <type name="reopen_error_rsn"/> <desc> <p>The <c>reopen</c> functions first rename the log file - to <c>File</c> and then re-create a new log file. - In case of a wrap log, <c>File</c> is used as the base name + to <c><anno>File</anno></c> and then re-create a new log file. + In case of a wrap log, <c><anno>File</anno></c> is used as the base name of the renamed files. By default the header given to <c>open/1</c> is written first in - the newly opened log file, but if the <c>Head</c> or the - <c>BHead</c> argument is given, this item is used instead. + the newly opened log file, but if the <c><anno>Head</anno></c> or the + <c><anno>BHead</anno></c> argument is given, this item is used instead. The header argument is used once only; next time a wrap log file is opened, the header given to <c>open/1</c> is used. </p> @@ -1089,12 +1041,9 @@ If </desc> </func> <func> - <name>sync(Log) -> ok | {error, Reason}</name> + <name name="sync" arity="1"/> + <type name="sync_error_rsn"/> <fsummary>Flush the contents of a disk log to the disk.</fsummary> - <type> - <v>Log = term()</v> - <v>Reason = no_such_log | nonode | {read_only_mode, Log} | {blocked_log, Log} | {file_error, FileName, FileError}</v> - </type> <desc> <p>The <c>sync/1</c> function ensures that the contents of the log are actually written to the disk. @@ -1103,20 +1052,17 @@ If </desc> </func> <func> - <name>truncate(Log)</name> - <name>truncate(Log, Head)</name> - <name>btruncate(Log, BHead) -> ok | {error, Reason}</name> + <name name="truncate" arity="1"/> + <name name="truncate" arity="2"/> + <name name="btruncate" arity="2"/> <fsummary>Truncate a disk log.</fsummary> - <type> - <v>Log = term()</v> - <v>Head = term()</v> - <v>BHead = binary() | [Byte]</v> - <v>Byte = [Byte] | 0 =< integer() =< 255</v> - <v>Reason = no_such_log | nonode | {read_only_mode, Log} | {blocked_log, Log} | {invalid_header, InvalidHeader} | {file_error, FileName, FileError}</v> - </type> + <type variable="Log"/> + <type variable="Head" name_i="2"/> + <type variable="BHead"/> + <type name="trunc_error_rsn"/> <desc> <p>The <c>truncate</c> functions remove all items from a disk log. - If the <c>Head</c> or the <c>BHead</c> argument is + If the <c><anno>Head</anno></c> or the <c><anno>BHead</anno></c> argument is given, this item is written first in the newly truncated log, otherwise the header given to <c>open/1</c> is used. The header argument is only used once; next time a wrap log file @@ -1138,12 +1084,9 @@ If </desc> </func> <func> - <name>unblock(Log) -> ok | {error, Reason}</name> + <name name="unblock" arity="1"/> + <type name="unblock_error_rsn"/> <fsummary>Unblock a disk log.</fsummary> - <type> - <v>Log = term()</v> - <v>Reason = no_such_log | nonode | {not_blocked, Log} | {not_blocked_by_pid, Log}</v> - </type> <desc> <p>The <c>unblock/1</c> function unblocks a log. A log can only be unblocked by the blocking process. @@ -1159,4 +1102,3 @@ If <seealso marker="wrap_log_reader">wrap_log_reader(3)</seealso></p> </section> </erlref> - diff --git a/lib/kernel/doc/src/erl_boot_server.xml b/lib/kernel/doc/src/erl_boot_server.xml index 4e7533810e..472671a80e 100644 --- a/lib/kernel/doc/src/erl_boot_server.xml +++ b/lib/kernel/doc/src/erl_boot_server.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2009</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -49,29 +49,17 @@ </description> <funcs> <func> - <name>start(Slaves) -> {ok, Pid} | {error, What}</name> + <name name="start" arity="1"/> <fsummary>Start the boot server</fsummary> - <type> - <v>Slaves = [Host]</v> - <v>Host = atom()</v> - <v>Pid = pid()</v> - <v>What = term()</v> - </type> <desc> - <p>Starts the boot server. <c>Slaves</c> is a list of IP + <p>Starts the boot server. <c><anno>Slaves</anno></c> is a list of IP addresses for hosts which are allowed to use this server as a boot server.</p> </desc> </func> <func> - <name>start_link(Slaves) -> {ok, Pid} | {error, What}</name> + <name name="start_link" arity="1"/> <fsummary>Start the boot server and links the caller</fsummary> - <type> - <v>Slaves = [Host]</v> - <v>Host = atom()</v> - <v>Pid = pid()</v> - <v>What = term()()</v> - </type> <desc> <p>Starts the boot server and links to the caller. This function is used to start the server if it is included in a supervision @@ -79,37 +67,23 @@ </desc> </func> <func> - <name>add_slave(Slave) -> ok | {error, What}</name> + <name name="add_slave" arity="1"/> <fsummary>Add a slave to the list of allowed slaves</fsummary> - <type> - <v>Slave = Host</v> - <v>Host = atom()</v> - <v>What = term()</v> - </type> <desc> - <p>Adds a <c>Slave</c> node to the list of allowed slave hosts.</p> + <p>Adds a <c><anno>Slave</anno></c> node to the list of allowed slave hosts.</p> </desc> </func> <func> - <name>delete_slave(Slave) -> ok | {error, What}</name> + <name name="delete_slave" arity="1"/> <fsummary>Delete a slave from the list of allowed slaves</fsummary> - <type> - <v>Slave = Host</v> - <v>Host = atom()</v> - <v>What = void()</v> - </type> <desc> - <p>Deletes a <c>Slave</c> node from the list of allowed slave + <p>Deletes a <c><anno>Slave</anno></c> node from the list of allowed slave hosts.</p> </desc> </func> <func> - <name>which_slaves() -> Slaves</name> + <name name="which_slaves" arity="0"/> <fsummary>Return the current list of allowed slave hosts</fsummary> - <type> - <v>Slaves = [Host]</v> - <v>Host = atom()</v> - </type> <desc> <p>Returns the current list of allowed slave hosts.</p> </desc> diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml index 9a62b45d63..1911fb628e 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>2010</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -172,6 +172,14 @@ </item> </taglist> </description> + <datatypes> + <datatype> + <name name="driver"/> + </datatype> + <datatype> + <name name="path"/> + </datatype> + </datatypes> <funcs> <func> <name>demonitor(MonitorRef) -> ok</name> @@ -189,37 +197,21 @@ </desc> </func> <func> - <name>info() -> AllInfoList</name> + <name name="info" arity="0"/> <fsummary>Retrieve information about all drivers</fsummary> - <type> - <v>AllInfoList = [ DriverInfo ]</v> - <v>DriverInfo = {DriverName, InfoList}</v> - <v>DriverName = string()</v> - <v>InfoList = [ InfoItem ]</v> - <v>InfoItem = {Tag, Value}</v> - <v>Tag = atom()</v> - <v>Value = term()</v> - </type> <desc> - <p>Returns a list of tuples <c>{DriverName, InfoList}</c>, where - <c>InfoList</c> is the result of calling <seealso marker="#info/1">info/1</seealso> for that - <c>DriverName</c>. Only dynamically linked in drivers are + <p>Returns a list of tuples <c>{<anno>DriverName</anno>, <anno>InfoList</anno>}</c>, where + <c><anno>InfoList</anno></c> is the result of calling <seealso marker="#info/1">info/1</seealso> for that + <c><anno>DriverName</anno></c>. Only dynamically linked in drivers are included in the list.</p> </desc> </func> <func> - <name>info(Name) -> InfoList</name> + <name name="info" arity="1"/> <fsummary>Retrieve information about one driver</fsummary> - <type> - <v>Name = string() | atom()</v> - <v>InfoList = [ InfoItem ]</v> - <v>InfoItem = {Tag, Value}</v> - <v>Tag = atom()</v> - <v>Value = term()</v> - </type> <desc> - <p>Returns a list of tuples <c>{Tag, Value}</c>, where - <c>Tag</c> is the information item and <c>Value</c> is the result + <p>Returns a list of tuples <c>{<anno>Tag</anno>, <anno>Value</anno>}</c>, where + <c><anno>Tag</anno></c> is the information item and <c><anno>Value</anno></c> is the result of calling <seealso marker="#info/2">info/2</seealso> with this driver name and this tag. The result being a tuple list containing all information available about a driver. </p> @@ -305,22 +297,18 @@ </desc> </func> <func> - <name>load(Path, Name) -> ok | {error, ErrorDesc}</name> + <name name="load" arity="2"/> <fsummary>Load a driver</fsummary> - <type> - <v>Path = Name = string() | atom()</v> - <v>ErrorDesc = term()</v> - </type> <desc> - <p>Loads and links the dynamic driver <c>Name</c>. <c>Path</c> + <p>Loads and links the dynamic driver <c><anno>Name</anno></c>. <c><anno>Path</anno></c> is a file path to the directory containing the driver. - <c>Name</c> must be a sharable object/dynamic library. Two - drivers with different <c>Path</c> parameters cannot be - loaded under the same name. The <c>Name</c> is a string or + <c><anno>Name</anno></c> must be a sharable object/dynamic library. Two + drivers with different <c><anno>Path</anno></c> parameters cannot be + loaded under the same name. The <c><anno>Name</anno></c> is a string or atom containing at least one character.</p> - <p>The <c>Name</c> given should correspond to the filename + <p>The <c><anno>Name</anno></c> given should correspond to the filename of the actual dynamically loadable object file residing in - the directory given as <c>Path</c>, but <em>without</em> the + the directory given as <c><anno>Path</anno></c>, but <em>without</em> the extension (i.e. <c>.so</c>). The driver name provided in the driver initialization routine must correspond with the filename, in much the same way as erlang module names @@ -328,14 +316,14 @@ <p>If the driver has been previously unloaded, but is still present due to open ports against it, a call to <c>load/2</c> will stop the unloading and keep the driver - (as long as the <c>Path</c> is the same) and <c>ok</c> is + (as long as the <c><anno>Path</anno></c> is the same) and <c>ok</c> is returned. If one actually wants the object code to be reloaded, one uses <seealso marker="#reload/2">reload/2</seealso> or the low-level interface <seealso marker="#try_load/3">try_load/3</seealso> instead. Please refer to the description of <seealso marker="#scenarios">different scenarios</seealso> for loading/unloading in the introduction.</p> <p>If more than one process tries to load an already loaded - driver withe the same <c>Path</c>, or if the same process + driver withe the same <c><anno>Path</anno></c>, or if the same process tries to load it several times, the function will return <c>ok</c>. The emulator will keep track of the <c>load/2</c> calls, so that a corresponding number of @@ -349,16 +337,16 @@ several drivers with the same name but with different <c>Path</c> parameters.</p> <note> - <p>Note especially that the <c>Path</c> is interpreted + <p>Note especially that the <c><anno>Path</anno></c> is interpreted literally, so that all loaders of the same driver needs to - give the same <em>literal</em><c>Path</c> string, even + give the same <em>literal</em><c><anno>Path</anno></c> string, even though different paths might point out the same directory in the filesystem (due to use of relative paths and links).</p> </note> <p>On success, the function returns <c>ok</c>. On - failure, the return value is <c>{error,ErrorDesc}</c>, - where <c>ErrorDesc</c> is an opaque term to be + failure, the return value is <c>{error,<anno>ErrorDesc</anno>}</c>, + where <c><anno>ErrorDesc</anno></c> is an opaque term to be translated into human readable form by the <seealso marker="#format_error/1">format_error/1</seealso> function.</p> <p>For more control over the error handling, again use the @@ -369,20 +357,16 @@ </desc> </func> <func> - <name>load_driver(Path, Name) -> ok | {error, ErrorDesc}</name> + <name name="load_driver" arity="2"/> <fsummary>Load a driver</fsummary> - <type> - <v>Path = Name = string() | atom()</v> - <v>ErrorDesc = term()</v> - </type> <desc> <p>Works essentially as <c>load/2</c>, but will load the driver - with options other options. All ports that are using the + with other options. All ports that are using the driver will get killed with the reason <c>driver_unloaded</c> when the driver is to be unloaded.</p> <p>The number of loads and unloads by different <seealso marker="#users">users</seealso> influence the actual loading and unloading of a driver file. The port killing will - therefore only happen when the <em>last</em><seealso marker="#users">user</seealso> unloads the driver, or the + therefore only happen when the <em>last</em> <seealso marker="#users">user</seealso> unloads the driver, or the last process having loaded the driver exits.</p> <p>This interface (or at least the name of the functions) is kept for backward compatibility. Using <seealso marker="#try_load/3">try_load/3</seealso> with @@ -551,16 +535,11 @@ </desc> </func> <func> - <name>reload(Path, Name) -> ok | {error, ErrorDesc}</name> + <name name="reload" arity="2"/> <fsummary>Replace a driver</fsummary> - <type> - <v>Path = Name = string() | atom()</v> - <v>ErrorDesc = pending_process | OpaqueError</v> - <v>OpaqueError = term()</v> - </type> <desc> - <p>Reloads the driver named <c>Name</c> from a possibly - different <c>Path</c> than was previously used. This + <p>Reloads the driver named <c><anno>Name</anno></c> from a possibly + different <c><anno>Path</anno></c> than was previously used. This function is used in the code change <seealso marker="#scenarios">scenario</seealso> described in the introduction.</p> <p>If there are other <seealso marker="#users">users</seealso> @@ -574,7 +553,7 @@ <p>If one wants to avoid hanging on open ports, one should use the <seealso marker="#try_load/3">try_load/3</seealso> function instead.</p> - <p>The <c>Name</c> and <c>Path</c> parameters have exactly the + <p>The <c><anno>Name</anno></c> and <c><anno>Path</anno></c> parameters have exactly the same meaning as when calling the plain <seealso marker="#load/2">load/2</seealso> function.</p> <note> <p>Avoid mixing @@ -594,13 +573,8 @@ </desc> </func> <func> - <name>reload_driver(Path, Name) -> ok | {error, ErrorDesc}</name> + <name name="reload_driver" arity="2"/> <fsummary>Replace a driver</fsummary> - <type> - <v>Path = Name = string() | atom()</v> - <v>ErrorDesc = pending_process | OpaqueError</v> - <v>OpaqueError = term()</v> - </type> <desc> <p>Works exactly as <seealso marker="#reload/2">reload/2</seealso>, but for drivers loaded with the <seealso marker="#load_driver/2">load_driver/2</seealso> interface. </p> @@ -1015,7 +989,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>MonitorOption</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 @@ -1066,15 +1040,11 @@ </desc> </func> <func> - <name>unload(Name) -> ok | {error, ErrorDesc}</name> + <name name="unload" arity="1"/> <fsummary>Unload a driver</fsummary> - <type> - <v>Name = string() | atom()</v> - <v>ErrorDesc = term()</v> - </type> <desc> <p>Unloads, or at least dereferences the driver named - <c>Name</c>. If the caller is the last <seealso marker="#users">user</seealso> of the driver, and there + <c><anno>Name</anno></c>. If the caller is the last <seealso marker="#users">user</seealso> of the driver, and there are no more open ports using the driver, the driver will actually get unloaded. In all other cases, actual unloading will be delayed until all ports are closed and there are no @@ -1084,7 +1054,7 @@ is no longer considered a user of the driver. For usage scenarios, see the <seealso marker="#scenarios">description</seealso> in the beginning of this document. </p> - <p>The <c>ErrorDesc</c> returned is an opaque value to be + <p>The <c><anno>ErrorDesc</anno></c> returned is an opaque value to be passed further on to the <seealso marker="#format_error/1">format_error/1</seealso> function. For more control over the operation, use the <seealso marker="#try_unload/2">try_unload/2</seealso> @@ -1094,15 +1064,11 @@ </desc> </func> <func> - <name>unload_driver(Name) -> ok | {error, ErrorDesc}</name> + <name name="unload_driver" arity="1"/> <fsummary>Unload a driver</fsummary> - <type> - <v>Name = string() | atom()</v> - <v>ErrorDesc = term()</v> - </type> <desc> <p>Unloads, or at least dereferences the driver named - <c>Name</c>. If the caller is the last <seealso marker="#users">user</seealso> of the driver, all + <c><anno>Name</anno></c>. If the caller is the last <seealso marker="#users">user</seealso> of the driver, all remaining open ports using the driver will get killed with the reason <c>driver_unloaded</c> and the driver will eventually get unloaded.</p> @@ -1112,7 +1078,7 @@ <seealso marker="#users">user</seealso>. For usage scenarios, see the <seealso marker="#scenarios">description</seealso> in the beginning of this document.</p> - <p>The <c>ErrorDesc</c> returned is an opaque value to be + <p>The <c><anno>ErrorDesc</anno></c> returned is an opaque value to be passed further on to the <seealso marker="#format_error/1">format_error/1</seealso> function. For more control over the operation, use the <seealso marker="#try_unload/2">try_unload/2</seealso> @@ -1125,7 +1091,7 @@ <name>loaded_drivers() -> {ok, Drivers}</name> <fsummary>List loaded drivers</fsummary> <type> - <v>Drivers = [Driver()]</v> + <v>Drivers = [Driver]</v> <v>Driver = string()</v> </type> <desc> @@ -1138,13 +1104,10 @@ </desc> </func> <func> - <name>format_error(ErrorDesc) -> string()</name> + <name name="format_error" arity="1"/> <fsummary>Format an error descriptor</fsummary> - <type> - <v>ErrorDesc -- see below</v> - </type> <desc> - <p>Takes an <c>ErrorDesc</c> returned by load, unload or + <p>Takes an <c><anno>ErrorDesc</anno></c> returned by load, unload or reload functions and returns a string which describes the error or warning.</p> <note> diff --git a/lib/kernel/doc/src/error_handler.xml b/lib/kernel/doc/src/error_handler.xml index 7f78322472..acbf9a2c6e 100644 --- a/lib/kernel/doc/src/error_handler.xml +++ b/lib/kernel/doc/src/error_handler.xml @@ -37,48 +37,44 @@ </description> <funcs> <func> - <name>undefined_function(Module, Function, Args) -> term()</name> + <name name="undefined_function" arity="3"/> <fsummary>Called when an undefined function is encountered</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - <d>A (possibly empty) list of arguments <c>Arg1,..,ArgN</c></d> - </type> + <type_desc variable="Args"> + A (possibly empty) list of arguments <c>Arg1,..,ArgN</c> + </type_desc> <desc> <p>This function is evaluated if a call is made to - <c>Module:Function(Arg1,.., ArgN)</c> and - <c>Module:Function/N</c> is undefined. Note that + <c><anno>Module</anno>:<anno>Function</anno>(Arg1,.., ArgN)</c> and + <c><anno>Module</anno>:<anno>Function</anno>/N</c> is undefined. Note that <c>undefined_function/3</c> is evaluated inside the process making the original call.</p> - <p>If <c>Module</c> is interpreted, the interpreter is invoked + <p>If <c><anno>Module</anno></c> is interpreted, the interpreter is invoked and the return value of the interpreted - <c>Function(Arg1,.., ArgN)</c> call is returned.</p> + <c><anno>Function</anno>(Arg1,.., ArgN)</c> call is returned.</p> <p>Otherwise, it returns, if possible, the value of - <c>apply(Module, Function, Args)</c> after an attempt has been - made to autoload <c>Module</c>. If this is not possible, the - call to <c>Module:Function(Arg1,.., ArgN)</c> fails with + <c>apply(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> after an attempt has been + made to autoload <c><anno>Module</anno></c>. If this is not possible, the + call to <c><anno>Module</anno>:<anno>Function</anno>(Arg1,.., ArgN)</c> fails with exit reason <c>undef</c>.</p> </desc> </func> <func> - <name>undefined_lambda(Module, Fun, Args) -> term()</name> + <name name="undefined_lambda" arity="3"/> <fsummary>Called when an undefined lambda (fun) is encountered</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - <d>A (possibly empty) list of arguments <c>Arg1,..,ArgN</c></d> - </type> + <type_desc variable="Args"> + A (possibly empty) list of arguments <c>Arg1,..,ArgN</c> + </type_desc> <desc> <p>This function is evaluated if a call is made to - <c>Fun(Arg1,.., ArgN)</c> when the module defining the fun is + <c><anno>Fun</anno>(Arg1,.., ArgN)</c> when the module defining the fun is not loaded. The function is evaluated inside the process making the original call.</p> - <p>If <c>Module</c> is interpreted, the interpreter is invoked + <p>If <c><anno>Module</anno></c> is interpreted, the interpreter is invoked and the return value of the interpreted - <c>Fun(Arg1,.., ArgN)</c> call is returned.</p> + <c><anno>Fun</anno>(Arg1,.., ArgN)</c> call is returned.</p> <p>Otherwise, it returns, if possible, the value of - <c>apply(Fun, Args)</c> after an attempt has been made to - autoload <c>Module</c>. If this is not possible, the call + <c>apply(<anno>Fun</anno>, <anno>Args</anno>)</c> after an attempt has been made to + autoload <c><anno>Module</anno></c>. If this is not possible, the call fails with exit reason <c>undef</c>.</p> </desc> </func> diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml index e107d9b746..2d95f96ac7 100644 --- a/lib/kernel/doc/src/error_logger.xml +++ b/lib/kernel/doc/src/error_logger.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2009</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -65,19 +65,20 @@ be tagged as warnings or info. Tagging them as warnings may require rewriting existing user defined event handlers.</p> </description> + <datatypes> + <datatype> + <name name="report"/> + </datatype> + </datatypes> <funcs> <func> - <name>error_msg(Format) -> ok</name> - <name>error_msg(Format, Data) -> ok</name> - <name>format(Format, Data) -> ok</name> + <name name="error_msg" arity="1"/> + <name name="error_msg" arity="2"/> + <name name="format" arity="2"/> <fsummary>Send an standard error event to the error logger</fsummary> - <type> - <v>Format = string()</v> - <v>Data = [term()]</v> - </type> <desc> <p>Sends a standard error event to the error logger. - The <c>Format</c> and <c>Data</c> arguments are the same as + The <c><anno>Format</anno></c> and <c><anno>Data</anno></c> arguments are the same as the arguments of <c>io:format/2</c>. The event is handled by the standard event handler.</p> <pre> @@ -94,12 +95,8 @@ ok</pre> </desc> </func> <func> - <name>error_report(Report) -> ok</name> + <name name="error_report" arity="1"/> <fsummary>Send a standard error report event to the error logger</fsummary> - <type> - <v>Report = [{Tag, Data} | term()] | string() | term()</v> - <v> Tag = Data = term()</v> - </type> <desc> <p>Sends a standard error report event to the error logger. The event is handled by the standard event handler.</p> @@ -119,18 +116,13 @@ ok</pre> </desc> </func> <func> - <name>error_report(Type, Report) -> ok</name> + <name name="error_report" arity="2"/> <fsummary>Send a user defined error report event to the error logger</fsummary> - <type> - <v>Type = term()</v> - <v>Report = [{Tag, Data} | term()] | string() | term()</v> - <v> Tag = Data = term()</v> - </type> <desc> <p>Sends a user defined error report event to the error logger. An event handler to handle the event is supposed to have been added. The event is ignored by the standard event handler.</p> - <p>It is recommended that <c>Report</c> follows the same + <p>It is recommended that <c><anno>Report</anno></c> follows the same structure as for <c>error_report/1</c>.</p> </desc> </func> @@ -174,16 +166,12 @@ ok</pre> </desc> </func> <func> - <name>warning_msg(Format) -> ok</name> - <name>warning_msg(Format, Data) -> ok</name> + <name name="warning_msg" arity="1"/> + <name name="warning_msg" arity="2"/> <fsummary>Send a standard warning event to the error logger</fsummary> - <type> - <v>Format = string()</v> - <v>Data = [term()]</v> - </type> <desc> <p>Sends a standard warning event to the error logger. - The <c>Format</c> and <c>Data</c> arguments are the same as + The <c><anno>Format</anno></c> and <c><anno>Data</anno></c> arguments are the same as the arguments of <c>io:format/2</c>. The event is handled by the standard event handler. It is tagged either as an error, warning or info, see @@ -196,12 +184,8 @@ ok</pre> </desc> </func> <func> - <name>warning_report(Report) -> ok</name> + <name name="warning_report" arity="1"/> <fsummary>Send a standard warning report event to the error logger</fsummary> - <type> - <v>Report = [{Tag, Data} | term()] | string() | term()</v> - <v> Tag = Data = term()</v> - </type> <desc> <p>Sends a standard warning report event to the error logger. The event is handled by the standard event handler. It is @@ -210,13 +194,8 @@ ok</pre> </desc> </func> <func> - <name>warning_report(Type, Report) -> ok</name> + <name name="warning_report" arity="2"/> <fsummary>Send a user defined warning report event to the error logger</fsummary> - <type> - <v>Type = term()</v> - <v>Report = [{Tag, Data} | term()] | string() | term()</v> - <v> Tag = Data = term()</v> - </type> <desc> <p>Sends a user defined warning report event to the error logger. An event handler to handle the event is supposed to @@ -227,16 +206,12 @@ ok</pre> </desc> </func> <func> - <name>info_msg(Format) -> ok</name> - <name>info_msg(Format, Data) -> ok</name> + <name name="info_msg" arity="1"/> + <name name="info_msg" arity="2"/> <fsummary>Send a standard information event to the error logger</fsummary> - <type> - <v>Format = string()</v> - <v>Data = [term()]</v> - </type> <desc> <p>Sends a standard information event to the error logger. - The <c>Format</c> and <c>Data</c> arguments are the same as + The <c><anno>Format</anno></c> and <c><anno>Data</anno></c> arguments are the same as the arguments of <c>io:format/2</c>. The event is handled by the standard event handler.</p> <pre> @@ -253,12 +228,8 @@ ok</pre> </desc> </func> <func> - <name>info_report(Report) -> ok</name> + <name name="info_report" arity="1"/> <fsummary>Send a standard information report event to the error logger</fsummary> - <type> - <v>Report = [{Tag, Data} | term()] | string() | term()</v> - <v> Tag = Data = term()</v> - </type> <desc> <p>Sends a standard information report event to the error logger. The event is handled by the standard event handler.</p> @@ -278,63 +249,49 @@ ok</pre> </desc> </func> <func> - <name>info_report(Type, Report) -> ok</name> + <name name="info_report" arity="2"/> <fsummary>Send a user defined information report event to the error logger</fsummary> - <type> - <v>Type = term()</v> - <v>Report = [{Tag, Data} | term()] | string() | term()</v> - <v> Tag = Data = term()</v> - </type> <desc> <p>Sends a user defined information report event to the error logger. An event handler to handle the event is supposed to have been added. The event is ignored by the standard event handler.</p> - <p>It is recommended that <c>Report</c> follows the same + <p>It is recommended that <c><anno>Report</anno></c> follows the same structure as for <c>info_report/1</c>.</p> </desc> </func> <func> - <name>add_report_handler(Handler) -> Result</name> - <name>add_report_handler(Handler, Args) -> Result</name> + <name name="add_report_handler" arity="1"/> + <name name="add_report_handler" arity="2"/> <fsummary>Add an event handler to the error logger</fsummary> - <type> - <v>Handler, Args, Result -- see gen_event:add_handler/3</v> - </type> <desc> <p>Adds a new event handler to the error logger. The event handler must be implemented as a <c>gen_event</c> callback module, see <seealso marker="stdlib:gen_event">gen_event(3)</seealso>.</p> - <p><c>Handler</c> is typically the name of the callback module - and <c>Args</c> is an optional term (defaults to []) passed - to the initialization callback function <c>Module:init/1</c>. + <p><c><anno>Handler</anno></c> is typically the name of the callback module + and <c><anno>Args</anno></c> is an optional term (defaults to []) passed + to the initialization callback function <c><anno>Handler</anno>:init/1</c>. The function returns <c>ok</c> if successful.</p> <p>The event handler must be able to handle the <seealso marker="#events">events</seealso> described below.</p> </desc> </func> <func> - <name>delete_report_handler(Handler) -> Result</name> + <name name="delete_report_handler" arity="1"/> <fsummary>Delete an event handler from the error logger</fsummary> - <type> - <v>Handler, Result -- see gen_event:delete_handler/3</v> - </type> <desc> <p>Deletes an event handler from the error logger by calling - <c>gen_event:delete_handler(error_logger, Handler, [])</c>, + <c>gen_event:delete_handler(error_logger, <anno>Handler</anno>, [])</c>, see <seealso marker="stdlib:gen_event">gen_event(3)</seealso>.</p> </desc> </func> <func> - <name>tty(Flag) -> ok</name> + <name name="tty" arity="1"/> <fsummary>Enable or disable printouts to the tty</fsummary> - <type> - <v>Flag = bool()</v> - </type> <desc> - <p>Enables (<c>Flag == true</c>) or disables - (<c>Flag == false</c>) printout of standard events to the tty.</p> + <p>Enables (<c><anno>Flag</anno> == true</c>) or disables + (<c><anno>Flag</anno> == false</c>) printout of standard events to the tty.</p> <p>This is done by adding or deleting the standard event handler for output to tty, thus calling this function overrides the value of the Kernel <c>error_logger</c> configuration @@ -342,13 +299,15 @@ ok</pre> </desc> </func> <func> - <name>logfile(Request) -> ok | Filename | {error, What}</name> + <name name="logfile" arity="1" clause_i="1"/> + <name name="logfile" arity="1" clause_i="2"/> + <name name="logfile" arity="1" clause_i="3"/> + <type variable="Filename"/> + <type variable="OpenReason" name_i="1"/> + <type variable="CloseReason" name_i="2"/> + <type variable="FilenameReason" name_i="3"/> + <type name="open_error"/> <fsummary>Enable or disable error printouts to a file</fsummary> - <type> - <v>Request = {open, Filename} | close | filename</v> - <v> Filename = atom() | string()</v> - <v>What = allready_have_logfile | no_log_file | term()</v> - </type> <desc> <p>Enables or disables printout of standard events to a file.</p> <p>This is done by adding or deleting the standard event handler @@ -361,22 +320,22 @@ ok</pre> There can only be one active log file at a time.</p> <p><c>Request</c> is one of:</p> <taglist> - <tag><c>{open, Filename}</c></tag> + <tag><c>{open, <anno>Filename</anno>}</c></tag> <item> - <p>Opens the log file <c>Filename</c>. Returns <c>ok</c> if + <p>Opens the log file <c><anno>Filename</anno></c>. Returns <c>ok</c> if successful, or <c>{error, allready_have_logfile}</c> if logging to file is already enabled, or an error tuple if - another error occurred. For example, if <c>Filename</c> + another error occurred. For example, if <c><anno>Filename</anno></c> could not be opened.</p> </item> <tag><c>close</c></tag> <item> <p>Closes the current log file. Returns <c>ok</c>, or - <c>{error, What}</c>.</p> + <c>{error, module_not_found}</c>.</p> </item> <tag><c>filename</c></tag> <item> - <p>Returns the name of the log file <c>Filename</c>, or + <p>Returns the name of the log file <c><anno>Filename</anno></c>, or <c>{error, no_log_file}</c> if logging to file is not enabled.</p> </item> diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 36fce464c5..7db20e6343 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>2010</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -60,11 +60,13 @@ converted, why the Unicode mode for file names is not default on systems having completely transparent file naming.</p> - <note>As of R14B01, the most basic file handling modules - (<c>file</c>, <c>prim_file</c>, <c>filelib</c> and - <c>filename</c>) accept raw file names, but the rest of OTP is not - guaranteed to handle them, why Unicode file naming on systems - where it is not default is still considered experimental.</note> + <note> + <p>As of R14B01, the most basic file handling modules + (<c>file</c>, <c>prim_file</c>, <c>filelib</c> and + <c>filename</c>) accept raw file names, but the rest of OTP is not + guaranteed to handle them, why Unicode file naming on systems + where it is not default is still considered experimental.</p> + </note> <p>Raw file names is a new feature in OTP R14B01, which allows the user to supply completely uninterpreted file names to the @@ -93,47 +95,67 @@ is UTF-8...</p> </description> - <section> - <title>DATA TYPES</title> - <code type="none"> -iodata() = iolist() | binary() - iolist() = [char() | binary() | iolist()] - -io_device() - as returned by file:open/2, a process handling IO protocols - -name() = string() | atom() | DeepList | RawFilename - DeepList = [char() | atom() | DeepList] - RawFilename = binary() - If VM is in unicode filename mode, string() and char() are allowed to be > 255. - RawFilename is a filename not subject to Unicode translation, meaning that it - can contain characters not conforming to the Unicode encoding expected from the - filesystem (i.e. non-UTF-8 characters although the VM is started in Unicode - filename mode). - -posix() - an atom which is named from the POSIX error codes used in - Unix, and in the runtime libraries of most C compilers - -ext_posix() = posix() | badarg + <datatypes> + <datatype> + <name name="deep_list"/> + </datatype> + <datatype> + <name name="fd"/> + </datatype> + <datatype> + <name name="filename"/> + </datatype> + <datatype> + <name name="io_device"/> + <desc> + <p>As returned by + <seealso marker="#open/2">file:open/2</seealso>, + a process handling IO protocols.</p> + </desc> + </datatype> + <datatype> + <name name="name"/> + <desc> + <p>If VM is in Unicode filename mode, <c>string()</c> and <c>char()</c> + are allowed to be > 255. + <c><anno>RawFilename</anno></c> is a filename not subject to + Unicode translation, + meaning that it can contain characters not conforming to + the Unicode encoding expected from the filesystem + (i.e. non-UTF-8 characters although the VM is started + in Unicode filename mode). + </p> + </desc> + </datatype> + <datatype> + <name name="posix"/> + <desc> + <p>An atom which is named from the POSIX error codes used in + Unix, and in the runtime libraries of most C compilers.</p> + </desc> + </datatype> + <datatype> + <name name="date_time"/> + <desc> + <p>Must denote a valid date and time.</p> + </desc> + </datatype> + <datatype> + <name name="file_info"/> + </datatype> + <datatype> + <name name="location"/> + </datatype> + <datatype> + <name name="mode"/> + </datatype> + </datatypes> -time() = {{Year, Month, Day}, {Hour, Minute, Second}} - Year = Month = Day = Hour = Minute = Second = int() - Must denote a valid date and time</code> - </section> <funcs> <func> - <name>advise(IoDevice, Offset, Length, Advise) -> ok | {error, Reason}</name> + <name name="advise" arity="4"/> <fsummary>Predeclare an access pattern for file data</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>Offset = int()</v> - <v>Length = int()</v> - <v>Advise = posix_file_advise()</v> - <v>posix_file_advise() = normal | sequential | random | no_reuse - | will_need | dont_need</v> - <v>Reason = ext_posix()</v> - </type> + <type name="posix_file_advise"/> <desc> <p><c>advise/4</c> can be used to announce an intention to access file data in a specific pattern in the future, thus allowing the @@ -142,93 +164,58 @@ time() = {{Year, Month, Day}, {Hour, Minute, Second}} </desc> </func> <func> - <name>change_group(Filename, Gid) -> ok | {error, Reason}</name> + <name name="change_group" arity="2"/> <fsummary>Change group of a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Gid = int()</v> - <v>Reason = ext_posix()</v> - </type> <desc> <p>Changes group of a file. See <seealso marker="#write_file_info/2">write_file_info/2</seealso>.</p> </desc> </func> <func> - <name>change_mode(Filename, Mode) -> ok | {error, Reason}</name> + <name name="change_mode" arity="2"/> <fsummary>Change permissions of a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Mode = int()</v> - <v>Reason = ext_posix()</v> - </type> <desc> <p>Changes permissions of a file. See <seealso marker="#write_file_info/2">write_file_info/2</seealso>.</p> </desc> </func> <func> - <name>change_owner(Filename, Uid) -> ok | {error, Reason}</name> + <name name="change_owner" arity="2"/> <fsummary>Change owner of a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Uid = int()</v> - <v>Reason = ext_posix()</v> - </type> <desc> <p>Changes owner of a file. See <seealso marker="#write_file_info/2">write_file_info/2</seealso>.</p> </desc> </func> <func> - <name>change_owner(Filename, Uid, Gid) -> ok | {error, Reason}</name> + <name name="change_owner" arity="3"/> <fsummary>Change owner and group of a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Uid = int()</v> - <v>Gid = int()</v> - <v>Reason = ext_posix()</v> - </type> <desc> <p>Changes owner and group of a file. See <seealso marker="#write_file_info/2">write_file_info/2</seealso>.</p> </desc> </func> <func> - <name>change_time(Filename, Mtime) -> ok | {error, Reason}</name> + <name name="change_time" arity="2"/> <fsummary>Change the modification time of a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Mtime = time()</v> - <v>Reason = ext_posix()</v> - </type> <desc> <p>Changes the modification and access times of a file. See <seealso marker="#write_file_info/2">write_file_info/2</seealso>.</p> </desc> </func> <func> - <name>change_time(Filename, Mtime, Atime) -> ok | {error, Reason}</name> + <name name="change_time" arity="3"/> <fsummary>Change the modification and last access time of a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Mtime = Atime = time()</v> - <v>Reason = ext_posix()</v> - </type> <desc> <p>Changes the modification and last access times of a file. See <seealso marker="#write_file_info/2">write_file_info/2</seealso>.</p> </desc> </func> <func> - <name>close(IoDevice) -> ok | {error, Reason}</name> + <name name="close" arity="1"/> <fsummary>Close a file</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>Reason = ext_posix() | terminated</v> - </type> <desc> - <p>Closes the file referenced by <c>IoDevice</c>. It mostly + <p>Closes the file referenced by <c><anno>IoDevice</anno></c>. It mostly returns <c>ok</c>, expect for some severe errors such as out of memory.</p> <p>Note that if the option <c>delayed_write</c> was @@ -238,20 +225,13 @@ time() = {{Year, Month, Day}, {Hour, Minute, Second}} </desc> </func> <func> - <name>consult(Filename) -> {ok, Terms} | {error, Reason}</name> + <name name="consult" arity="1"/> <fsummary>Read Erlang terms from a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Terms = [term()]</v> - <v>Reason = ext_posix() | terminated | system_limit - | {Line, Mod, Term}</v> - <v> Line, Mod, Term -- see below</v> - </type> <desc> - <p>Reads Erlang terms, separated by '.', from <c>Filename</c>. - Returns one of the following:</p> + <p>Reads Erlang terms, separated by '.', from + <c><anno>Filename</anno></c>. Returns one of the following:</p> <taglist> - <tag><c>{ok, Terms}</c></tag> + <tag><c>{ok, <anno>Terms</anno>}</c></tag> <item> <p>The file was successfully read.</p> </item> @@ -261,7 +241,8 @@ time() = {{Year, Month, Day}, {Hour, Minute, Second}} See <seealso marker="#open/2">open/2</seealso> for a list of typical error codes.</p> </item> - <tag><c>{error, {Line, Mod, Term}}</c></tag> + <tag><c>{error, {<anno>Line</anno>, <anno>Mod</anno>, + <anno>Term</anno>}}</c></tag> <item> <p>An error occurred when interpreting the Erlang terms in the file. Use <c>format_error/1</c> to convert @@ -270,62 +251,53 @@ time() = {{Year, Month, Day}, {Hour, Minute, Second}} </item> </taglist> <p>Example:</p> - <code type="none"> -f.txt: {person, "kalle", 25}. +<code type="none">f.txt: {person, "kalle", 25}. {person, "pelle", 30}.</code> - <pre> -1> <input>file:consult("f.txt").</input> +<pre>1> <input>file:consult("f.txt").</input> {ok,[{person,"kalle",25},{person,"pelle",30}]}</pre> </desc> </func> <func> - <name>copy(Source, Destination) -></name> - <name>copy(Source, Destination, ByteCount) -> {ok, BytesCopied} | {error, Reason}</name> + <name name="copy" arity="2"/> + <name name="copy" arity="3"/> <fsummary>Copy file contents</fsummary> - <type> - <v>Source = Destination = io_device() | Filename | {Filename, Modes}</v> - <v> Filename = name()</v> - <v> Modes = [Mode] -- see open/2</v> - <v>ByteCount = int() >= 0 | infinity</v> - <v>BytesCopied = int()</v> - </type> <desc> - <p>Copies <c>ByteCount</c> bytes from <c>Source</c> to - <c>Destination</c>. <c>Source</c> and <c>Destination</c> refer + <p>Copies <c><anno>ByteCount</anno></c> bytes from + <c><anno>Source</anno></c> to <c><anno>Destination</anno></c>. + <c><anno>Source</anno></c> and <c><anno>Destination</anno></c> refer to either filenames or IO devices from e.g. <c>open/2</c>. - <c>ByteCount</c> defaults <c>infinity</c>, denoting an + <c><anno>ByteCount</anno></c> defaults to <c>infinity</c>, denoting an infinite number of bytes.</p> - <p>The argument <c>Modes</c> is a list of possible modes, see - <seealso marker="#open/2">open/2</seealso>, and defaults to + <p>The argument <c><anno>Modes</anno></c> is a list of possible modes, + see <seealso marker="#open/2">open/2</seealso>, and defaults to [].</p> - <p>If both <c>Source</c> and <c>Destination</c> refer to + <p>If both <c><anno>Source</anno></c> and + <c><anno>Destination</anno></c> refer to filenames, the files are opened with <c>[read, binary]</c> and <c>[write, binary]</c> prepended to their mode lists, respectively, to optimize the copy.</p> - <p>If <c>Source</c> refers to a filename, it is opened with + <p>If <c><anno>Source</anno></c> refers to a filename, it is opened with <c>read</c> mode prepended to the mode list before the copy, and closed when done.</p> - <p>If <c>Destination</c> refers to a filename, it is opened + <p>If <c><anno>Destination</anno></c> refers to a filename, it is opened with <c>write</c> mode prepended to the mode list before the copy, and closed when done.</p> - <p>Returns <c>{ok, BytesCopied}</c> where <c>BytesCopied</c> is + <p>Returns <c>{ok, <anno>BytesCopied</anno>}</c> where + <c><anno>BytesCopied</anno></c> is the number of bytes that actually was copied, which may be - less than <c>ByteCount</c> if end of file was encountered on - the source. If the operation fails, <c>{error, Reason}</c> is - returned.</p> + less than <c><anno>ByteCount</anno></c> if end of file was + encountered on the source. If the operation fails, + <c>{error, <anno>Reason</anno>}</c> is returned.</p> <p>Typical error reasons: As for <c>open/2</c> if a file had to be opened, and as for <c>read/2</c> and <c>write/2</c>.</p> </desc> </func> <func> - <name>del_dir(Dir) -> ok | {error, Reason}</name> + <name name="del_dir" arity="1"/> <fsummary>Delete a directory</fsummary> - <type> - <v>Dir = name()</v> - <v>Reason = ext_posix()</v> - </type> <desc> - <p>Tries to delete the directory <c>Dir</c>. The directory must + <p>Tries to delete the directory <c><anno>Dir</anno></c>. + The directory must be empty before it can be deleted. Returns <c>ok</c> if successful.</p> <p>Typical error reasons are:</p> @@ -333,7 +305,7 @@ f.txt: {person, "kalle", 25}. <tag><c>eacces</c></tag> <item> <p>Missing search or write permissions for the parent - directories of <c>Dir</c>.</p> + directories of <c><anno>Dir</anno></c>.</p> </item> <tag><c>eexist</c></tag> <item> @@ -345,8 +317,8 @@ f.txt: {person, "kalle", 25}. </item> <tag><c>enotdir</c></tag> <item> - <p>A component of <c>Dir</c> is not a directory. On some - platforms, <c>enoent</c> is returned instead.</p> + <p>A component of <c><anno>Dir</anno></c> is not a directory. + On some platforms, <c>enoent</c> is returned instead.</p> </item> <tag><c>einval</c></tag> <item> @@ -357,15 +329,11 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>delete(Filename) -> ok | {error, Reason}</name> + <name name="delete" arity="1"/> <fsummary>Delete a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Reason = ext_posix()</v> - </type> <desc> - <p>Tries to delete the file <c>Filename</c>. Returns <c>ok</c> - if successful.</p> + <p>Tries to delete the file <c><anno>Filename</anno></c>. + Returns <c>ok</c> if successful.</p> <p>Typical error reasons are:</p> <taglist> <tag><c>enoent</c></tag> @@ -387,30 +355,24 @@ f.txt: {person, "kalle", 25}. </item> <tag><c>einval</c></tag> <item> - <p><c>Filename</c> had an improper type, such as tuple.</p> + <p><c><anno>Filename</anno></c> had an improper type, such as tuple.</p> </item> </taglist> <warning> - <p>In a future release, a bad type for the <c>Filename</c> - argument will probably generate an exception.</p> - <p></p> + <p>In a future release, a bad type for the + <c><anno>Filename</anno></c> argument will probably generate + an exception.</p> </warning> </desc> </func> <func> - <name>eval(Filename) -> ok | {error, Reason}</name> + <name name="eval" arity="1"/> <fsummary>Evaluate Erlang expressions in a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Reason = ext_posix() | terminated | system_limit - | {Line, Mod, Term}</v> - <v> Line, Mod, Term -- see below</v> - </type> <desc> <p>Reads and evaluates Erlang expressions, separated by '.' (or ',', a sequence of expressions is also an expression), from - <c>Filename</c>. The actual result of the evaluation is not - returned; any expression sequence in the file must be there + <c><anno>Filename</anno></c>. The actual result of the evaluation + is not returned; any expression sequence in the file must be there for its side effect. Returns one of the following:</p> <taglist> <tag><c>ok</c></tag> @@ -422,7 +384,8 @@ f.txt: {person, "kalle", 25}. <p>An error occurred when opening the file or reading it. See <c>open/2</c> for a list of typical error codes.</p> </item> - <tag><c>{error, {Line, Mod, Term}}</c></tag> + <tag><c>{error, {<anno>Line</anno>, <anno>Mod</anno>, + <anno>Term</anno>}}</c></tag> <item> <p>An error occurred when interpreting the Erlang expressions in the file. Use <c>format_error/1</c> to @@ -433,18 +396,11 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>eval(Filename, Bindings) -> ok | {error, Reason}</name> + <name name="eval" arity="2"/> <fsummary>Evaluate Erlang expressions in a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Bindings -- see erl_eval(3)</v> - <v>Reason = ext_posix() | terminated | system_limit - | {Line, Mod, Term}</v> - <v> Line, Mod, Term -- see eval/1</v> - </type> <desc> <p>The same as <c>eval/1</c> but the variable bindings - <c>Bindings</c> are used in the evaluation. See + <c><anno>Bindings</anno></c> are used in the evaluation. See <seealso marker="stdlib:erl_eval">erl_eval(3)</seealso> about variable bindings.</p> </desc> @@ -458,27 +414,19 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>format_error(Reason) -> Chars</name> + <name name="format_error" arity="1"/> <fsummary>Return a descriptive string for an error reason</fsummary> - <type> - <v>Reason = atom() | {Line, Mod, Term}</v> - <v> Line, Mod, Term -- see eval/1</v> - <v>Chars = [char() | Chars]</v> - </type> <desc> <p>Given the error reason returned by any function in this module, returns a descriptive string of the error in English.</p> </desc> </func> <func> - <name>get_cwd() -> {ok, Dir} | {error, Reason}</name> + <name name="get_cwd" arity="0"/> <fsummary>Get the current working directory</fsummary> - <type> - <v>Dir = string()</v> - <v>Reason = posix()</v> - </type> <desc> - <p>Returns <c>{ok, Dir}</c>, where <c>Dir</c> is the current + <p>Returns <c>{ok, <anno>Dir</anno>}</c>, where <c><anno>Dir</anno></c> + is the current working directory of the file server.</p> <note> <p>In rare circumstances, this function can fail on Unix. @@ -496,17 +444,14 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>get_cwd(Drive) -> {ok, Dir} | {error, Reason}</name> + <name name="get_cwd" arity="1"/> <fsummary>Get the current working directory for the drive specified</fsummary> - <type> - <v>Drive = string() -- see below</v> - <v>Dir = string()</v> - <v>Reason = ext_posix()</v> - </type> <desc> - <p><c>Drive</c> should be of the form "<c>Letter</c><c>:</c>", - for example "c:". Returns <c>{ok, Dir}</c> or - <c>{error, Reason}</c>, where <c>Dir</c> is the current + <p><c><anno>Drive</anno></c> should be of the form + "<c>Letter</c><c>:</c>", + for example "c:". Returns <c>{ok, <anno>Dir</anno>}</c> or + <c>{error, <anno>Reason</anno>}</c>, where <c><anno>Dir</anno></c> + is the current working directory of the drive specified.</p> <p>This function returns <c>{error, enotsup}</c> on platforms which have no concept of current drive (Unix, for example).</p> @@ -514,7 +459,7 @@ f.txt: {person, "kalle", 25}. <taglist> <tag><c>enotsup</c></tag> <item> - <p>The operating system have no concept of drives.</p> + <p>The operating system has no concept of drives.</p> </item> <tag><c>eacces</c></tag> <item> @@ -522,32 +467,27 @@ f.txt: {person, "kalle", 25}. </item> <tag><c>einval</c></tag> <item> - <p>The format of <c>Drive</c> is invalid.</p> + <p>The format of <c><anno>Drive</anno></c> is invalid.</p> </item> </taglist> </desc> </func> <func> - <name>list_dir(Dir) -> {ok, Filenames} | {error, Reason}</name> + <name name="list_dir" arity="1"/> <fsummary>List files in a directory</fsummary> - <type> - <v>Dir = name()</v> - <v>Filenames = [Filename]</v> - <v> Filename = string()</v> - <v>Reason = ext_posix()</v> - </type> <desc> <p>Lists all the files in a directory. Returns - <c>{ok, Filenames}</c> if successful. Otherwise, it returns - <c>{error, Reason}</c>. <c>Filenames</c> is a list of + <c>{ok, <anno>Filenames</anno>}</c> if successful. + Otherwise, it returns <c>{error, <anno>Reason</anno>}</c>. + <c><anno>Filenames</anno></c> is a list of the names of all the files in the directory. The names are not sorted.</p> <p>Typical error reasons are:</p> <taglist> <tag><c>eacces</c></tag> <item> - <p>Missing search or write permissions for <c>Dir</c> or - one of its parent directories.</p> + <p>Missing search or write permissions for <c><anno>Dir</anno></c> + or one of its parent directories.</p> </item> <tag><c>enoent</c></tag> <item> @@ -557,14 +497,10 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>make_dir(Dir) -> ok | {error, Reason}</name> + <name name="make_dir" arity="1"/> <fsummary>Make a directory</fsummary> - <type> - <v>Dir = name()</v> - <v>Reason = ext_posix()</v> - </type> <desc> - <p>Tries to create the directory <c>Dir</c>. Missing parent + <p>Tries to create the directory <c><anno>Dir</anno></c>. Missing parent directories are <em>not</em> created. Returns <c>ok</c> if successful.</p> <p>Typical error reasons are:</p> @@ -572,15 +508,15 @@ f.txt: {person, "kalle", 25}. <tag><c>eacces</c></tag> <item> <p>Missing search or write permissions for the parent - directories of <c>Dir</c>.</p> + directories of <c><anno>Dir</anno></c>.</p> </item> <tag><c>eexist</c></tag> <item> - <p>There is already a file or directory named <c>Dir</c>.</p> + <p>There is already a file or directory named <c><anno>Dir</anno></c>.</p> </item> <tag><c>enoent</c></tag> <item> - <p>A component of <c>Dir</c> does not exist.</p> + <p>A component of <c><anno>Dir</anno></c> does not exist.</p> </item> <tag><c>enospc</c></tag> <item> @@ -588,35 +524,33 @@ f.txt: {person, "kalle", 25}. </item> <tag><c>enotdir</c></tag> <item> - <p>A component of <c>Dir</c> is not a directory. On some - platforms, <c>enoent</c> is returned instead.</p> + <p>A component of <c><anno>Dir</anno></c> is not a directory. + On some platforms, <c>enoent</c> is returned instead.</p> </item> </taglist> </desc> </func> <func> - <name>make_link(Existing, New) -> ok | {error, Reason}</name> + <name name="make_link" arity="2"/> <fsummary>Make a hard link to a file</fsummary> - <type> - <v>Existing = New = name()</v> - <v>Reason = ext_posix()</v> - </type> <desc> - <p>Makes a hard link from <c>Existing</c> to <c>New</c>, on + <p>Makes a hard link from <c><anno>Existing</anno></c> to + <c><anno>New</anno></c>, on platforms that support links (Unix). This function returns <c>ok</c> if the link was successfully created, or - <c>{error, Reason}</c>. On platforms that do not support + <c>{error, <anno>Reason</anno>}</c>. On platforms that do not support links, <c>{error,enotsup}</c> is returned.</p> <p>Typical error reasons:</p> <taglist> <tag><c>eacces</c></tag> <item> <p>Missing read or write permissions for the parent - directories of <c>Existing</c> or <c>New</c>.</p> + directories of <c><anno>Existing</anno></c> or + <c><anno>New</anno></c>.</p> </item> <tag><c>eexist</c></tag> <item> - <p><c>New</c> already exists.</p> + <p><c><anno>New</anno></c> already exists.</p> </item> <tag><c>enotsup</c></tag> <item> @@ -626,30 +560,28 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>make_symlink(Name1, Name2) -> ok | {error, Reason}</name> + <name name="make_symlink" arity="2"/> <fsummary>Make a symbolic link to a file or directory</fsummary> - <type> - <v>Name1 = Name2 = name()</v> - <v>Reason = ext_posix()</v> - </type> <desc> - <p>This function creates a symbolic link <c>Name2</c> to - the file or directory <c>Name1</c>, on platforms that support - symbolic links (most Unix systems). <c>Name1</c> need not + <p>This function creates a symbolic link <c><anno>Name2</anno></c> to + the file or directory <c><anno>Name1</anno></c>, on platforms that + support + symbolic links (most Unix systems). <c><anno>Name1</anno></c> need not exist. This function returns <c>ok</c> if the link was - successfully created, or <c>{error, Reason}</c>. On platforms + successfully created, or <c>{error, <anno>Reason</anno>}</c>. + On platforms that do not support symbolic links, <c>{error, enotsup}</c> is returned.</p> <p>Typical error reasons:</p> <taglist> <tag><c>eacces</c></tag> <item> - <p>Missing read or write permissions for the parent - directories of <c>Name1</c> or <c>Name2</c>.</p> + <p>Missing read or write permissions for the parent directories + of <c><anno>Name1</anno></c> or <c><anno>Name2</anno></c>.</p> </item> <tag><c>eexist</c></tag> <item> - <p><c>Name2</c> already exists.</p> + <p><c><anno>Name2</anno></c> already exists.</p> </item> <tag><c>enotsup</c></tag> <item> @@ -668,22 +600,12 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>open(Filename, Modes) -> {ok, IoDevice} | {error, Reason}</name> + <name name="open" arity="2"/> <fsummary>Open a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Modes = [Mode]</v> - <v> Mode = read | write | append | exclusive | raw | binary | {delayed_write, Size, Delay} | delayed_write | {read_ahead, Size} | read_ahead | compressed | {encoding, Encoding}</v> - <v> Size = Delay = int()</v> - <v> Encoding = latin1 | unicode | utf8 | utf16 | {utf16, Endian} | utf32 | {utf32, Endian}</v> - <v> Endian = big | little</v> - <v>IoDevice = io_device()</v> - <v>Reason = ext_posix() | system_limit</v> - </type> <desc> - <p>Opens the file <c>Filename</c> in the mode determined by - <c>Modes</c>, which may contain one or more of the following - items:</p> + <p>Opens the file <c><anno>Filename</anno></c> in the mode determined + by <c><anno>Modes</anno></c>, which may contain one or more of the + following items:</p> <taglist> <tag><c>read</c></tag> <item> @@ -841,23 +763,23 @@ f.txt: {person, "kalle", 25}. </taglist> <p>Returns:</p> <taglist> - <tag><c>{ok, IoDevice}</c></tag> + <tag><c>{ok, <anno>IoDevice</anno>}</c></tag> <item> <p>The file has been opened in the requested mode. - <c>IoDevice</c> is a reference to the file.</p> + <c><anno>IoDevice</anno></c> is a reference to the file.</p> </item> - <tag><c>{error, Reason}</c></tag> + <tag><c>{error, <anno>Reason</anno>}</c></tag> <item> <p>The file could not be opened.</p> </item> </taglist> - <p><c>IoDevice</c> is really the pid of the process which + <p><c><anno>IoDevice</anno></c> is really the pid of the process which handles the file. This process is linked to the process which originally opened the file. If any process to which - the <c>IoDevice</c> is linked terminates, the file will be - closed and the process itself will be terminated. - An <c>IoDevice</c> returned from this call can be used as an - argument to the IO functions (see + the <c><anno>IoDevice</anno></c> is linked terminates, the file will + be closed and the process itself will be terminated. + An <c><anno>IoDevice</anno></c> returned from this call can be used + as an argument to the IO functions (see <seealso marker="stdlib:io">io(3)</seealso>).</p> <note> <p>In previous versions of <c>file</c>, modes were given @@ -897,34 +819,25 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>path_consult(Path, Filename) -> {ok, Terms, FullName} | {error, Reason}</name> + <name name="path_consult" arity="2"/> <fsummary>Read Erlang terms from a file</fsummary> - <type> - <v>Path = [Dir]</v> - <v> Dir = name()</v> - <v>Filename = name()</v> - <v>Terms = [term()]</v> - <v>FullName = string()</v> - <v>Reason = ext_posix() | terminated | system_limit - | {Line, Mod, Term}</v> - <v> Line, Mod, Term -- see below</v> - </type> <desc> - <p>Searches the path <c>Path</c> (a list of directory names) - until the file <c>Filename</c> is found. If <c>Filename</c> - is an absolute filename, <c>Path</c> is ignored. + <p>Searches the path <c><anno>Path</anno></c> (a list of directory + names) until the file <c><anno>Filename</anno></c> is found. + If <c><anno>Filename</anno></c> + is an absolute filename, <c><anno>Path</anno></c> is ignored. Then reads Erlang terms, separated by '.', from the file. Returns one of the following:</p> <taglist> - <tag><c>{ok, Terms, FullName}</c></tag> + <tag><c>{ok, <anno>Terms</anno>, <anno>FullName</anno>}</c></tag> <item> - <p>The file was successfully read. <c>FullName</c> is + <p>The file was successfully read. <c><anno>FullName</anno></c> is the full name of the file.</p> </item> <tag><c>{error, enoent}</c></tag> <item> <p>The file could not be found in any of the directories in - <c>Path</c>.</p> + <c><anno>Path</anno></c>.</p> </item> <tag><c>{error, atom()}</c></tag> <item> @@ -932,7 +845,8 @@ f.txt: {person, "kalle", 25}. See <seealso marker="#open/2">open/2</seealso> for a list of typical error codes.</p> </item> - <tag><c>{error, {Line, Mod, Term}}</c></tag> + <tag><c>{error, {<anno>Line</anno>, <anno>Mod</anno>, + <anno>Term</anno>}}</c></tag> <item> <p>An error occurred when interpreting the Erlang terms in the file. Use <c>format_error/1</c> to convert @@ -943,36 +857,28 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>path_eval(Path, Filename) -> {ok, FullName} | {error, Reason}</name> + <name name="path_eval" arity="2"/> <fsummary>Evaluate Erlang expressions in a file</fsummary> - <type> - <v>Path = [Dir]</v> - <v> Dir = name()</v> - <v>Filename = name()</v> - <v>FullName = string()</v> - <v>Reason = ext_posix() | terminated | system_limit - | {Line, Mod, Term}</v> - <v> Line, Mod, Term -- see below</v> - </type> <desc> - <p>Searches the path <c>Path</c> (a list of directory names) - until the file <c>Filename</c> is found. If <c>Filename</c> - is an absolute file name, <c>Path</c> is ignored. Then reads + <p>Searches the path <c><anno>Path</anno></c> (a list of directory + names) until the file <c><anno>Filename</anno></c> is found. + If <c><anno>Filename</anno></c> is an absolute file name, + <c><anno>Path</anno></c> is ignored. Then reads and evaluates Erlang expressions, separated by '.' (or ',', a sequence of expressions is also an expression), from the file. The actual result of evaluation is not returned; any expression sequence in the file must be there for its side effect. Returns one of the following:</p> <taglist> - <tag><c>{ok, FullName}</c></tag> + <tag><c>{ok, <anno>FullName</anno>}</c></tag> <item> - <p>The file was read and evaluated. <c>FullName</c> is + <p>The file was read and evaluated. <c><anno>FullName</anno></c> is the full name of the file.</p> </item> <tag><c>{error, enoent}</c></tag> <item> <p>The file could not be found in any of the directories in - <c>Path</c>.</p> + <c><anno>Path</anno></c>.</p> </item> <tag><c>{error, atom()}</c></tag> <item> @@ -980,7 +886,8 @@ f.txt: {person, "kalle", 25}. See <seealso marker="#open/2">open/2</seealso> for a list of typical error codes.</p> </item> - <tag><c>{error, {Line, Mod, Term}}</c></tag> + <tag><c>{error, {<anno>Line</anno>, <anno>Mod</anno>, + <anno>Term</anno>}}</c></tag> <item> <p>An error occurred when interpreting the Erlang expressions in the file. Use <c>format_error/1</c> to @@ -991,34 +898,26 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>path_open(Path, Filename, Modes) -> {ok, IoDevice, FullName} | {error, Reason}</name> + <name name="path_open" arity="3"/> <fsummary>Open a file</fsummary> - <type> - <v>Path = [Dir]</v> - <v> Dir = name()</v> - <v>Filename = name()</v> - <v>Modes = [Mode] -- see open/2</v> - <v>IoDevice = io_device()</v> - <v>FullName = string()</v> - <v>Reason = ext_posix() | system_limit</v> - </type> <desc> - <p>Searches the path <c>Path</c> (a list of directory names) - until the file <c>Filename</c> is found. If <c>Filename</c> - is an absolute file name, <c>Path</c> is ignored. - Then opens the file in the mode determined by <c>Modes</c>. + <p>Searches the path <c><anno>Path</anno></c> (a list of directory + names) until the file <c><anno>Filename</anno></c> is found. + If <c><anno>Filename</anno></c> + is an absolute file name, <c><anno>Path</anno></c> is ignored. + Then opens the file in the mode determined by <c><anno>Modes</anno></c>. Returns one of the following:</p> <taglist> - <tag><c>{ok, IoDevice, FullName}</c></tag> + <tag><c>{ok, <anno>IoDevice</anno>, <anno>FullName</anno>}</c></tag> <item> <p>The file has been opened in the requested mode. - <c>IoDevice</c> is a reference to the file and - <c>FullName</c> is the full name of the file.</p> + <c><anno>IoDevice</anno></c> is a reference to the file and + <c><anno>FullName</anno></c> is the full name of the file.</p> </item> <tag><c>{error, enoent}</c></tag> <item> <p>The file could not be found in any of the directories in - <c>Path</c>.</p> + <c><anno>Path</anno></c>.</p> </item> <tag><c>{error, atom()}</c></tag> <item> @@ -1028,36 +927,27 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>path_script(Path, Filename) -> {ok, Value, FullName} | {error, Reason}</name> + <name name="path_script" arity="2"/> <fsummary>Evaluate and return the value of Erlang expressions in a file</fsummary> - <type> - <v>Path = [Dir]</v> - <v> Dir = name()</v> - <v>Filename = name()</v> - <v>Value = term()</v> - <v>FullName = string()</v> - <v>Reason = ext_posix() | terminated | system_limit - | {Line, Mod, Term}</v> - <v> Line, Mod, Term -- see below</v> - </type> <desc> - <p>Searches the path <c>Path</c> (a list of directory names) - until the file <c>Filename</c> is found. If <c>Filename</c> - is an absolute file name, <c>Path</c> is ignored. Then reads + <p>Searches the path <c><anno>Path</anno></c> (a list of directory + names) until the file <c><anno>Filename</anno></c> is found. + If <c><anno>Filename</anno></c> is an absolute file name, + <c><anno>Path</anno></c> is ignored. Then reads and evaluates Erlang expressions, separated by '.' (or ',', a sequence of expressions is also an expression), from the file. Returns one of the following:</p> <taglist> - <tag><c>{ok, Value, FullName}</c></tag> + <tag><c>{ok, <anno>Value</anno>, <anno>FullName</anno>}</c></tag> <item> - <p>The file was read and evaluated. <c>FullName</c> is - the full name of the file and <c>Value</c> the value of + <p>The file was read and evaluated. <c><anno>FullName</anno></c> is + the full name of the file and <c><anno>Value</anno></c> the value of the last expression.</p> </item> <tag><c>{error, enoent}</c></tag> <item> <p>The file could not be found in any of the directories in - <c>Path</c>.</p> + <c><anno>Path</anno></c>.</p> </item> <tag><c>{error, atom()}</c></tag> <item> @@ -1065,7 +955,8 @@ f.txt: {person, "kalle", 25}. See <seealso marker="#open/2">open/2</seealso> for a list of typical error codes.</p> </item> - <tag><c>{error, {Line, Mod, Term}}</c></tag> + <tag><c>{error, {<anno>Line</anno>, <anno>Mod</anno>, + <anno>Term</anno>}}</c></tag> <item> <p>An error occurred when interpreting the Erlang expressions in the file. Use <c>format_error/1</c> to @@ -1076,42 +967,28 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>path_script(Path, Filename, Bindings) -> {ok, Value, FullName} | {error, Reason}</name> + <name name="path_script" arity="3"/> <fsummary>Evaluate and return the value of Erlang expressions in a file</fsummary> - <type> - <v>Path = [Dir]</v> - <v> Dir = name()</v> - <v>Filename = name()</v> - <v>Bindings -- see erl_eval(3)</v> - <v>Value = term()</v> - <v>FullName = string()</v> - <v>Reason = posix() | terminated | system_limit - | {Line, Mod, Term}</v> - <v> Line, Mod, Term -- see path_script/2</v> - </type> <desc> <p>The same as <c>path_script/2</c> but the variable bindings - <c>Bindings</c> are used in the evaluation. See + <c><anno>Bindings</anno></c> are used in the evaluation. See <seealso marker="stdlib:erl_eval">erl_eval(3)</seealso> about variable bindings.</p> </desc> </func> <func> - <name>pid2name(Pid) -> string() | undefined</name> + <name name="pid2name" arity="1"/> <fsummary>Return the name of the file handled by a pid</fsummary> - <type> - <v>Pid = pid()</v> - </type> <desc> - <p>If <c>Pid</c> is an IO device, that is, a pid returned from + <p>If <c><anno>Pid</anno></c> is an IO device, that is, a pid returned from <c>open/2</c>, this function returns the filename, or rather:</p> <taglist> - <tag><c>{ok, Filename}</c></tag> + <tag><c>{ok, <anno>Filename</anno>}</c></tag> <item> <p>If this node's file server is not a slave, the file was opened by this node's file server, (this implies that - <c>Pid</c> must be a local pid) and the file is not - closed. <c>Filename</c> is the filename in flat string + <c><anno>Pid</anno></c> must be a local pid) and the file is not + closed. <c><anno>Filename</anno></c> is the filename in flat string format.</p> </item> <tag><c>undefined</c></tag> @@ -1125,21 +1002,15 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>position(IoDevice, Location) -> {ok, NewPosition} | {error, Reason}</name> + <name name="position" arity="2"/> <fsummary>Set position in a file</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>Location = Offset | {bof, Offset} | {cur, Offset} | {eof, Offset} | bof | cur | eof</v> - <v> Offset = int()</v> - <v>NewPosition = int()</v> - <v>Reason = ext_posix() | terminated</v> - </type> <desc> - <p>Sets the position of the file referenced by <c>IoDevice</c> - to <c>Location</c>. Returns <c>{ok, NewPosition}</c> (as + <p>Sets the position of the file referenced by <c><anno>IoDevice</anno></c> + to <c><anno>Location</anno></c>. Returns + <c>{ok, <anno>NewPosition</anno>}</c> (as absolute offset) if successful, otherwise - <c>{error, Reason}</c>. <c>Location</c> is one of - the following:</p> + <c>{error, <anno>Reason</anno>}</c>. <c><anno>Location</anno></c> is + one of the following:</p> <taglist> <tag><c>Offset</c></tag> <item> @@ -1167,7 +1038,8 @@ f.txt: {person, "kalle", 25}. <taglist> <tag><c>einval</c></tag> <item> - <p>Either <c>Location</c> was illegal, or it evaluated to a + <p>Either <c><anno>Location</anno></c> was illegal, or it + evaluated to a negative offset in the file. Note that if the resulting position is a negative value, the result is an error, and after the call the file position is undefined.</p> @@ -1176,22 +1048,14 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>pread(IoDevice, LocNums) -> {ok, DataL} | eof | {error, Reason}</name> + <name name="pread" arity="2"/> <fsummary>Read from a file at certain positions</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>LocNums = [{Location, Number}]</v> - <v> Location -- see position/2</v> - <v> Number = int()</v> - <v>DataL = [Data]</v> - <v> Data = [char()] | binary()</v> - <v>Reason = ext_posix() | terminated</v> - </type> <desc> <p>Performs a sequence of <c>pread/3</c> in one operation, which is more efficient than calling them one at a time. - Returns <c>{ok, [Data, ...]}</c> or <c>{error, Reason}</c>, - where each <c>Data</c>, the result of the corresponding + Returns <c>{ok, [<anno>Data</anno>, ...]}</c> or + <c>{error, <anno>Reason</anno>}</c>, + where each <c><anno>Data</anno></c>, the result of the corresponding <c>pread</c>, is either a list or a binary depending on the mode of the file, or <c>eof</c> if the requested position was beyond end of file.</p> @@ -1199,76 +1063,53 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>pread(IoDevice, Location, Number) -> {ok, Data} | eof | {error, Reason}</name> + <name name="pread" arity="3"/> <fsummary>Read from a file at a certain position</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>Location -- see position/2</v> - <v>Number = int()</v> - <v>Data = [char()] | binary()</v> - <v>Reason = ext_posix() | terminated</v> - </type> <desc> <p>Combines <c>position/2</c> and <c>read/2</c> in one operation, which is more efficient than calling them one at a - time. If <c>IoDevice</c> has been opened in raw mode, some - restrictions apply: <c>Location</c> is only allowed to be an + time. If <c><anno>IoDevice</anno></c> has been opened in raw mode, + some restrictions apply: <c><anno>Location</anno></c> is only allowed + to be an integer; and the current position of the file is undefined after the operation.</p> <p>As the position is given as a byte-offset, special caution has to be taken when working with files where <c>encoding</c> is set to something else than <c>latin1</c>, as not every byte position will be a valid character boundary on such a file.</p> </desc> </func> <func> - <name>pwrite(IoDevice, LocBytes) -> ok | {error, {N, Reason}}</name> + <name name="pwrite" arity="2"/> <fsummary>Write to a file at certain positions</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>LocBytes = [{Location, Bytes}]</v> - <v> Location -- see position/2</v> - <v> Bytes = iodata()</v> - <v>N = int()</v> - <v>Reason = ext_posix() | terminated</v> - </type> <desc> <p>Performs a sequence of <c>pwrite/3</c> in one operation, which is more efficient than calling them one at a time. - Returns <c>ok</c> or <c>{error, {N, Reason}}</c>, where - <c>N</c> is the number of successful writes that was done + Returns <c>ok</c> or <c>{error, {<anno>N</anno>, + <anno>Reason</anno>}}</c>, where + <c><anno>N</anno></c> is the number of successful writes that was done before the failure.</p> <p>When positioning in a file with other <c>encoding</c> than <c>latin1</c>, caution must be taken to set the position on a correct character boundary, see <seealso marker="#position/2">position/2</seealso> for details.</p> </desc> </func> <func> - <name>pwrite(IoDevice, Location, Bytes) -> ok | {error, Reason}</name> + <name name="pwrite" arity="3"/> <fsummary>Write to a file at a certain position</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>Location -- see position/2</v> - <v>Bytes = iodata()</v> - <v>Reason = ext_posix() | terminated</v> - </type> <desc> <p>Combines <c>position/2</c> and <c>write/2</c> in one operation, which is more efficient than calling them one at a - time. If <c>IoDevice</c> has been opened in raw mode, some - restrictions apply: <c>Location</c> is only allowed to be an + time. If <c><anno>IoDevice</anno></c> has been opened in raw mode, + some restrictions apply: <c><anno>Location</anno></c> is only allowed + to be an integer; and the current position of the file is undefined after the operation.</p> <p>When positioning in a file with other <c>encoding</c> than <c>latin1</c>, caution must be taken to set the position on a correct character boundary, see <seealso marker="#position/2">position/2</seealso> for details.</p> </desc> </func> <func> - <name>read(IoDevice, Number) -> {ok, Data} | eof | {error, Reason}</name> + <name name="read" arity="2"/> <fsummary>Read from a file</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>Number = int()</v> - <v>Data = [char()] | binary()</v> - <v>Reason = ext_posix() | terminated</v> - </type> <desc> - <p>Reads <c>Number</c> bytes/characters from the file referenced by - <c>IoDevice</c>. The functions <c>read/2</c>, <c>pread/3</c> + <p>Reads <c><anno>Number</anno></c> bytes/characters from the file + referenced by <c><anno>IoDevice</anno></c>. The functions + <c>read/2</c>, <c>pread/3</c> and <c>read_line/1</c> are the only ways to read from a file opened in raw mode (although they work for normally opened files, too).</p> @@ -1276,7 +1117,7 @@ f.txt: {person, "kalle", 25}. <p>Also if <c>encoding</c> is set to something else than <c>latin1</c>, the <c>read/3</c> call will fail if the data contains characters larger than 255, why the <seealso marker="stdlib:io">io(3)</seealso> module is to be preferred when reading such a file.</p> <p>The function returns:</p> <taglist> - <tag><c>{ok, Data}</c></tag> + <tag><c>{ok, <anno>Data</anno>}</c></tag> <item> <p>If the file was opened in binary mode, the read bytes are returned in a binary, otherwise in a list. The list or @@ -1285,10 +1126,10 @@ f.txt: {person, "kalle", 25}. </item> <tag><c>eof</c></tag> <item> - <p>Returned if <c>Number>0</c> and end of file was reached - before anything at all could be read.</p> + <p>Returned if <c><anno>Number</anno>>0</c> and end of file was + reached before anything at all could be read.</p> </item> - <tag><c>{error, Reason}</c></tag> + <tag><c>{error, <anno>Reason</anno>}</c></tag> <item> <p>An error occurred.</p> </item> @@ -1307,17 +1148,14 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>read_file(Filename) -> {ok, Binary} | {error, Reason}</name> + <name name="read_file" arity="1"/> <fsummary>Read a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Binary = binary()</v> - <v>Reason = ext_posix() | terminated | system_limit</v> - </type> <desc> - <p>Returns <c>{ok, Binary}</c>, where <c>Binary</c> is a binary - data object that contains the contents of <c>Filename</c>, or - <c>{error, Reason}</c> if an error occurs.</p> + <p>Returns <c>{ok, <anno>Binary</anno>}</c>, where + <c><anno>Binary</anno></c> is a binary + data object that contains the contents of + <c><anno>Filename</anno></c>, or + <c>{error, <anno>Reason</anno>}</c> if an error occurs.</p> <p>Typical error reasons:</p> <taglist> <tag><c>enoent</c></tag> @@ -1346,17 +1184,13 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>read_file_info(Filename) -> {ok, FileInfo} | {error, Reason}</name> + <name name="read_file_info" arity="1"/> <fsummary>Get information about a file</fsummary> - <type> - <v>Filename = name()</v> - <v>FileInfo = #file_info{}</v> - <v>Reason = ext_posix()</v> - </type> <desc> <p>Retrieves information about a file. Returns - <c>{ok, FileInfo}</c> if successful, otherwise - <c>{error, Reason}</c>. <c>FileInfo</c> is a record + <c>{ok, <anno>FileInfo</anno>}</c> if successful, otherwise + <c>{error, <anno>Reason</anno>}</c>. <c><anno>FileInfo</anno></c> + is a record <c>file_info</c>, defined in the Kernel include file <c>file.hrl</c>. Include the following directive in the module from which the function is called:</p> @@ -1364,7 +1198,7 @@ f.txt: {person, "kalle", 25}. -include_lib("kernel/include/file.hrl").</code> <p>The record <c>file_info</c> contains the following fields.</p> <taglist> - <tag><c>size = int()</c></tag> + <tag><c>size = integer()</c></tag> <item> <p>Size of file in bytes.</p> </item> @@ -1376,22 +1210,22 @@ f.txt: {person, "kalle", 25}. <item> <p>The current system access to the file.</p> </item> - <tag><c>atime = time()</c></tag> + <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso></c></tag> <item> <p>The last (local) time the file was read.</p> </item> - <tag><c>mtime = time()</c></tag> + <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso></c></tag> <item> <p>The last (local) time the file was written.</p> </item> - <tag><c>ctime = time()</c></tag> + <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso></c></tag> <item> <p>The interpretation of this time field depends on the operating system. On Unix, it is the last time the file or the inode was changed. In Windows, it is the create time.</p> </item> - <tag><c>mode = int()</c></tag> + <tag><c>mode = integer()</c></tag> <item> <p>The file permissions as the sum of the following bit values:</p> @@ -1422,33 +1256,33 @@ f.txt: {person, "kalle", 25}. <p>On Unix platforms, other bits than those listed above may be set.</p> </item> - <tag><c>links = int()</c></tag> + <tag><c>links = integer()</c></tag> <item> <p>Number of links to the file (this will always be 1 for file systems which have no concept of links).</p> </item> - <tag><c>major_device = int()</c></tag> + <tag><c>major_device = integer()</c></tag> <item> <p>Identifies the file system where the file is located. In Windows, the number indicates a drive as follows: 0 means A:, 1 means B:, and so on.</p> </item> - <tag><c>minor_device = int()</c></tag> + <tag><c>minor_device = integer()</c></tag> <item> <p>Only valid for character devices on Unix. In all other cases, this field is zero.</p> </item> - <tag><c>inode = int()</c></tag> + <tag><c>inode = integer()</c></tag> <item> <p>Gives the <c>inode</c> number. On non-Unix file systems, this field will be zero.</p> </item> - <tag><c>uid = int()</c></tag> + <tag><c>uid = integer()</c></tag> <item> <p>Indicates the owner of the file. Will be zero for non-Unix file systems.</p> </item> - <tag><c>gid = int()</c></tag> + <tag><c>gid = integer()</c></tag> <item> <p>Gives the group that the owner of the file belongs to. Will be zero for non-Unix file systems.</p> @@ -1474,21 +1308,16 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>read_line(IoDevice) -> {ok, Data} | eof | {error, Reason}</name> + <name name="read_line" arity="1"/> <fsummary>Read a line from a file</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>Data = [char()] | binary()</v> - <v>Reason = ext_posix() | terminated</v> - </type> <desc> <p>Reads a line of bytes/characters from the file referenced by - <c>IoDevice</c>. Lines are defined to be delimited by the linefeed (LF, <c>\n</c>) character, but any carriage return (CR, <c>\r</c>) followed by a newline is also treated as a single LF character (the carriage return is silently ignored). The line is returned <em>including</em> the LF, but excluding any CR immediately followed by a LF. This behaviour is consistent with the behaviour of <seealso marker="stdlib:io#get_line/2">io:get_line/2</seealso>. If end of file is reached without any LF ending the last line, a line with no trailing LF is returned.</p> + <c><anno>IoDevice</anno></c>. Lines are defined to be delimited by the linefeed (LF, <c>\n</c>) character, but any carriage return (CR, <c>\r</c>) followed by a newline is also treated as a single LF character (the carriage return is silently ignored). The line is returned <em>including</em> the LF, but excluding any CR immediately followed by a LF. This behaviour is consistent with the behaviour of <seealso marker="stdlib:io#get_line/2">io:get_line/2</seealso>. If end of file is reached without any LF ending the last line, a line with no trailing LF is returned.</p> <p>The function can be used on files opened in <c>raw</c> mode. It is however inefficient to use it on <c>raw</c> files if the file is not opened with the option <c>{read_ahead, Size}</c> specified, why combining <c>raw</c> and <c>{read_ahead, Size}</c> is highly recommended when opening a text file for raw line oriented reading.</p> <p>If <c>encoding</c> is set to something else than <c>latin1</c>, the <c>read_line/1</c> call will fail if the data contains characters larger than 255, why the <seealso marker="stdlib:io">io(3)</seealso> module is to be preferred when reading such a file.</p> <p>The function returns:</p> <taglist> - <tag><c>{ok, Data}</c></tag> + <tag><c>{ok, <anno>Data</anno>}</c></tag> <item> <p>One line from the file is returned, including the trailing LF, but with CRLF sequences replaced by a single LF (see above).</p> <p>If the file was opened in binary mode, the read bytes are @@ -1499,7 +1328,7 @@ f.txt: {person, "kalle", 25}. <p>Returned if end of file was reached before anything at all could be read.</p> </item> - <tag><c>{error, Reason}</c></tag> + <tag><c>{error, <anno>Reason</anno>}</c></tag> <item> <p>An error occurred.</p> </item> @@ -1518,23 +1347,19 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>read_link(Name) -> {ok, Filename} | {error, Reason}</name> + <name name="read_link" arity="1"/> <fsummary>See what a link is pointing to</fsummary> - <type> - <v>Name = name()</v> - <v>Filename = string()</v> - <v>Reason = ext_posix()</v> - </type> <desc> - <p>This function returns <c>{ok, Filename}</c> if <c>Name</c> - refers to a symbolic link or <c>{error, Reason}</c> otherwise. + <p>This function returns <c>{ok, <anno>Filename</anno>}</c> if + <c><anno>Name</anno></c> refers to a symbolic link or + <c>{error, <anno>Reason</anno>}</c> otherwise. On platforms that do not support symbolic links, the return value will be <c>{error,enotsup}</c>.</p> <p>Typical error reasons:</p> <taglist> <tag><c>einval</c></tag> <item> - <p><c>Linkname</c> does not refer to a symbolic link.</p> + <p><c><anno>Name</anno></c> does not refer to a symbolic link.</p> </item> <tag><c>enoent</c></tag> <item> @@ -1548,34 +1373,26 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>read_link_info(Name) -> {ok, FileInfo} | {error, Reason}</name> + <name name="read_link_info" arity="1"/> <fsummary>Get information about a link or file</fsummary> - <type> - <v>Name = name()</v> - <v>FileInfo = #file_info{}, see read_file_info/1</v> - <v>Reason = ext_posix()</v> - </type> <desc> <p>This function works like <c>read_file_info/1</c>, except that - if <c>Name</c> is a symbolic link, information about the link - will be returned in the <c>file_info</c> record and + if <c><anno>Name</anno></c> is a symbolic link, information about + the link will be returned in the <c>file_info</c> record and the <c>type</c> field of the record will be set to <c>symlink</c>.</p> - <p>If <c>Name</c> is not a symbolic link, this function returns + <p>If <c><anno>Name</anno></c> is not a symbolic link, this function returns exactly the same result as <c>read_file_info/1</c>. On platforms that do not support symbolic links, this function is always equivalent to <c>read_file_info/1</c>.</p> </desc> </func> <func> - <name>rename(Source, Destination) -> ok | {error, Reason}</name> + <name name="rename" arity="2"/> <fsummary>Rename a file</fsummary> - <type> - <v>Source = Destination = name()</v> - <v>Reason = ext_posix()</v> - </type> <desc> - <p>Tries to rename the file <c>Source</c> to <c>Destination</c>. + <p>Tries to rename the file <c><anno>Source</anno></c> to + <c><anno>Destination</anno></c>. It can be used to move files (and directories) between directories, but it is not sufficient to specify the destination only. The destination file name must also be @@ -1593,25 +1410,28 @@ f.txt: {person, "kalle", 25}. <tag><c>eacces</c></tag> <item> <p>Missing read or write permissions for the parent - directories of <c>Source</c> or <c>Destination</c>. On + directories of <c><anno>Source</anno></c> or + <c><anno>Destination</anno></c>. On some platforms, this error is given if either - <c>Source</c> or <c>Destination</c> is open.</p> + <c><anno>Source</anno></c> or <c><anno>Destination</anno></c> + is open.</p> </item> <tag><c>eexist</c></tag> <item> - <p><c>Destination</c> is not an empty directory. On some - platforms, also given when <c>Source</c> and - <c>Destination</c> are not of the same type.</p> + <p><c><anno>Destination</anno></c> is not an empty directory. + On some platforms, also given when <c><anno>Source</anno></c> and + <c><anno>Destination</anno></c> are not of the same type.</p> </item> <tag><c>einval</c></tag> <item> - <p><c>Source</c> is a root directory, or <c>Destination</c> - is a sub-directory of <c>Source</c>.</p> + <p><c><anno>Source</anno></c> is a root directory, or + <c><anno>Destination</anno></c> + is a sub-directory of <c><anno>Source</anno></c>.</p> </item> <tag><c>eisdir</c></tag> <item> - <p><c>Destination</c> is a directory, but <c>Source</c> is - not.</p> + <p><c><anno>Destination</anno></c> is a directory, but + <c><anno>Source</anno></c> is not.</p> </item> <tag><c>enoent</c></tag> <item> @@ -1619,35 +1439,28 @@ f.txt: {person, "kalle", 25}. </item> <tag><c>enotdir</c></tag> <item> - <p><c>Source</c> is a directory, but <c>Destination</c> is - not.</p> + <p><c><anno>Source</anno></c> is a directory, but + <c><anno>Destination</anno></c> is not.</p> </item> <tag><c>exdev</c></tag> <item> - <p><c>Source</c> and <c>Destination</c> are on different - file systems.</p> + <p><c><anno>Source</anno></c> and <c><anno>Destination</anno></c> + are on different file systems.</p> </item> </taglist> </desc> </func> <func> - <name>script(Filename) -> {ok, Value} | {error, Reason}</name> + <name name="script" arity="1"/> <fsummary>Evaluate and return the value of Erlang expressions in a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Value = term()</v> - <v>Reason = ext_posix() | terminated | system_limit - | {Line, Mod, Term}</v> - <v> Line, Mod, Term -- see below</v> - </type> <desc> <p>Reads and evaluates Erlang expressions, separated by '.' (or ',', a sequence of expressions is also an expression), from the file. Returns one of the following:</p> <taglist> - <tag><c>{ok, Value}</c></tag> + <tag><c>{ok, <anno>Value</anno>}</c></tag> <item> - <p>The file was read and evaluated. <c>Value</c> is + <p>The file was read and evaluated. <c><anno>Value</anno></c> is the value of the last expression.</p> </item> <tag><c>{error, atom()}</c></tag> @@ -1656,7 +1469,8 @@ f.txt: {person, "kalle", 25}. See <seealso marker="#open/2">open/2</seealso> for a list of typical error codes.</p> </item> - <tag><c>{error, {Line, Mod, Term}}</c></tag> + <tag><c>{error, {<anno>Line</anno>, <anno>Mod</anno>, + <anno>Term</anno>}}</c></tag> <item> <p>An error occurred when interpreting the Erlang expressions in the file. Use <c>format_error/1</c> to @@ -1667,33 +1481,21 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>script(Filename, Bindings) -> {ok, Value} | {error, Reason}</name> + <name name="script" arity="2"/> <fsummary>Evaluate and return the value of Erlang expressions in a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Bindings -- see erl_eval(3)</v> - <v>Value = term()</v> - <v>Reason = ext_posix() | terminated | system_limit - | {Line, Mod, Term}</v> - <v> Line, Mod, Term -- see below</v> - </type> <desc> <p>The same as <c>script/1</c> but the variable bindings - <c>Bindings</c> are used in the evaluation. See + <c><anno>Bindings</anno></c> are used in the evaluation. See <seealso marker="stdlib:erl_eval">erl_eval(3)</seealso> about variable bindings.</p> </desc> </func> <func> - <name>set_cwd(Dir) -> ok | {error,Reason}</name> + <name name="set_cwd" arity="1"/> <fsummary>Set the current working directory</fsummary> - <type> - <v>Dir = name()</v> - <v>Reason = ext_posix()</v> - </type> <desc> <p>Sets the current working directory of the file server to - <c>Dir</c>. Returns <c>ok</c> if successful.</p> + <c><anno>Dir</anno></c>. Returns <c>ok</c> if successful.</p> <p>Typical error reasons are:</p> <taglist> <tag><c>enoent</c></tag> @@ -1702,8 +1504,8 @@ f.txt: {person, "kalle", 25}. </item> <tag><c>enotdir</c></tag> <item> - <p>A component of <c>Dir</c> is not a directory. On some - platforms, <c>enoent</c> is returned.</p> + <p>A component of <c><anno>Dir</anno></c> is not a directory. + On some platforms, <c>enoent</c> is returned.</p> </item> <tag><c>eacces</c></tag> <item> @@ -1712,23 +1514,20 @@ f.txt: {person, "kalle", 25}. </item> <tag><c>badarg</c></tag> <item> - <p><c>Filename</c> had an improper type, such as tuple.</p> + <p><c><anno>Dir</anno></c> had an improper type, + such as tuple.</p> </item> </taglist> <warning> - <p>In a future release, a bad type for the <c>Filename</c> + <p>In a future release, a bad type for the + <c><anno>Dir</anno></c> argument will probably generate an exception.</p> - <p></p> </warning> </desc> </func> <func> - <name>sync(IoDevice) -> ok | {error, Reason}</name> + <name name="sync" arity="1"/> <fsummary>Synchronizes the in-memory state of a file with that on the physical medium</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>Reason = ext_posix() | terminated</v> - </type> <desc> <p>Makes sure that any buffers kept by the operating system (not by the Erlang runtime system) are written to disk. On @@ -1743,12 +1542,8 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>datasync(IoDevice) -> ok | {error, Reason}</name> + <name name="datasync" arity="1"/> <fsummary>Synchronizes the in-memory data of a file, ignoring most of its metadata, with that on the physical medium</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>Reason = ext_posix() | terminated</v> - </type> <desc> <p>Makes sure that any buffers kept by the operating system (not by the Erlang runtime system) are written to disk. In @@ -1770,32 +1565,23 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>truncate(IoDevice) -> ok | {error, Reason}</name> + <name name="truncate" arity="1"/> <fsummary>Truncate a file</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>Reason = ext_posix() | terminated</v> - </type> <desc> - <p>Truncates the file referenced by <c>IoDevice</c> at + <p>Truncates the file referenced by <c><anno>IoDevice</anno></c> at the current position. Returns <c>ok</c> if successful, - otherwise <c>{error, Reason}</c>.</p> + otherwise <c>{error, <anno>Reason</anno>}</c>.</p> </desc> </func> <func> - <name>write(IoDevice, Bytes) -> ok | {error, Reason}</name> + <name name="write" arity="2"/> <fsummary>Write to a file</fsummary> - <type> - <v>IoDevice = io_device()</v> - <v>Bytes = iodata()</v> - <v>Reason = ext_posix() | terminated</v> - </type> <desc> - <p>Writes <c>Bytes</c> to the file referenced by - <c>IoDevice</c>. This function is the only way to write to a + <p>Writes <c><anno>Bytes</anno></c> to the file referenced by + <c><anno>IoDevice</anno></c>. This function is the only way to write to a file opened in raw mode (although it works for normally opened files, too). Returns <c>ok</c> if successful, and - <c>{error, Reason}</c> otherwise.</p> + <c>{error, <anno>Reason</anno>}</c> otherwise.</p> <p>If the file is opened with <c>encoding</c> set to something else than <c>latin1</c>, each byte written might result in several bytes actually being written to the file, as the byte range 0..255 might represent anything between one and four bytes depending on value and UTF encoding type.</p> <p>Typical error reasons are:</p> <taglist> @@ -1811,18 +1597,14 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>write_file(Filename, Bytes) -> ok | {error, Reason}</name> + <name name="write_file" arity="2"/> <fsummary>Write a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Bytes = iodata()</v> - <v>Reason = ext_posix() | terminated | system_limit</v> - </type> <desc> - <p>Writes the contents of the iodata term <c>Bytes</c> to the - file <c>Filename</c>. The file is created if it does not + <p>Writes the contents of the iodata term <c><anno>Bytes</anno></c> + to the file <c><anno>Filename</anno></c>. + The file is created if it does not exist. If it exists, the previous contents are - overwritten. Returns <c>ok</c>, or <c>{error, Reason}</c>.</p> + overwritten. Returns <c>ok</c>, or <c>{error, <anno>Reason</anno>}</c>.</p> <p>Typical error reasons are:</p> <taglist> <tag><c>enoent</c></tag> @@ -1851,33 +1633,23 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name>write_file(Filename, Bytes, Modes) -> ok | {error, Reason}</name> + <name name="write_file" arity="3"/> <fsummary>Write a file</fsummary> - <type> - <v>Filename = name()</v> - <v>Bytes = iodata()</v> - <v>Modes = [Mode] -- see open/2</v> - <v>Reason = ext_posix() | terminated | system_limit</v> - </type> <desc> <p>Same as <c>write_file/2</c>, but takes a third argument - <c>Modes</c>, a list of possible modes, see + <c><anno>Modes</anno></c>, a list of possible modes, see <seealso marker="#open/2">open/2</seealso>. The mode flags <c>binary</c> and <c>write</c> are implicit, so they should not be used.</p> </desc> </func> <func> - <name>write_file_info(Filename, FileInfo) -> ok | {error, Reason}</name> + <name name="write_file_info" arity="2"/> <fsummary>Change information about a file</fsummary> - <type> - <v>Filename = name()</v> - <v>FileInfo = #file_info{} -- see also read_file_info/1</v> - <v>Reason = ext_posix()</v> - </type> <desc> <p>Change file information. Returns <c>ok</c> if successful, - otherwise <c>{error, Reason}</c>. <c>FileInfo</c> is a record + otherwise <c>{error, <anno>Reason</anno>}</c>. + <c><anno>FileInfo</anno></c> is a record <c>file_info</c>, defined in the Kernel include file <c>file.hrl</c>. Include the following directive in the module from which the function is called:</p> @@ -1886,22 +1658,22 @@ f.txt: {person, "kalle", 25}. <p>The following fields are used from the record, if they are given.</p> <taglist> - <tag><c>atime = time()</c></tag> + <tag><c>atime = <seealso marker="#type-date_time">date_time()</seealso></c></tag> <item> <p>The last (local) time the file was read.</p> </item> - <tag><c>mtime = time()</c></tag> + <tag><c>mtime = <seealso marker="#type-date_time">date_time()</seealso></c></tag> <item> <p>The last (local) time the file was written.</p> </item> - <tag><c>ctime = time()</c></tag> + <tag><c>ctime = <seealso marker="#type-date_time">date_time()</seealso></c></tag> <item> <p>On Unix, any value give for this field will be ignored (the "ctime" for the file will be set to the current time). On Windows, this field is the new creation time to set for the file.</p> </item> - <tag><c>mode = int()</c></tag> + <tag><c>mode = integer()</c></tag> <item> <p>The file permissions as the sum of the following bit values:</p> @@ -1932,12 +1704,12 @@ f.txt: {person, "kalle", 25}. <p>On Unix platforms, other bits than those listed above may be set.</p> </item> - <tag><c>uid = int()</c></tag> + <tag><c>uid = integer()</c></tag> <item> <p>Indicates the owner of the file. Ignored for non-Unix file systems.</p> </item> - <tag><c>gid = int()</c></tag> + <tag><c>gid = integer()</c></tag> <item> <p>Gives the group that the owner of the file belongs to. Ignored non-Unix file systems.</p> diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml index fb09092f1c..418bfae4b8 100644 --- a/lib/kernel/doc/src/gen_sctp.xml +++ b/lib/kernel/doc/src/gen_sctp.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2007</year><year>2010</year> + <year>2007</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -45,10 +45,17 @@ SUSE Linux Enterprise Server 10 (x86_64) kernel 2.6.16.27-0.6-smp, with lksctp-tools-1.0.6, briefly on Solaris 10, and later on SUSE Linux Enterprise Server 10 Service Pack 1 (x86_64) - kernel 2.6.16.54-0.2.3-smp with lksctp-tools-1.0.7.</p> + kernel 2.6.16.54-0.2.3-smp with lksctp-tools-1.0.7, + and later also on FreeBSD 8.2. + </p> + <p> + This module was written for one-to-many style sockets + (type <c>seqpacket</c>). With the addition of + <seealso marker="#peeloff/2">peeloff/2</seealso>, one-to-one style + sockets (type <c>stream</c>) were introduced. + </p> <p>Record definitions for the <c>gen_sctp</c> module can be found using:</p> - <pre> - -include_lib("kernel/include/inet_sctp.hrl"). </pre> +<pre> -include_lib("kernel/include/inet_sctp.hrl"). </pre> <p>These record definitions use the "new" spelling 'adaptation', not the deprecated 'adaption', regardless of which spelling the underlying C API uses.</p> @@ -63,79 +70,54 @@ <item><seealso marker="#options">SCTP SOCKET OPTIONS</seealso></item> <item><seealso marker="#examples">SCTP EXAMPLES</seealso></item> <item><seealso marker="#seealso">SEE ALSO</seealso></item> - <item><seealso marker="#authors">AUTHORS</seealso></item> </list> + <marker id="types"></marker> </section> - <section> - <marker id="types"></marker> - <title>DATA TYPES</title> - <marker id="type-assoc_id"></marker> - <taglist> - <tag><c>assoc_id()</c></tag> - <item> + <datatypes> + <datatype> + <name><marker id="type-assoc_id">assoc_id()</marker></name> + <desc> <p>An opaque term returned in for example #sctp_paddr_change{} that identifies an association for an SCTP socket. The term is opaque except for the special value <c>0</c> that has a - meaning such as "the whole endpoint" or "all future associations".</p> - <marker id="type-charlist"></marker> - </item> - <tag><c>charlist() = [char()]</c></tag> - <item> <marker id="type-iolist"></marker> -</item> - <tag><c>iolist() = [char() | binary()]</c></tag> - <item> <marker id="type-ip_address"></marker> -</item> - <tag><c>ip_address()</c></tag> - <item> - <p>Represents an address of an SCTP socket. - It is a tuple as explained in - <seealso marker="inet">inet(3)</seealso>.</p> - <marker id="type-port_number"></marker> - </item> - <tag><c>port_number() = 0 .. 65535</c></tag> - <item> <marker id="type-posix"></marker> -</item> - <tag><c>posix()</c></tag> - <item> - <p>See - <seealso marker="inet#error_codes">inet(3); POSIX Error Codes.</seealso></p> - <marker id="type-sctp_option"></marker> - </item> - <tag><c>sctp_option()</c></tag> - <item> + meaning such as "the whole endpoint" or "all future associations". + </p> + </desc> + </datatype> + <datatype> + <name name="option"/> + <desc> <p>One of the <seealso marker="#options">SCTP Socket Options.</seealso></p> - <marker id="type-sctp_socket"></marker> - </item> - <tag><c>sctp_socket()</c></tag> - <item> + </desc> + </datatype> + <datatype> + <name name="option_name"/> + <desc><marker id="type-sctp_socket"></marker></desc> + </datatype> + <datatype> + <name><marker id="type-sctp_socket">sctp_socket()</marker></name> + <desc> <p>Socket identifier returned from <c>open/*</c>.</p> - <marker id="type-timeout"></marker> - </item> - <tag><c>timeout() = int() | infinity</c></tag> - <item> - <p>Timeout used in SCTP connect and receive calls.</p> - </item> - </taglist> - <marker id="exports"></marker> - </section> + <marker id="exports"></marker> + </desc> + </datatype> + </datatypes> + <funcs> <func> - <name>abort(sctp_socket(), Assoc) -> ok | {error, posix()}</name> + <name name="abort" arity="2"/> <fsummary>Abnormally terminate the association given by Assoc, without flushing of unsent data</fsummary> - <type> - <v>Assoc = #sctp_assoc_change{}</v> - </type> <desc> - <p>Abnormally terminates the association given by <c>Assoc</c>, without + <p>Abnormally terminates the association given by <c><anno>Assoc</anno></c>, without flushing of unsent data. The socket itself remains open. Other associations opened on this socket are still valid, and it can be used in new associations.</p> </desc> </func> <func> - <name>close(sctp_socket()) -> ok | {error, posix()}</name> + <name name="close" arity="1"/> <fsummary>Completely close the socket and all associations on it</fsummary> <desc> <p>Completely closes the socket and all associations on it. The unsent @@ -148,35 +130,26 @@ </desc> </func> <func> - <name>connect(Socket, Addr, Port, Opts) -> {ok,Assoc} | {error, posix()}</name> + <name name="connect" arity="4"/> <fsummary>Same as <c>connect(Socket, Addr, Port, Opts, infinity)</c>.</fsummary> <desc> - <p>Same as <c>connect(Socket, Addr, Port, Opts, infinity)</c>.</p> + <p>Same as <c>connect(<anno>Socket</anno>, <anno>Addr</anno>, <anno>Port</anno>, <anno>Opts</anno>, infinity)</c>.</p> </desc> </func> <func> - <name>connect(Socket, Addr, Port, [Opt], Timeout) -> {ok, Assoc} | {error, posix()}</name> + <name name="connect" arity="5"/> <fsummary>Establish a new association for the socket <c>Socket</c>, with a peer (SCTP server socket)</fsummary> - <type> - <v>Socket = sctp_socket()</v> - <v>Addr = ip_address() | Host</v> - <v>Port = port_number()</v> - <v>Opt = sctp_option()</v> - <v>Timeout = timeout()</v> - <v>Host = atom() | string()</v> - <v>Assoc = #sctp_assoc_change{}</v> - </type> <desc> - <p>Establishes a new association for the socket <c>Socket</c>, + <p>Establishes a new association for the socket <c><anno>Socket</anno></c>, with the peer (SCTP server socket) given by - <c>Addr</c> and <c>Port</c>. The <c>Timeout</c>, + <c><anno>Addr</anno></c> and <c><anno>Port</anno></c>. The <c><anno>Timeout</anno></c>, is expressed in milliseconds. A socket can be associated with multiple peers.</p> - <p><b>WARNING:</b>Using a value of <c>Timeout</c> less than + <p><b>WARNING:</b>Using a value of <c><anno>Timeout</anno></c> less than the maximum time taken by the OS to establish an association (around 4.5 minutes if the default values from RFC 4960 are used) can result in inconsistent or incorrect return values. This is especially - relevant for associations sharing the same <c>Socket</c> + relevant for associations sharing the same <c><anno>Socket</anno></c> (i.e. source address and port) since the controlling process blocks until <c>connect/*</c> returns. <seealso marker="#connect_init/4">connect_init/*</seealso> @@ -185,26 +158,24 @@ <p><marker id="record-sctp_assoc_change"></marker> The result of <c>connect/*</c> is an <c>#sctp_assoc_change{}</c> event which contains, in particular, the new - <seealso marker="#type-assoc_id">Association ID:</seealso></p> - <pre> - #sctp_assoc_change{ + <seealso marker="#type-assoc_id">Association ID</seealso>.</p> +<pre> #sctp_assoc_change{ state = atom(), error = atom(), - outbound_streams = int(), - inbound_streams = int(), + outbound_streams = integer(), + inbound_streams = integer(), assoc_id = assoc_id() } </pre> <p>The number of outbound and inbound streams can be set by giving an <c>sctp_initmsg</c> option to <c>connect</c> as in:</p> - <pre> - connect(Socket, Ip, Port, +<pre> connect(<anno>Socket</anno>, Ip, <anno>Port</anno>, [{sctp_initmsg,#sctp_initmsg{num_ostreams=OutStreams, max_instreams=MaxInStreams}}]) </pre> - <p>All options <c>Opt</c> are set on the socket before the + <p>All options <c><anno>Opt</anno></c> are set on the socket before the association is attempted. If an option record has got undefined field values, the options record is first read from the socket - for those values. In effect, <c>Opt</c> option records only + for those values. In effect, <c><anno>Opt</anno></c> option records only define field values to change before connecting.</p> <p>The returned <c>outbound_streams</c> and <c>inbound_streams</c> are the actual stream numbers on the socket, which may be different @@ -242,27 +213,19 @@ </desc> </func> <func> - <name>connect_init(Socket, Addr, Port, Opts) -> ok | {error, posix()}</name> + <name name="connect_init" arity="4"/> <fsummary>Same as <c>connect_init(Socket, Addr, Port, Opts, infinity)</c>.</fsummary> <desc> - <p>Same as <c>connect_init(Socket, Addr, Port, Opts, infinity)</c>.</p> + <p>Same as <c>connect_init(<anno>Socket</anno>, <anno>Addr</anno>, <anno>Port</anno>, <anno>Opts</anno>, infinity)</c>.</p> </desc> </func> <func> - <name>connect_init(Socket, Addr, Port, [Opt], Timeout) -> ok | {error, posix()}</name> + <name name="connect_init" arity="5"/> <fsummary>Initiate a new association for the socket <c>Socket</c>, with a peer (SCTP server socket)</fsummary> - <type> - <v>Socket = sctp_socket()</v> - <v>Addr = ip_address() | Host</v> - <v>Port = port_number()</v> - <v>Opt = sctp_option()</v> - <v>Timeout = timeout()</v> - <v>Host = atom() | string()</v> - </type> <desc> - <p>Initiates a new association for the socket <c>Socket</c>, + <p>Initiates a new association for the socket <c><anno>Socket</anno></c>, with the peer (SCTP server socket) given by - <c>Addr</c> and <c>Port</c>.</p> + <c><anno>Addr</anno></c> and <c><anno>Port</anno></c>.</p> <p>The fundamental difference between this API and <c>connect/*</c> is that the return value is that of the underlying OS connect(2) system call. If <c>ok</c> is returned @@ -275,97 +238,119 @@ active option.</p> <p>The parameters are as described in <seealso marker="#connect/5">connect/*</seealso>, with the - exception of the <c>Timeout</c> value.</p> - <p>The timer associated with <c>Timeout</c> only supervises - IP resolution of <c>Addr</c></p> + exception of the <c><anno>Timeout</anno></c> value.</p> + <p>The timer associated with <c><anno>Timeout</anno></c> only supervises + IP resolution of <c><anno>Addr</anno></c></p> </desc> </func> <func> - <name>controlling_process(sctp_socket(), pid()) -> ok</name> + <name name="controlling_process" arity="2"/> <fsummary>Assign a new controlling process pid to the socket</fsummary> <desc> - <p>Assigns a new controlling process Pid to Socket. Same implementation + <p>Assigns a new controlling process <c><anno>Pid</anno></c> to <c><anno>Socket</anno></c>. Same implementation as <c>gen_udp:controlling_process/2</c>.</p> </desc> </func> <func> - <name>eof(Socket, Assoc) -> ok | {error, Reason}</name> + <name name="eof" arity="2"/> <fsummary>Gracefully terminate the association given by Assoc, with flushing of all unsent data</fsummary> - <type> - <v>Socket = sctp_socket()</v> - <v>Assoc = #sctp_assoc_change{}</v> - </type> <desc> - <p>Gracefully terminates the association given by <c>Assoc</c>, with + <p>Gracefully terminates the association given by <c><anno>Assoc</anno></c>, with flushing of all unsent data. The socket itself remains open. Other associations opened on this socket are still valid, and it can be used in new associations.</p> </desc> </func> <func> - <name>listen(Socket, IsServer) -> ok | {error, Reason}</name> + <name name="listen" arity="2" clause_i="1"/> + <name name="listen" arity="2" clause_i="2"/> <fsummary>Set up a socket to listen.</fsummary> - <type> - <v>Socket = sctp_socket()</v> - <v>IsServer = bool()</v> - </type> <desc> <p>Sets up a socket to listen on the IP address and port number - it is bound to. IsServer must be 'true' or 'false'. - In the contrast to TCP, in SCTP there is no listening queue length. - If IsServer is 'true' the socket accepts new associations, i.e. - it will become an SCTP server socket.</p> + it is bound to.</p> + <p>For type <c>seqpacket</c> sockets (the default) + <c><anno>IsServer</anno></c> must be <c>true</c> or <c>false</c>. + In the contrast to TCP, in SCTP there is no listening queue length. + If <c><anno>IsServer</anno></c> is <c>true</c> the socket accepts new associations, i.e. + it will become an SCTP server socket.</p> + <p>For type <c>stream</c> sockets <anno>Backlog</anno> defines + the backlog queue length just like in TCP.</p> </desc> </func> <func> - <name>open() -> {ok, Socket} | {error, posix()}</name> - <name>open(Port) -> {ok, Socket} | {error, posix()}</name> - <name>open([Opt]) -> {ok, Socket} | {error, posix()}</name> - <name>open(Port, [Opt]) -> {ok, Socket} | {error, posix()}</name> + <name name="open" arity="0"/> + <name name="open" arity="1" clause_i="1"/> + <name name="open" arity="1" clause_i="2"/> + <name name="open" arity="2"/> <fsummary>Create an SCTP socket and bind it to local addresses</fsummary> - <type> - <v>Opt = {ip,IP} | {ifaddr,IP} | {port,Port} | sctp_option()</v> - <v>IP = ip_address() | any | loopback</v> - <v>Port = port_number()</v> - </type> <desc> <p>Creates an SCTP socket and binds it to the local addresses - specified by all <c>{ip,IP}</c> (or synonymously <c>{ifaddr,IP}</c>) + specified by all <c>{ip,<anno>IP</anno>}</c> (or synonymously <c>{ifaddr,<anno>IP</anno>}</c>) options (this feature is called SCTP multi-homing). - The default <c>IP</c> and <c>Port</c> are <c>any</c> + The default <c><anno>IP</anno></c> and <c><anno>Port</anno></c> are <c>any</c> and <c>0</c>, meaning bind to all local addresses on any one free port.</p> + + <p>Other options are:</p> + <taglist> + <tag><c>inet6</c></tag> + <item> + <p>Set up the socket for IPv6.</p> + </item> + <tag><c>inet</c></tag> + <item> + <p>Set up the socket for IPv4. This is the default.</p> + </item> + </taglist> + <p>A default set of socket <seealso marker="#options">options</seealso> is used. In particular, the socket is opened in <seealso marker="#option-binary">binary</seealso> and <seealso marker="#option-active">passive</seealso> mode, + with <anno>SockType</anno> <c>seqpacket</c>, and with reasonably large <seealso marker="#option-sndbuf">kernel</seealso> and driver <seealso marker="#option-buffer">buffers.</seealso></p> </desc> </func> <func> - <name>recv(sctp_socket()) -> {ok, {FromIP, FromPort, AncData, BinMsg}} | {error, Reason}</name> - <name>recv(sctp_socket(), timeout()) -> {ok, {FromIP, FromPort, AncData, Data}} | {error, Reason}</name> + <name name="peeloff" arity="2"/> + <fsummary> + Peel off a type <c>stream</c> socket from a type <c>seqpacket</c> one + </fsummary> + <desc> + <p> + Branch off an existing association <anno>Assoc</anno> + in a socket <anno>Socket</anno> of type <c>seqpacket</c> + (one-to-may style) into + a new socket <anno>NewSocket</anno> of type <c>stream</c> + (one-to-one style). + </p> + <p> + The existing association argument <anno>Assoc</anno> + can be either a + <seealso marker="#record-sctp_assoc_change"> + #sctp_assoc_change{} + </seealso> + record as returned from e.g + <seealso marker="#recv-2">recv/*</seealso>, + <seealso marker="#connect-5">connect/*</seealso> or + from a listening socket in active mode. Or it can be just + the field <c>assoc_id</c> integer from such a record. + </p> + </desc> + </func> + <func> + <name name="recv" arity="1"/> + <name name="recv" arity="2"/> <fsummary>Receive a message from a socket</fsummary> - <type> - <v>FromIP = ip_address()</v> - <v>FromPort = port_number()</v> - <v>AncData = [#sctp_sndrcvinfo{}]</v> - <v>Data = binary() | charlist() | #sctp_sndrcvinfo{} | - #sctp_assoc_change{} | #sctp_paddr_change{} | - #sctp_adaptation_event{} </v> - <v>Reason = posix() | #sctp_send_failed{} | #scpt_paddr_change{} | - #sctp_pdapi_event{} | #sctp_remote_error{} | - #sctp_shutdown_event{}</v> - </type> <desc> - <p>Receives the <c>Data</c> message from any association of the socket. + <p>Receives the <c><anno>Data</anno></c> message from any association of the socket. If the receive times out <c>{error,timeout</c> is returned. The default timeout is <c>infinity</c>. - <c>FromIP</c> and <c>FromPort</c> indicate the sender's address.</p> - <p><c>AncData</c> is a list of Ancillary Data items which - may be received along with the main <c>Data</c>. + <c><anno>FromIP</anno></c> and <c><anno>FromPort</anno></c> indicate the sender's address.</p> + <p><c><anno>AncData</anno></c> is a list of Ancillary Data items which + may be received along with the main <c><anno>Data</anno></c>. This list can be empty, or contain a single <seealso marker="#record-sctp_sndrcvinfo">#sctp_sndrcvinfo{}</seealso> record, if receiving of such ancillary data is enabled @@ -375,10 +360,10 @@ provide an easy way of determining the association and stream over which the message has been received. (An alternative way would be to get the Association ID from the - <c>FromIP</c> and <c>FromPort</c> using the + <c><anno>FromIP</anno></c> and <c><anno>FromPort</anno></c> using the <seealso marker="#option-sctp_get_peer_addr_info">sctp_get_peer_addr_info</seealso> socket option, but this would still not produce the Stream number).</p> - <p>The actual <c>Data</c> received may be a <c>binary()</c>, + <p>The actual <c><anno>Data</anno></c> received may be a <c>binary()</c>, or <c>list()</c> of bytes (integers in the range 0 through 255) depending on the socket mode, or an SCTP Event. <marker id="sctp_events"></marker> @@ -392,11 +377,10 @@ <p><seealso marker="#record-sctp_assoc_change">#sctp_assoc_change{}</seealso>;</p> </item> <item> - <pre> - #sctp_paddr_change{ +<pre> #sctp_paddr_change{ addr = {ip_address(),port()}, state = atom(), - error = int(), + error = integer(), assoc_id = assoc_id() } </pre> <p>Indicates change of the status of the peer's IP address given by @@ -430,10 +414,9 @@ converted into a string using <c>error_string/1</c>.</p> </item> <item> - <pre> - #sctp_send_failed{ +<pre> #sctp_send_failed{ flags = true | false, - error = int(), + error = integer(), info = #sctp_sndrcvinfo{}, assoc_id = assoc_id() data = binary() @@ -451,9 +434,8 @@ returned by <c>recv/*</c>.</p> </item> <item> - <pre> - #sctp_adaptation_event{ - adaptation_ind = int(), +<pre> #sctp_adaptation_event{ + adaptation_ind = integer(), assoc_id = assoc_id() } </pre> <p>Delivered when a peer sends an Adaptation Layer Indication @@ -463,8 +445,7 @@ the Erlang/SCTP binding, this event is disabled by default.</p> </item> <item> - <pre> - #sctp_pdapi_event{ +<pre> #sctp_pdapi_event{ indication = sctp_partial_delivery_aborted, assoc_id = assoc_id() } </pre> @@ -476,15 +457,10 @@ </desc> </func> <func> - <name>send(Socket, SndRcvInfo, Data) -> ok | {error, Reason}</name> + <name name="send" arity="3"/> <fsummary>Send a message using an <c>#sctp_sndrcvinfo{}</c>record</fsummary> - <type> - <v>Socket = sctp_socket()</v> - <v>SndRcvInfo = #sctp_sndrcvinfo{}</v> - <v>Data = binary() | iolist()</v> - </type> <desc> - <p>Sends the <c>Data</c> message with all sending parameters from a + <p>Sends the <c><anno>Data</anno></c> message with all sending parameters from a <seealso marker="#record-sctp_sndrcvinfo">#sctp_sndrcvinfo{}</seealso> record. This way, the user can specify the PPID (passed to the remote end) and Context (passed to the local SCTP layer) which can be used @@ -494,21 +470,15 @@ </desc> </func> <func> - <name>send(Socket, Assoc, Stream, Data) -> ok | {error, Reason}</name> + <name name="send" arity="4"/> <fsummary>Send a message over an existing association and given stream</fsummary> - <type> - <v>Socket = sctp_socket()</v> - <v>Assoc = #sctp_assoc_change{} | assoc_id()</v> - <v>Stream = integer()</v> - <v>Data = binary() | iolist()</v> - </type> <desc> - <p>Sends <c>Data</c> message over an existing association and given + <p>Sends <c><anno>Data</anno></c> message over an existing association and given stream.</p> </desc> </func> <func> - <name>error_string(integer()) -> ok | string() | undefined</name> + <name name="error_string" arity="1"/> <fsummary>Translate an SCTP error number into a string</fsummary> <desc> <p>Translates an SCTP error number from for example @@ -532,7 +502,7 @@ <marker id="option-binary"></marker> <marker id="option-list"></marker> <taglist> - <tag><c>{mode, list|binary}</c>or just <c>list</c> or <c>binary</c>.</tag> + <tag><c>{mode, list|binary}</c> or just <c>list</c> or <c>binary</c></tag> <item> <p>Determines the type of data returned from <c>gen_sctp:recv/1,2</c>.</p> <marker id="option-active"></marker> @@ -562,7 +532,7 @@ </list> <marker id="option-buffer"></marker> </item> - <tag><c>{buffer, int()}</c></tag> + <tag><c>{buffer, integer()}</c></tag> <item> <p>Determines the size of the user-level software buffer used by the SCTP driver. Not to be confused with <c>sndbuf</c> @@ -572,7 +542,7 @@ In fact, the <c>val(buffer)</c> is automatically set to the above maximum when <c>sndbuf</c> or <c>recbuf</c> values are set.</p> </item> - <tag><c>{tos, int()}</c></tag> + <tag><c>{tos, integer()}</c></tag> <item> <p>Sets the Type-Of-Service field on the IP datagrams being sent, to the given value, which effectively determines a prioritization @@ -580,7 +550,7 @@ are system-dependent. TODO: we do not provide symbolic names for these values yet.</p> </item> - <tag><c>{priority, int()}</c></tag> + <tag><c>{priority, integer()}</c></tag> <item> <p>A protocol-independent equivalent of <c>tos</c> above. Setting priority implies setting tos as well.</p> @@ -599,7 +569,7 @@ required for high-throughput servers).</p> <marker id="option-linger"></marker> </item> - <tag><c>{linger, {true|false, int()}</c></tag> + <tag><c>{linger, {true|false, integer()}</c></tag> <item> <p>Determines the timeout in seconds for flushing unsent data in the <c>gen_sctp:close/1</c> socket call. If the 1st component of the value @@ -609,14 +579,14 @@ the flushing time-out in seconds.</p> <marker id="option-sndbuf"></marker> </item> - <tag><c>{sndbuf, int()}</c></tag> + <tag><c>{sndbuf, integer()}</c></tag> <item> <p>The size, in bytes, of the *kernel* send buffer for this socket. Sending errors would occur for datagrams larger than <c>val(sndbuf)</c>. Setting this option also adjusts the size of the driver buffer (see <c>buffer</c> above).</p> </item> - <tag><c>{recbuf, int()}</c></tag> + <tag><c>{recbuf, integer()}</c></tag> <item> <p>The size, in bytes, of the *kernel* recv buffer for this socket. Sending errors would occur for datagrams larger than @@ -625,12 +595,11 @@ </item> <tag><c>{sctp_rtoinfo, #sctp_rtoinfo{}}</c></tag> <item> - <pre> - #sctp_rtoinfo{ +<pre> #sctp_rtoinfo{ assoc_id = assoc_id(), - initial = int(), - max = int(), - min = int() + initial = integer(), + max = integer(), + min = integer() } </pre> <p>Determines re-transmission time-out parameters, in milliseconds, for the association(s) given by <c>assoc_id</c>. @@ -640,14 +609,13 @@ </item> <tag><c>{sctp_associnfo, #sctp_assocparams{}}</c></tag> <item> - <pre> - #sctp_assocparams{ +<pre> #sctp_assocparams{ assoc_id = assoc_id(), - asocmaxrxt = int(), - number_peer_destinations = int(), - peer_rwnd = int(), - local_rwnd = int(), - cookie_life = int() + asocmaxrxt = integer(), + number_peer_destinations = integer(), + peer_rwnd = integer(), + local_rwnd = integer(), + cookie_life = integer() } </pre> <p>Determines association parameters for the association(s) given by <c>assoc_id</c>. <c>assoc_id = 0</c> (default) indicates @@ -656,12 +624,11 @@ </item> <tag><c>{sctp_initmsg, #sctp_initmsg{}}</c></tag> <item> - <pre> - #sctp_initmsg{ - num_ostreams = int(), - max_instreams = int(), - max_attempts = int(), - max_init_timeo = int() +<pre> #sctp_initmsg{ + num_ostreams = integer(), + max_instreams = integer(), + max_attempts = integer(), + max_init_timeo = integer() } </pre> <p>Determines the default parameters which this socket attempts to negotiate with its peer while establishing an association with it. @@ -685,12 +652,12 @@ for establishing an association.</p> </item> </list> - <p></p> </item> - <tag><c>{sctp_autoclose, int()|infinity}</c></tag> + <tag><c>{sctp_autoclose, integer() >= 0}</c></tag> <item> <p>Determines the time (in seconds) after which an idle association is - automatically closed.</p> + automatically closed. <c>0</c> means that the association is + never automatically closed.</p> </item> <tag><c>{sctp_nodelay, true|false}</c></tag> <item> @@ -712,15 +679,14 @@ <p>Turns on|off automatic mapping of IPv4 addresses into IPv6 ones (if the socket address family is AF_INET6).</p> </item> - <tag><c>{sctp_maxseg, int()}</c></tag> + <tag><c>{sctp_maxseg, integer()}</c></tag> <item> <p>Determines the maximum chunk size if message fragmentation is used. If <c>0</c>, the chunk size is limited by the Path MTU only.</p> </item> <tag><c>{sctp_primary_addr, #sctp_prim{}}</c></tag> <item> - <pre> - #sctp_prim{ +<pre> #sctp_prim{ assoc_id = assoc_id(), addr = {IP, Port} } @@ -733,8 +699,7 @@ </item> <tag><c>{sctp_set_peer_primary_addr, #sctp_setpeerprim{}}</c></tag> <item> - <pre> - #sctp_setpeerprim{ +<pre> #sctp_setpeerprim{ assoc_id = assoc_id(), addr = {IP, Port} } @@ -748,9 +713,8 @@ <tag><c>{sctp_adaptation_layer, #sctp_setadaptation{}}</c></tag> <item> <marker id="record-sctp_setadaptation"></marker> - <pre> - #sctp_setadaptation{ - adaptation_ind = int() +<pre> #sctp_setadaptation{ + adaptation_ind = integer() } </pre> <p>When set, requests that the local endpoint uses the value given by <c>adaptation_ind</c> as the Adaptation Indication parameter for @@ -760,14 +724,13 @@ </item> <tag><c>{sctp_peer_addr_params, #sctp_paddrparams{}}</c></tag> <item> - <pre> - #sctp_paddrparams{ +<pre> #sctp_paddrparams{ assoc_id = assoc_id(), address = {IP, Port}, - hbinterval = int(), - pathmaxrxt = int(), - pathmtu = int(), - sackdelay = int(), + hbinterval = integer(), + pathmaxrxt = integer(), + pathmtu = integer(), + sackdelay = integer(), flags = list() } IP = ip_address() @@ -818,24 +781,21 @@ <p><c>sackdelay_disable</c>: disable SAC delay.</p> </item> </list> - <p></p> </item> </list> - <p></p> </item> <tag><c>{sctp_default_send_param, #sctp_sndrcvinfo{}}</c></tag> <item> <marker id="record-sctp_sndrcvinfo"></marker> - <pre> - #sctp_sndrcvinfo{ - stream = int(), - ssn = int(), +<pre> #sctp_sndrcvinfo{ + stream = integer(), + ssn = integer(), flags = list(), - ppid = int(), - context = int(), - timetolive = int(), - tsn = int(), - cumtsn = int(), + ppid = integer(), + context = integer(), + timetolive = integer(), + tsn = integer(), + cumtsn = integer(), assoc_id = assoc_id() } </pre> <p><c>#sctp_sndrcvinfo{}</c> is used both in this socket option, and as @@ -869,20 +829,17 @@ association, with flushing of unsent data.</p> </item> </list> - <p></p> <p>Other fields are rarely used. See <url href="http://www.rfc-archive.org/getrfc.php?rfc=2960">RFC2960</url> and <url href="http://tools.ietf.org/html/draft-ietf-tsvwg-sctpsocket-13">Sockets API Extensions for SCTP</url> for full information.</p> </item> </list> - <p></p> <marker id="option-sctp_events"></marker> </item> <tag><c>{sctp_events, #sctp_event_subscribe{}}</c></tag> <item> <marker id="record-sctp_event_subscribe"></marker> - <pre> - #sctp_event_subscribe{ +<pre> #sctp_event_subscribe{ data_io_event = true | false, association_event = true | false, address_event = true | false, @@ -907,10 +864,9 @@ </item> <tag><c>{sctp_delayed_ack_time, #sctp_assoc_value{}}</c></tag> <item> - <pre> - #sctp_assoc_value{ +<pre> #sctp_assoc_value{ assoc_id = assoc_id(), - assoc_value = int() + assoc_value = integer() } </pre> <p>Rarely used. Determines the ACK time (given by <c>assoc_value</c> in milliseconds) for @@ -919,16 +875,15 @@ </item> <tag><c>{sctp_status, #sctp_status{}}</c></tag> <item> - <pre> - #sctp_status{ +<pre> #sctp_status{ assoc_id = assoc_id(), state = atom(), - rwnd = int(), - unackdata = int(), - penddata = int(), - instrms = int(), - outstrms = int(), - fragmentation_point = int(), + rwnd = integer(), + unackdata = integer(), + penddata = integer(), + instrms = integer(), + outstrms = integer(), + fragmentation_point = integer(), primary = #sctp_paddrinfo{} } </pre> <p>This option is read-only. It determines the status of @@ -992,21 +947,19 @@ address (see below for the format of <c>#sctp_paddrinfo{}</c>).</p> </item> </list> - <p></p> <marker id="option-sctp_get_peer_addr_info"></marker> </item> <tag><c>{sctp_get_peer_addr_info, #sctp_paddrinfo{}}</c></tag> <item> <marker id="record-sctp_paddrinfo"></marker> - <pre> - #sctp_paddrinfo{ +<pre> #sctp_paddrinfo{ assoc_id = assoc_id(), address = {IP, Port}, state = inactive | active, - cwnd = int(), - srtt = int(), - rto = int(), - mtu = int() + cwnd = integer(), + srtt = integer(), + rto = integer(), + mtu = integer() } IP = ip_address() Port = port_number() </pre> @@ -1030,8 +983,7 @@ <item> <p>Example of an Erlang SCTP Server which receives SCTP messages and prints them on the standard output:</p> - <pre> - -module(sctp_server). +<pre> -module(sctp_server). -export([server/0,server/1,server/2]). -include_lib("kernel/include/inet.hrl"). @@ -1047,7 +999,7 @@ server(IP, Port) when is_tuple(IP) orelse IP == any orelse IP == loopback, is_integer(Port) -> - {ok,S} = gen_sctp:open([{ip,IP},{port,Port}],[{recbuf,65536}]), + {ok,S} = gen_sctp:open(Port, [{recbuf,65536}, {ip,IP}]), io:format("Listening on ~w:~w. ~w~n", [IP,Port,S]), ok = gen_sctp:listen(S, true), server_loop(S). @@ -1060,7 +1012,6 @@ io:format("Received: ~p~n", [Data]) end, server_loop(S). </pre> - <p></p> </item> <item> <p>Example of an Erlang SCTP Client which interacts with the above Server. @@ -1070,8 +1021,7 @@ over Stream 5 fails. The client then <c>abort</c>s the association, which results in the corresponding Event being received on the Server side.</p> - <pre> - -module(sctp_client). +<pre> -module(sctp_client). -export([client/0, client/1, client/2]). -include_lib("kernel/include/inet.hrl"). @@ -1104,13 +1054,11 @@ timer:sleep(1000), gen_sctp:close(S). </pre> - <p></p> </item> <item> <p>A very simple Erlang SCTP Client which uses the connect_init API.</p> - <pre> --module(ex3). +<pre>-module(ex3). -export([client/4]). -include_lib("kernel/include/inet.hrl"). @@ -1163,7 +1111,6 @@ client_loop(S, Peer1, Port1, AssocId1, Peer2, Port2, AssocId2) -> ok end. </pre> - <p></p> </item> </list> </section> @@ -1176,7 +1123,6 @@ client_loop(S, Peer1, Port1, AssocId1, Peer2, Port2, AssocId2) -> <seealso marker="gen_udp">gen_udp(3)</seealso>, <url href="http://www.rfc-archive.org/getrfc.php?rfc=2960">RFC2960</url> (Stream Control Transmission Protocol), <url href="http://tools.ietf.org/html/draft-ietf-tsvwg-sctpsocket-13">Sockets API Extensions for SCTP.</url></p> - <marker id="authors"></marker> </section> </erlref> diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml index aa171c77c2..8a5d40bb16 100644 --- a/lib/kernel/doc/src/gen_tcp.xml +++ b/lib/kernel/doc/src/gen_tcp.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1997</year><year>2010</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -37,7 +37,7 @@ binary and closing the connection:</p> <code type="none"> client() -> - SomeHostInNet = "localhost" % to make it runnable on one machine + SomeHostInNet = "localhost", % to make it runnable on one machine {ok, Sock} = gen_tcp:connect(SomeHostInNet, 5678, [binary, {packet, 0}]), ok = gen_tcp:send(Sock, "Some Data"), @@ -63,36 +63,36 @@ do_recv(Sock, Bs) -> <p>For more examples, see the <seealso marker="#examples">examples</seealso> section.</p> </description> - <section> - <title>DATA TYPES</title> - <code type="none"> -ip_address() - see inet(3) - -posix() - see inet(3) + <datatypes> + <datatype> + <name name="option"/> + </datatype> + <datatype> + <name name="option_name"/> + </datatype> + <datatype> + <name name="connect_option"/> + </datatype> + <datatype> + <name name="listen_option"/> + </datatype> + <datatype> + <name><marker id="type-socket">socket()</marker></name> + <desc> + <p>As returned by accept/1,2 and connect/3,4.</p> + <marker id="connect"></marker> + </desc> + </datatype> + </datatypes> -socket() - as returned by accept/1,2 and connect/3,4</code> - <marker id="connect"></marker> - </section> <funcs> <func> - <name>connect(Address, Port, Options) -> {ok, Socket} | {error, Reason}</name> - <name>connect(Address, Port, Options, Timeout) -> {ok, Socket} | {error, Reason}</name> + <name name="connect" arity="3"/> + <name name="connect" arity="4"/> <fsummary>Connect to a TCP port</fsummary> - <type> - <v>Address = string() | atom() | ip_address()</v> - <v>Port = 0..65535</v> - <v>Options = [Opt]</v> - <v> Opt -- see below</v> - <v>Timeout = int() | infinity</v> - <v>Socket = socket()</v> - <v>Reason = posix()</v> - </type> <desc> - <p>Connects to a server on TCP port <c>Port</c> on the host - with IP address <c>Address</c>. The <c>Address</c> argument + <p>Connects to a server on TCP port <c><anno>Port</anno></c> on the host + with IP address <c><anno>Address</anno></c>. The <c><anno>Address</anno></c> argument can be either a hostname, or an IP address.</p> <p>The available options are:</p> <taglist> @@ -113,7 +113,7 @@ socket() <item> <p>Specify which local port number to use.</p> </item> - <tag><c>{fd, int()}</c></tag> + <tag><c>{fd, integer() >= 0}</c></tag> <item> <p>If a socket has somehow been connected without using <c>gen_tcp</c>, use this option to pass the file @@ -127,13 +127,13 @@ socket() <item> <p>Set up the socket for IPv4.</p> </item> - <tag>Opt</tag> + <tag><c>Opt</c></tag> <item> <p>See <seealso marker="inet#setopts/2">inet:setopts/2</seealso>.</p> </item> </taglist> - <p>Packets can be sent to the returned socket <c>Socket</c> + <p>Packets can be sent to the returned socket <c><anno>Socket</anno></c> using <c>send/2</c>. Packets sent from the peer are delivered as messages:</p> <code type="none"> @@ -148,7 +148,7 @@ socket() <p>unless <c>{active, false}</c> is specified in the option list for the socket, in which case packets are retrieved by calling <c>recv/2</c>.</p> - <p>The optional <c>Timeout</c> parameter specifies a timeout in + <p>The optional <c><anno>Timeout</anno></c> parameter specifies a timeout in milliseconds. The default value is <c>infinity</c>.</p> <note> <p>The default values for options given to <c>connect</c> can @@ -159,19 +159,12 @@ socket() </desc> </func> <func> - <name>listen(Port, Options) -> {ok, ListenSocket} | {error, Reason}</name> + <name name="listen" arity="2"/> <fsummary>Set up a socket to listen on a port</fsummary> - <type> - <v>Port = 0..65535</v> - <v>Options = [Opt]</v> - <v> Opt -- see below</v> - <v>ListenSocket -- see below</v> - <v>Reason = posix()</v> - </type> <desc> - <p>Sets up a socket to listen on the port <c>Port</c> on + <p>Sets up a socket to listen on the port <c><anno>Port</anno></c> on the local host.</p> - <p>If <c>Port == 0</c>, the underlying OS assigns an available + <p>If <c><anno>Port</anno> == 0</c>, the underlying OS assigns an available port number, use <c>inet:port/1</c> to retrieve it.</p> <p>The available options are:</p> <taglist> @@ -194,6 +187,10 @@ socket() <p>If the host has several network interfaces, this option specifies which one to listen on.</p> </item> + <tag><c>{port, Port}</c></tag> + <item> + <p>Specify which local port number to use.</p> + </item> <tag><c>{fd, Fd}</c></tag> <item> <p>If a socket has somehow been connected without using @@ -214,7 +211,7 @@ socket() <seealso marker="inet#setopts/2">inet:setopts/2</seealso>.</p> </item> </taglist> - <p>The returned socket <c>ListenSocket</c> can only be used in + <p>The returned socket <c><anno>ListenSocket</anno></c> can only be used in calls to <c>accept/1,2</c>.</p> <note> <p>The default values for options given to <c>listen</c> can @@ -225,27 +222,23 @@ socket() </desc> </func> <func> - <name>accept(ListenSocket) -> {ok, Socket} | {error, Reason}</name> - <name>accept(ListenSocket, Timeout) -> {ok, Socket} | {error, Reason}</name> + <name name="accept" arity="1"/> + <name name="accept" arity="2"/> <fsummary>Accept an incoming connection request on a listen socket</fsummary> - <type> - <v>ListenSocket -- see listen/2</v> - <v>Timeout = int() | infinity</v> - <v>Socket = socket()</v> - <v>Reason = closed | timeout | posix()</v> - </type> + <type_desc variable="ListenSocket">Returned by <c>listen/2</c>. + </type_desc> <desc> <p>Accepts an incoming connection request on a listen socket. - <c>Socket</c> must be a socket returned from <c>listen/2</c>. - <c>Timeout</c> specifies a timeout value in ms, defaults to + <c><anno>Socket</anno></c> must be a socket returned from <c>listen/2</c>. + <c><anno>Timeout</anno></c> specifies a timeout value in ms, defaults to <c>infinity</c>.</p> - <p>Returns <c>{ok, Socket}</c> if a connection is established, - or <c>{error, closed}</c> if <c>ListenSocket</c> is closed, + <p>Returns <c>{ok, <anno>Socket</anno>}</c> if a connection is established, + or <c>{error, closed}</c> if <c><anno>ListenSocket</anno></c> is closed, or <c>{error, timeout}</c> if no connection is established within the specified time. May also return a POSIX error value if something else goes wrong, see inet(3) for possible error values.</p> - <p>Packets can be sent to the returned socket <c>Socket</c> + <p>Packets can be sent to the returned socket <c><anno>Socket</anno></c> using <c>send/2</c>. Packets sent from the peer are delivered as messages:</p> <code type="none"> @@ -264,13 +257,8 @@ socket() </desc> </func> <func> - <name>send(Socket, Packet) -> ok | {error, Reason}</name> + <name name="send" arity="2"/> <fsummary>Send a packet</fsummary> - <type> - <v>Socket = socket()</v> - <v>Packet = [char()] | binary()</v> - <v>Reason = posix()</v> - </type> <desc> <p>Sends a packet on a socket. </p> <p>There is no <c>send</c> call with timeout option, you use the @@ -279,70 +267,52 @@ socket() </desc> </func> <func> - <name>recv(Socket, Length) -> {ok, Packet} | {error, Reason}</name> - <name>recv(Socket, Length, Timeout) -> {ok, Packet} | {error, Reason}</name> + <name name="recv" arity="2"/> + <name name="recv" arity="3"/> <fsummary>Receive a packet from a passive socket</fsummary> - <type> - <v>Socket = socket()</v> - <v>Length = int()</v> - <v>Packet = [char()] | binary() | HttpPacket</v> - <v>Timeout = int() | infinity</v> - <v>Reason = closed | posix()</v> - <v>HttpPacket = see the description of <c>HttpPacket</c> in <seealso marker="erts:erlang#decode_packet/3">erlang:decode_packet/3</seealso></v> - </type> + <type_desc variable="HttpPacket">See the description of + <c>HttpPacket</c> in <seealso marker="erts:erlang#decode_packet/3"> + erlang:decode_packet/3</seealso>. + </type_desc> <desc> <p>This function receives a packet from a socket in passive mode. A closed socket is indicated by a return value <c>{error, closed}</c>.</p> - <p>The <c>Length</c> argument is only meaningful when + <p>The <c><anno>Length</anno></c> argument is only meaningful when the socket is in <c>raw</c> mode and denotes the number of - bytes to read. If <c>Length</c> = 0, all available bytes are - returned. If <c>Length</c> > 0, exactly <c>Length</c> + bytes to read. If <c><anno>Length</anno></c> = 0, all available bytes are + returned. If <c><anno>Length</anno></c> > 0, exactly <c><anno>Length</anno></c> bytes are returned, or an error; possibly discarding less - than <c>Length</c> bytes of data when the socket gets closed + than <c><anno>Length</anno></c> bytes of data when the socket gets closed from the other side.</p> - <p>The optional <c>Timeout</c> parameter specifies a timeout in + <p>The optional <c><anno>Timeout</anno></c> parameter specifies a timeout in milliseconds. The default value is <c>infinity</c>.</p> </desc> </func> <func> - <name>controlling_process(Socket, Pid) -> ok | {error, Reason}</name> + <name name="controlling_process" arity="2"/> <fsummary>Change controlling process of a socket</fsummary> - <type> - <v>Socket = socket()</v> - <v>Pid = pid()</v> - <v>Reason = closed | not_owner | posix()</v> - </type> <desc> - <p>Assigns a new controlling process <c>Pid</c> to - <c>Socket</c>. The controlling process is the process which + <p>Assigns a new controlling process <c><anno>Pid</anno></c> to + <c><anno>Socket</anno></c>. The controlling process is the process which receives messages from the socket. If called by any other process than the current controlling process, <c>{error, eperm}</c> is returned.</p> </desc> </func> <func> - <name>close(Socket) -> ok | {error, Reason}</name> + <name name="close" arity="1"/> <fsummary>Close a TCP socket</fsummary> - <type> - <v>Socket = socket()</v> - <v>Reason = posix()</v> - </type> <desc> <p>Closes a TCP socket.</p> </desc> </func> <func> - <name>shutdown(Socket, How) -> ok | {error, Reason}</name> + <name name="shutdown" arity="2"/> <fsummary>Immediately close a socket</fsummary> - <type> - <v>Socket = socket()</v> - <v>How = read | write | read_write</v> - <v>Reason = posix()</v> - </type> <desc> <p>Immediately close a socket in one or two directions.</p> - <p><c>How == write</c> means closing the socket for writing, + <p><c><anno>How</anno> == write</c> means closing the socket for writing, reading from it is still possible.</p> <p>To be able to handle that the peer has done a shutdown on the write side, the <c>{exit_on_close, false}</c> option diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml index 71f2e9bd83..daa9b7d887 100644 --- a/lib/kernel/doc/src/gen_udp.xml +++ b/lib/kernel/doc/src/gen_udp.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -34,32 +34,28 @@ with sockets using the UDP protocol.</p> </description> - <section> - <title>DATA TYPES</title> - <code type="none"> -ip_address() - see inet(3) - -posix() - see inet(3) + <datatypes> + <datatype> + <name name="option"/> + </datatype> + <datatype> + <name name="option_name"/> + </datatype> + <datatype> + <name><marker id="type-socket">socket()</marker></name> + <desc> + <p>As returned by open/1,2.</p> + </desc> + </datatype> + </datatypes> -socket() - as returned by open/1,2</code> - </section> <funcs> <func> - <name>open(Port) -> {ok, Socket} | {error, Reason}</name> - <name>open(Port, Options) -> {ok, Socket} | {error, Reason}</name> + <name name="open" arity="1"/> + <name name="open" arity="2"/> <fsummary>Associate a UDP port number with the process calling it</fsummary> - <type> - <v>Port = 0..65535</v> - <v>Options = [Opt]</v> - <v> Opt -- see below</v> - <v>Socket = socket()</v> - <v>Reason = posix()</v> - </type> <desc> - <p>Associates a UDP port number (<c>Port</c>) with the calling + <p>Associates a UDP port number (<c><anno>Port</anno></c>) with the calling process.</p> <p>The available options are:</p> <taglist> @@ -76,7 +72,7 @@ socket() <p>If the host has several network interfaces, this option specifies which one to use.</p> </item> - <tag><c>{fd, int()}</c></tag> + <tag><c>{fd, integer() >= 0}</c></tag> <item> <p>If a socket has somehow been opened without using <c>gen_udp</c>, use this option to pass the file @@ -96,7 +92,7 @@ socket() <seealso marker="inet#setopts/2">inet:setopts/2</seealso>.</p> </item> </taglist> - <p>The returned socket <c>Socket</c> is used to send packets + <p>The returned socket <c><anno>Socket</anno></c> is used to send packets from this port with <c>send/4</c>. When UDP packets arrive at the opened port, they are delivered as messages:</p> <code type="none"> @@ -110,66 +106,42 @@ socket() binary if the option <c>binary</c> was specified.</p> <p>Default value for the receive buffer option is <c>{recbuf, 8192}</c>.</p> - <p>If <c>Port == 0</c>, the underlying OS assigns a free UDP + <p>If <c><anno>Port</anno> == 0</c>, the underlying OS assigns a free UDP port, use <c>inet:port/1</c> to retrieve it.</p> </desc> </func> <func> - <name>send(Socket, Address, Port, Packet) -> ok | {error, Reason}</name> + <name name="send" arity="4"/> <fsummary>Send a packet</fsummary> - <type> - <v>Socket = socket()</v> - <v>Address = string() | atom() | ip_address()</v> - <v>Port = 0..65535</v> - <v>Packet = [char()] | binary()</v> - <v>Reason = not_owner | posix()</v> - </type> <desc> <p>Sends a packet to the specified address and port. - The <c>Address</c> argument can be either a hostname, or an + The <c><anno>Address</anno></c> argument can be either a hostname, or an IP address.</p> </desc> </func> <func> - <name>recv(Socket, Length) -> {ok, {Address, Port, Packet}} | {error, Reason}</name> - <name>recv(Socket, Length, Timeout) -> {ok, {Address, Port, Packet}} | {error, Reason}</name> + <name name="recv" arity="2"/> + <name name="recv" arity="3"/> <fsummary>Receive a packet from a passive socket</fsummary> - <type> - <v>Socket = socket()</v> - <v>Length = int()</v> - <v>Address = ip_address()</v> - <v>Port = 0..65535</v> - <v>Packet = [char()] | binary()</v> - <v>Timeout = int() | infinity</v> - <v>Reason = not_owner | posix()</v> - </type> <desc> <p>This function receives a packet from a socket in passive mode.</p> - <p>The optional <c>Timeout</c> parameter specifies a timeout in + <p>The optional <c><anno>Timeout</anno></c> parameter specifies a timeout in milliseconds. The default value is <c>infinity</c>.</p> </desc> </func> <func> - <name>controlling_process(Socket, Pid) -> ok</name> + <name name="controlling_process" arity="2"/> <fsummary>Change controlling process of a socket</fsummary> - <type> - <v>Socket = socket()</v> - <v>Pid = pid()</v> - </type> <desc> - <p>Assigns a new controlling process <c>Pid</c> to - <c>Socket</c>. The controlling process is the process which + <p>Assigns a new controlling process <c><anno>Pid</anno></c> to + <c><anno>Socket</anno></c>. The controlling process is the process which receives messages from the socket.</p> </desc> </func> <func> - <name>close(Socket) -> ok | {error, Reason}</name> + <name name="close" arity="1"/> <fsummary>Close a UDP socket</fsummary> - <type> - <v>Socket = socket()</v> - <v>Reason = not_owner | posix()</v> - </type> <desc> <p>Closes a UDP socket.</p> </desc> diff --git a/lib/kernel/doc/src/global.xml b/lib/kernel/doc/src/global.xml index 077109d6c9..304a9b1d88 100644 --- a/lib/kernel/doc/src/global.xml +++ b/lib/kernel/doc/src/global.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2009</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -106,45 +106,37 @@ </description> + <datatypes> + <datatype> + <name name="id"/> + </datatype> + </datatypes> + <funcs> <func> - <name>del_lock(Id)</name> - <name>del_lock(Id, Nodes) -> void()</name> + <name name="del_lock" arity="1"/> + <name name="del_lock" arity="2"/> <fsummary>Delete a lock</fsummary> - <type> - <v>Id = {ResourceId, LockRequesterId}</v> - <v> ResourceId = term()</v> - <v> LockRequesterId = term()</v> - <v>Nodes = [node()]</v> - </type> <desc> - <p>Deletes the lock <c>Id</c> synchronously.</p> + <p>Deletes the lock <c><anno>Id</anno></c> synchronously.</p> </desc> </func> <func> - <name>notify_all_name(Name, Pid1, Pid2) -> none</name> + <name name="notify_all_name" arity="3"/> <fsummary>Name resolving function that notifies both pids</fsummary> - <type> - <v>Name = term()</v> - <v>Pid1 = Pid2 = pid()</v> - </type> <desc> <p>This function can be used as a name resolving function for <c>register_name/3</c> and <c>re_register_name/3</c>. It unregisters both pids, and sends the message - <c>{global_name_conflict, Name, OtherPid}</c> to both + <c>{global_name_conflict, <anno>Name</anno>, OtherPid}</c> to both processes.</p> </desc> </func> <func> - <name>random_exit_name(Name, Pid1, Pid2) -> Pid1 | Pid2</name> + <name name="random_exit_name" arity="3"/> <fsummary>Name resolving function that kills one pid</fsummary> - <type> - <v>Name = term()</v> - <v>Pid1 = Pid2 = pid()</v> - </type> <desc> <p>This function can be used as a name resolving function for <c>register_name/3</c> and <c>re_register_name/3</c>. It @@ -154,33 +146,27 @@ </func> <func> - <name>random_notify_name(Name, Pid1, Pid2) -> Pid1 | Pid2</name> + <name name="random_notify_name" arity="3"/> <fsummary>Name resolving function that notifies one pid</fsummary> - <type> - <v>Name = term()</v> - <v>Pid1 = Pid2 = pid()</v> - </type> <desc> <p>This function can be used as a name resolving function for <c>register_name/3</c> and <c>re_register_name/3</c>. It randomly chooses one of the pids for registration, and sends - the message <c>{global_name_conflict, Name}</c> to the other + the message <c>{global_name_conflict, <anno>Name</anno>}</c> to the other pid.</p> </desc> </func> <func> - <name>register_name(Name, Pid)</name> - <name>register_name(Name, Pid, Resolve) -> yes | no</name> + <name name="register_name" arity="2"/> + <name name="register_name" arity="3"/> <fsummary>Globally register a name for a pid</fsummary> - <type> - <v>Name = term()</v> - <v>Pid = pid()</v> - <v>Resolve = fun() or {Module, Function} where</v> - <v> Resolve(Name, Pid, Pid2) -> Pid | Pid2 | none</v> - </type> + <type name="method"/> + <type_desc name="method">{<c>Module</c>, <c>Function</c>} + is also allowed + </type_desc> <desc> - <p>Globally associates the name <c>Name</c> with a pid, that is, + <p>Globally associates the name <c><anno>Name</anno></c> with a pid, that is, Globally notifies all nodes of a new global name in a network of Erlang nodes.</p> @@ -188,7 +174,7 @@ of the globally registered names that already exist. The network is also informed of any global names in newly connected nodes. If any name clashes are discovered, - the <c>Resolve</c> function is called. Its purpose is to + the <c><anno>Resolve</anno></c> function is called. Its purpose is to decide which pid is correct. If the function crashes, or returns anything other than one of the pids, the name is unregistered. This function is called once for each name @@ -196,7 +182,7 @@ <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>Resolve</c> function is + <c>notify_all_name/3</c>. If no <c><anno>Resolve</anno></c> function is defined, <c>random_exit_name</c> is used. This means that one of the two registered processes will be selected as correct while the other is killed.</p> @@ -225,78 +211,63 @@ </func> <func> - <name>registered_names() -> [Name]</name> + <name name="registered_names" arity="0"/> <fsummary>All globally registered names</fsummary> - <type> - <v>Name = term()</v> - </type> <desc> <p>Returns a lists of all globally registered names.</p> </desc> </func> <func> - <name>re_register_name(Name, Pid)</name> - <name>re_register_name(Name, Pid, Resolve) -> void()</name> + <name name="re_register_name" arity="2"/> + <name name="re_register_name" arity="3"/> <fsummary>Atomically re-register a name</fsummary> - <type> - <v>Name = term()</v> - <v>Pid = pid()</v> - <v>Resolve = fun() or {Module, Function} where</v> - <v> Resolve(Name, Pid, Pid2) -> Pid | Pid2 | none</v> - </type> + <type name="method"/> + <type_desc name="method">{<c>Module</c>, <c>Function</c>} + is also allowed + </type_desc> <desc> - <p>Atomically changes the registered name <c>Name</c> on all - nodes to refer to <c>Pid</c>.</p> + <p>Atomically changes the registered name <c><anno>Name</anno></c> on all + nodes to refer to <c><anno>Pid</anno></c>.</p> - <p>The <c>Resolve</c> function has the same behavior as in + <p>The <c><anno>Resolve</anno></c> function has the same behavior as in <c>register_name/2,3</c>.</p> </desc> </func> <func> - <name>send(Name, Msg) -> Pid</name> + <name name="send" arity="2"/> <fsummary>Send a message to a globally registered pid</fsummary> - <type> - <v>Name = term()</v> - <v>Msg = term()</v> - <v>Pid = pid()</v> - </type> <desc> - <p>Sends the message <c>Msg</c> to the pid globally registered - as <c>Name</c>.</p> + <p>Sends the message <c><anno>Msg</anno></c> to the pid globally registered + as <c><anno>Name</anno></c>.</p> - <p>Failure: If <c>Name</c> is not a globally registered + <p>Failure: If <c><anno>Name</anno></c> is not a globally registered name, the calling function will exit with reason - <c>{badarg, {Name, Msg}}</c>.</p> + <c>{badarg, {<anno>Name</anno>, <anno>Msg</anno>}}</c>.</p> </desc> </func> <func> - <name>set_lock(Id)</name> - <name>set_lock(Id, Nodes)</name> - <name>set_lock(Id, Nodes, Retries) -> boolean()</name> + <name name="set_lock" arity="1"/> + <name name="set_lock" arity="2"/> + <name name="set_lock" arity="3"/> <fsummary>Set a lock on the specified nodes</fsummary> - <type> - <v>Id = {ResourceId, LockRequesterId}</v> - <v> ResourceId = term()</v> - <v> LockRequesterId = term()</v> - <v>Nodes = [node()]</v> - <v>Retries = int() >= 0 | infinity</v> - </type> + <type name="id"/> + <type name="retries"/> <desc> <p>Sets a lock on the specified nodes (or on all nodes if none - are specified) on <c>ResourceId</c> for - <c>LockRequesterId</c>. If a lock already exists on - <c>ResourceId</c> for another requester than - <c>LockRequesterId</c>, and <c>Retries</c> is not equal to 0, + are specified) on <c><anno>ResourceId</anno></c> for + <c><anno>LockRequesterId</anno></c>. If a lock already exists on + <c><anno>ResourceId</anno></c> for another requester than + <c><anno>LockRequesterId</anno></c>, and <c><anno>Retries</anno></c> is not equal to 0, the process sleeps for a while and will try to execute - the action later. When <c>Retries</c> attempts have been made, + the action later. When <c><anno>Retries</anno></c> attempts have been made, <c>false</c> is returned, otherwise <c>true</c>. If - <c>Retries</c> is <c>infinity</c>, <c>true</c> is eventually + <c><anno>Retries</anno></c> is <c>infinity</c>, <c>true</c> is eventually returned (unless the lock is never released).</p> - <p>If no value for <c>Retries</c> is given, <c>infinity</c> is + <p>If no value for <c><anno>Retries</anno></c> is given, <c>infinity</c> is used.</p> <p>This function is completely synchronous.</p> @@ -315,7 +286,7 @@ application to detect and rectify a deadlock.</p> <note> - <p>Some values of <c>ResourceId</c> should be avoided or + <p>Some values of <c><anno>ResourceId</anno></c> should be avoided or Erlang/OTP will not work properly. A list of resources to avoid: <c>global</c>, <c>dist_ac</c>, <c>mnesia_table_lock</c>, <c>mnesia_adjust_log_writes</c>, @@ -326,7 +297,7 @@ </func> <func> - <name>sync() -> void()</name> + <name name="sync" arity="0"/> <fsummary>Synchronize the global name server</fsummary> <desc> <p>Synchronizes the global name server with all nodes known to @@ -335,56 +306,45 @@ the global name server will receive global information from all nodes. This function can be called when new nodes are added to the network.</p> + <p>The only possible error reason <c>Reason</c> is + <c>{"global_groups definition error", Error}</c>.</p> </desc> </func> <func> - <name>trans(Id, Fun)</name> - <name>trans(Id, Fun, Nodes)</name> - <name>trans(Id, Fun, Nodes, Retries) -> Res | aborted</name> + <name name="trans" arity="2"/> + <name name="trans" arity="3"/> + <name name="trans" arity="4"/> <fsummary>Micro transaction facility</fsummary> - <type> - <v>Id = {ResourceId, LockRequesterId}</v> - <v> ResourceId = term()</v> - <v> LockRequesterId = term()</v> - <v>Fun = fun() | {M, F}</v> - <v>Nodes = [node()]</v> - <v>Retries = int() >= 0 | infinity</v> - <v>Res = term()</v> - </type> + <type name="retries"/> + <type name="trans_fun"/> <desc> - <p>Sets a lock on <c>Id</c> (using <c>set_lock/3</c>). If this - succeeds, <c>Fun()</c> is evaluated and the result <c>Res</c> + <p>Sets a lock on <c><anno>Id</anno></c> (using <c>set_lock/3</c>). If this + succeeds, <c><anno>Fun</anno>()</c> is evaluated and the result <c><anno>Res</anno></c> is returned. Returns <c>aborted</c> if the lock attempt - failed. If <c>Retries</c> is set to <c>infinity</c>, + failed. If <c><anno>Retries</anno></c> is set to <c>infinity</c>, the transaction will not abort.</p> <p><c>infinity</c> is the default setting and will be used if - no value is given for <c>Retries</c>.</p> + no value is given for <c><anno>Retries</anno></c>.</p> </desc> </func> <func> - <name>unregister_name(Name) -> void()</name> + <name name="unregister_name" arity="1"/> <fsummary>Remove a globally registered name for a pid</fsummary> - <type> - <v>Name = term()</v> - </type> <desc> - <p>Removes the globally registered name <c>Name</c> from + <p>Removes the globally registered name <c><anno>Name</anno></c> from the network of Erlang nodes.</p> </desc> </func> <func> - <name>whereis_name(Name) -> pid() | undefined</name> + <name name="whereis_name" arity="1"/> <fsummary>Get the pid with a given globally registered name</fsummary> - <type> - <v>Name = term()</v> - </type> <desc> <p>Returns the pid with the globally registered name - <c>Name</c>. Returns <c>undefined</c> if the name is not + <c><anno>Name</anno></c>. Returns <c>undefined</c> if the name is not globally registered.</p> </desc> </func> diff --git a/lib/kernel/doc/src/global_group.xml b/lib/kernel/doc/src/global_group.xml index 4facf4a4aa..abf6178fc4 100644 --- a/lib/kernel/doc/src/global_group.xml +++ b/lib/kernel/doc/src/global_group.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1998</year><year>2009</year> + <year>1998</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -42,26 +42,7 @@ <seealso marker="kernel_app">kernel(6)</seealso>, <seealso marker="config">config(4)</seealso>:</p> <code type="none"> -{global_groups, [GroupTuple]}</code> - <p>Types:</p> - <list type="bulleted"> - <item><c>GroupTuple = {GroupName, [Node]} | {GroupName, PublishType, [Node]}</c></item> - <item><c>GroupName = atom()</c> (naming a global group)</item> - <item><c>PublishType = normal | hidden</c></item> - <item><c>Node = atom()</c> (naming a node)</item> - </list> - <p>A <c>GroupTuple</c> without <c>PublishType</c> is the same as a - <c>GroupTuple</c> with <c>PublishType == normal</c>.</p> - <p>A node started with the command line flag <c>-hidden</c>, see - <seealso marker="erts:erl">erl(1)</seealso>, is said to be a - <em>hidden</em> node. A hidden node will establish hidden - connections to nodes not part of the same global group, but - normal (visible) connections to nodes part of the same global - group.</p> - <p>A global group defined with <c>PublishType == hidden</c>, is - said to be a hidden global group. All nodes in a hidden global - group are hidden nodes, regardless if they are started with - the <c>-hidden</c> command line flag or not.</p> +{global_groups, [GroupTuple :: group_tuple()]}</code> <p>For the processes and nodes to run smoothly using the global group functionality, the following criteria must be met:</p> <list type="bulleted"> @@ -82,14 +63,44 @@ <p>In the following description, a <em>group node</em> is a node belonging to the same global group as the local node.</p> </description> + <datatypes> + <datatype> + <name name="group_tuple"/> + <desc> + <p>A <c>GroupTuple</c> without <c>PublishType</c> is the same as a + <c>GroupTuple</c> with <c>PublishType == normal</c>.</p> + </desc> + </datatype> + <datatype> + <name name="group_name"/> + </datatype> + <datatype> + <name name="publish_type"/> + <desc> + <p>A node started with the command line flag <c>-hidden</c>, see + <seealso marker="erts:erl">erl(1)</seealso>, is said to be a + <em>hidden</em> node. A hidden node will establish hidden + connections to nodes not part of the same global group, but + normal (visible) connections to nodes part of the same global + group.</p> + <p>A global group defined with <c>PublishType == hidden</c>, is + said to be a hidden global group. All nodes in a hidden global + group are hidden nodes, regardless if they are started with + the <c>-hidden</c> command line flag or not.</p> + </desc> + </datatype> + <datatype> + <name name="name"/> + <desc><p>A registered name.</p></desc> + </datatype> + <datatype> + <name name="where"/> + </datatype> + </datatypes> <funcs> <func> - <name>global_groups() -> {GroupName, GroupNames} | undefined</name> + <name name="global_groups" arity="0"/> <fsummary>Return the global group names</fsummary> - <type> - <v>GroupName = atom()</v> - <v>GroupNames = [GroupName]</v> - </type> <desc> <p>Returns a tuple containing the name of the global group the local node belongs to, and the list of all other known @@ -98,53 +109,52 @@ </desc> </func> <func> - <name>info() -> [{Item, Info}]</name> + <name name="info" arity="0"/> <fsummary>Information about global groups</fsummary> - <type> - <v>Item, Info -- see below</v> - </type> + <type name="info_item"/> + <type name="sync_state"/> <desc> <p>Returns a list containing information about the global groups. Each element of the list is a tuple. The order of the tuples is not defined.</p> <taglist> - <tag><c>{state, State}</c></tag> + <tag><c>{state, <anno>State</anno>}</c></tag> <item> <p>If the local node is part of a global group, - <c>State == synced</c>. If no global groups are defined, - <c>State == no_conf</c>.</p> + <c><anno>State</anno> == synced</c>. If no global groups are defined, + <c><anno>State</anno> == no_conf</c>.</p> </item> - <tag><c>{own_group_name, GroupName}</c></tag> + <tag><c>{own_group_name, <anno>GroupName</anno>}</c></tag> <item> <p>The name (atom) of the group that the local node belongs to.</p> </item> - <tag><c>{own_group_nodes, Nodes}</c></tag> + <tag><c>{own_group_nodes, <anno>Nodes</anno>}</c></tag> <item> <p>A list of node names (atoms), the group nodes.</p> </item> - <tag><c>{synced_nodes, Nodes}</c></tag> + <tag><c>{synced_nodes, <anno>Nodes</anno>}</c></tag> <item> <p>A list of node names, the group nodes currently synchronized with the local node.</p> </item> - <tag><c>{sync_error, Nodes}</c></tag> + <tag><c>{sync_error, <anno>Nodes</anno>}</c></tag> <item> <p>A list of node names, the group nodes with which the local node has failed to synchronize.</p> </item> - <tag><c>{no_contact, Nodes}</c></tag> + <tag><c>{no_contact, <anno>Nodes</anno>}</c></tag> <item> <p>A list of node names, the group nodes to which there are currently no connections.</p> </item> - <tag><c>{other_groups, Groups}</c></tag> + <tag><c>{other_groups, <anno>Groups</anno>}</c></tag> <item> - <p><c>Groups</c> is a list of tuples - <c>{GroupName, Nodes}</c>, specifying the name and nodes + <p><c><anno>Groups</anno></c> is a list of tuples + <c>{<anno>GroupName</anno>, <anno>Nodes</anno>}</c>, specifying the name and nodes of the other global groups.</p> </item> - <tag><c>{monitoring, Pids}</c></tag> + <tag><c>{monitoring, <anno>Pids</anno>}</c></tag> <item> <p>A list of pids, specifying the processes which have subscribed to <c>nodeup</c> and <c>nodedown</c> messages.</p> @@ -153,73 +163,52 @@ </desc> </func> <func> - <name>monitor_nodes(Flag) -> ok </name> + <name name="monitor_nodes" arity="1"/> <fsummary>Subscribe to node status changes</fsummary> - <type> - <v>Flag = bool()</v> - </type> <desc> - <p>Depending on <c>Flag</c>, the calling process starts - subscribing (<c>Flag == true</c>) or stops subscribing - (<c>Flag == false</c>) to node status change messages.</p> + <p>Depending on <c><anno>Flag</anno></c>, the calling process starts + subscribing (<c><anno>Flag</anno> == true</c>) or stops subscribing + (<c><anno>Flag</anno> == false</c>) to node status change messages.</p> <p>A process which has subscribed will receive the messages <c>{nodeup, Node}</c> and <c>{nodedown, Node}</c> when a group node connects or disconnects, respectively.</p> </desc> </func> <func> - <name>own_nodes() -> Nodes</name> + <name name="own_nodes" arity="0"/> <fsummary>Return the group nodes</fsummary> - <type> - <v>Nodes = [Node]</v> - <v> Node = node()</v> - </type> <desc> <p>Returns the names of all group nodes, regardless of their current status.</p> </desc> </func> <func> - <name>registered_names(Where) -> Names</name> + <name name="registered_names" arity="1"/> <fsummary>Return globally registered names</fsummary> - <type> - <v>Where = {node, Node} | {group, GroupName}</v> - <v> Node = node()</v> - <v> GroupName = atom()</v> - <v>Names = [Name]</v> - <v> Name = atom()</v> - </type> <desc> <p>Returns a list of all names which are globally registered on the specified node or in the specified global group.</p> </desc> </func> <func> - <name>send(Name, Msg) -> pid() | {badarg, {Name, Msg}}</name> - <name>send(Where, Name, Msg) -> pid() | {badarg, {Name, Msg}}</name> + <name name="send" arity="2"/> + <name name="send" arity="3"/> <fsummary>Send a message to a globally registered pid</fsummary> - <type> - <v>Where = {node, Node} | {group, GroupName}</v> - <v> Node = node()</v> - <v> GroupName = atom()</v> - <v>Name = atom()</v> - <v>Msg = term()</v> - </type> <desc> - <p>Searches for <c>Name</c>, globally registered on + <p>Searches for <c><anno>Name</anno></c>, globally registered on the specified node or in the specified global group, or -- - if the <c>Where</c> argument is not provided -- in any global + if the <c><anno>Where</anno></c> argument is not provided -- in any global group. The global groups are searched in the order in which they appear in the value of the <c>global_groups</c> configuration parameter.</p> - <p>If <c>Name</c> is found, the message <c>Msg</c> is sent to + <p>If <c><anno>Name</anno></c> is found, the message <c><anno>Msg</anno></c> is sent to the corresponding pid. The pid is also the return value of the function. If the name is not found, the function returns - <c>{badarg, {Name, Msg}}</c>.</p> + <c>{badarg, {<anno>Name</anno>, <anno>Msg</anno>}}</c>.</p> </desc> </func> <func> - <name>sync() -> ok</name> + <name name="sync" arity="0"/> <fsummary>Synchronize the group nodes</fsummary> <desc> <p>Synchronizes the group nodes, that is, the global name @@ -235,23 +224,17 @@ </desc> </func> <func> - <name>whereis_name(Name) -> pid() | undefined</name> - <name>whereis_name(Where, Name) -> pid() | undefined</name> + <name name="whereis_name" arity="1"/> + <name name="whereis_name" arity="2"/> <fsummary>Get the pid with a given globally registered name</fsummary> - <type> - <v>Where = {node, Node} | {group, GroupName}</v> - <v> Node = node()</v> - <v> GroupName = atom()</v> - <v>Name = atom()</v> - </type> <desc> - <p>Searches for <c>Name</c>, globally registered on + <p>Searches for <c><anno>Name</anno></c>, globally registered on the specified node or in the specified global group, or -- if - the <c>Where</c> argument is not provided -- in any global + the <c><anno>Where</anno></c> argument is not provided -- in any global group. The global groups are searched in the order in which they appear in the value of the <c>global_groups</c> configuration parameter.</p> - <p>If <c>Name</c> is found, the corresponding pid is returned. + <p>If <c><anno>Name</anno></c> is found, the corresponding pid is returned. If the name is not found, the function returns <c>undefined</c>.</p> </desc> diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml index 0df699572d..26d1e27822 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>2009</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -42,7 +42,7 @@ system.</p> <p>An Erlang runtime system to be monitored by a heart program, should be started with the command line flag <c>-heart</c> (see - also <seealso marker="erts:erl">erl(1)</seealso>. The <c>heart</c> + also <seealso marker="erts:erl">erl(1)</seealso>). The <c>heart</c> process is then started automatically:</p> <pre> % <input>erl -heart ...</input></pre> @@ -76,11 +76,8 @@ </description> <funcs> <func> - <name>set_cmd(Cmd) -> ok | {error, {bad_cmd, Cmd}}</name> + <name name="set_cmd" arity="1"/> <fsummary>Set a temporary reboot command</fsummary> - <type> - <v>Cmd = string()</v> - </type> <desc> <p>Sets a temporary reboot command. This command is used if a <c>HEART_COMMAND</c> other than the one specified with @@ -88,12 +85,12 @@ the system. The new Erlang runtime system will (if it misbehaves) use the environment variable <c>HEART_COMMAND</c> to reboot.</p> - <p>Limitations: The length of the <c>Cmd</c> command string + <p>Limitations: The length of the <c><anno>Cmd</anno></c> command string must be less than 2047 characters.</p> </desc> </func> <func> - <name>clear_cmd() -> ok</name> + <name name="clear_cmd" arity="0"/> <fsummary>Clear the temporary boot command</fsummary> <desc> <p>Clears the temporary boot command. If the system terminates, @@ -101,11 +98,8 @@ </desc> </func> <func> - <name>get_cmd() -> {ok, Cmd}</name> + <name name="get_cmd" arity="0"/> <fsummary>Get the temporary reboot command</fsummary> - <type> - <v>Cmd = string()</v> - </type> <desc> <p>Get the temporary reboot command. If the command is cleared, the empty string will be returned.</p> diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index f05a224f33..fad5af85bb 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1997</year><year>2010</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -54,33 +54,6 @@ $ <input>erl -sname test -kernel \</input> <input>inet_default_listen_options '[{delay_send,true}]'</input></pre> <p>Note that the default option <c>{active, true}</c> currently cannot be changed, for internal reasons.</p> - </description> - - <section> - <title>DATA TYPES</title> - <code type="none"> -#hostent{h_addr_list = [ip_address()] % list of addresses for this host - h_addrtype = inet | inet6 - h_aliases = [hostname()] % list of aliases - h_length = int() % length of address in bytes - h_name = hostname() % official name for host - The record is defined in the Kernel include file "inet.hrl" - Add the following directive to the module: - -include_lib("kernel/include/inet.hrl"). - -hostname() = atom() | string() - -ip_address() = {N1,N2,N3,N4} % IPv4 - | {K1,K2,K3,K4,K5,K6,K7,K8} % IPv6 - Ni = 0..255 - Ki = 0..65535 - -posix() - an atom which is named from the Posix error codes used in - Unix, and in the runtime libraries of most C compilers - -socket() - see gen_tcp(3), gen_udp(3)</code> <p>Addresses as inputs to functions can be either a string or a tuple. For instance, the IP address 150.236.20.73 can be passed to <c>gethostbyaddr/1</c> either as the string "150.236.20.73" @@ -109,24 +82,61 @@ fe80::204:acff:fe17:bf38 {ok,{192,168,42,2}} 2> <input>inet_parse:address("FFFF::192.168.42.2").</input> {ok,{65535,0,0,0,0,0,49320,10754}}</pre> - </section> + </description> + + <datatypes> + <datatype> + <name name="hostent"/> + <desc> + <p>The record is defined in the Kernel include file "inet.hrl". + Add the following directive to the module:</p> +<code>-include_lib("kernel/include/inet.hrl").</code></desc> + </datatype> + <datatype> + <name name="hostname"/> + </datatype> + <datatype> + <name name="ip_address"/> + </datatype> + <datatype> + <name name="ip4_address"/> + </datatype> + <datatype> + <name name="ip6_address"/> + </datatype> + <datatype> + <name name="port_number"/> + </datatype> + <datatype> + <name name="posix"/> + <desc><p>An atom which is named from the Posix error codes + used in Unix, and in the runtime libraries of most + C compilers. See + <seealso marker="#error_codes">POSIX Error Codes</seealso>.</p> + </desc> + </datatype> + <datatype> + <name><marker id="type-socket">socket()</marker></name> + <desc><p>See <seealso marker="gen_tcp#type-socket">gen_tcp(3)</seealso> + and <seealso marker="gen_udp#type-socket">gen_udp(3)</seealso>.</p> + </desc> + </datatype> + <datatype> + <name name="address_family"/> + </datatype> + </datatypes> + <funcs> <func> - <name>close(Socket) -> ok</name> + <name name="close" arity="1"/> <fsummary>Close a socket of any type</fsummary> - <type> - <v>Socket = socket()</v> - </type> <desc> <p>Closes a socket of any type.</p> </desc> </func> <func> - <name>get_rc() -> [{Par, Val}]</name> + <name name="get_rc" arity="0"/> <fsummary>Return a list of IP configuration parameters</fsummary> - <type> - <v>Par, Val -- see below</v> - </type> <desc> <p>Returns the state of the Inet configuration database in form of a list of recorded configuration parameters. (See the @@ -135,116 +145,74 @@ fe80::204:acff:fe17:bf38 </desc> </func> <func> - <name>format_error(Posix) -> string()</name> + <name name="format_error" arity="1"/> <fsummary>Return a descriptive string for an error reason</fsummary> - <type> - <v>Posix = posix()</v> - </type> <desc> <p>Returns a diagnostic error string. See the section below - for possible <c>Posix</c> values and the corresponding + for possible <c><anno>Posix</anno></c> values and the corresponding strings.</p> </desc> </func> <func> - <name>getaddr(Host, Family) -> {ok, Address} | {error, posix()}</name> + <name name="getaddr" arity="2"/> <fsummary>Return the IP-address for a host</fsummary> - <type> - <v>Host = ip_address() | string() | atom()</v> - <v>Family = inet | inet6</v> - <v>Address = ip_address()</v> - <v>posix() = term()</v> - </type> <desc> - <p>Returns the IP-address for <c>Host</c> as a tuple of - integers. <c>Host</c> can be an IP-address, a single hostname + <p>Returns the IP-address for <c><anno>Host</anno></c> as a tuple of + integers. <c><anno>Host</anno></c> can be an IP-address, a single hostname or a fully qualified hostname.</p> </desc> </func> <func> - <name>getaddrs(Host, Family) -> {ok, Addresses} | {error, posix()}</name> + <name name="getaddrs" arity="2"/> <fsummary>Return the IP-addresses for a host</fsummary> - <type> - <v>Host = ip_address() | string() | atom()</v> - <v>Addresses = [ip_address()]</v> - <v>Family = inet | inet6</v> - </type> <desc> - <p>Returns a list of all IP-addresses for <c>Host</c>. - <c>Host</c> can be an IP-address, a single hostname or a fully + <p>Returns a list of all IP-addresses for <c><anno>Host</anno></c>. + <c><anno>Host</anno></c> can be an IP-address, a single hostname or a fully qualified hostname.</p> </desc> </func> <func> - <name>gethostbyaddr(Address) -> {ok, Hostent} | {error, posix()}</name> + <name name="gethostbyaddr" arity="1"/> <fsummary>Return a hostent record for the host with the given address</fsummary> - <type> - <v>Address = string() | ip_address()</v> - <v>Hostent = #hostent{}</v> - </type> <desc> <p>Returns a <c>hostent</c> record given an address.</p> </desc> </func> <func> - <name>gethostbyname(Name) -> {ok, Hostent} | {error, posix()}</name> + <name name="gethostbyname" arity="1"/> <fsummary>Return a hostent record for the host with the given name</fsummary> - <type> - <v>Hostname = hostname()</v> - <v>Hostent = #hostent{}</v> - </type> <desc> <p>Returns a <c>hostent</c> record given a hostname.</p> </desc> </func> <func> - <name>gethostbyname(Name, Family) -> {ok, Hostent} | {error, posix()}</name> + <name name="gethostbyname" arity="2"/> <fsummary>Return a hostent record for the host with the given name</fsummary> - <type> - <v>Hostname = hostname()</v> - <v>Family = inet | inet6</v> - <v>Hostent = #hostent{}</v> - </type> <desc> <p>Returns a <c>hostent</c> record given a hostname, restricted to the given address family.</p> </desc> </func> <func> - <name>gethostname() -> {ok, Hostname}</name> + <name name="gethostname" arity="0"/> <fsummary>Return the local hostname</fsummary> - <type> - <v>Hostname = string()</v> - </type> <desc> <p>Returns the local hostname. Will never fail.</p> </desc> </func> <func> - <name>getifaddrs() -> {ok,Iflist} | {error,posix}</name> + <name name="getifaddrs" arity="0"/> <fsummary>Return a list of interfaces and their addresses</fsummary> - <type> - <v>Iflist = {Ifname,[Ifopt]}</v> - <v>Ifname = string()</v> - <v>Ifopt = {flag,[Flag]} | {addr,Addr} | {netmask,Netmask} - | {broadaddr,Broadaddr} | {dstaddr,Dstaddr} - | {hwaddr,Hwaddr}</v> - <v>Flag = up | broadcast | loopback | pointtopoint - | running | multicast</v> - <v>Addr = Netmask = Broadadddr = Dstaddr = ip_address()</v> - <v>Hwaddr = [byte()]</v> - </type> - </func> <desc> <p> Returns a list of 2-tuples containing interface names and the - interface's addresses. <c>Ifname</c> is a Unicode string. - <c>Hwaddr</c> is hardware dependent, e.g on Ethernet interfaces + interface's addresses. <c><anno>Ifname</anno></c> is a Unicode string. + <c><anno>Hwaddr</anno></c> is hardware dependent, e.g on Ethernet interfaces it is the 6-byte Ethernet address (MAC address (EUI-48 address)). </p> <p> - The <c>{addr,Addr}</c>, <c>{netmask,_}</c> and <c>{broadaddr,_}</c> + The <c>{addr,<anno>Addr</anno>}</c>, <c>{netmask,_}</c> and <c>{broadaddr,_}</c> tuples are repeated in the result list iff the interface has multiple addresses. If you come across an interface that has multiple <c>{flag,_}</c> or <c>{hwaddr,_}</c> tuples you have @@ -252,8 +220,8 @@ fe80::204:acff:fe17:bf38 The <c>{flag,_}</c> tuple is mandatory, all other optional. </p> <p> - Do not rely too much on the order of <c>Flag</c> atoms or - <c>Ifopt</c> tuples. There are some rules, though: + Do not rely too much on the order of <c><anno>Flag</anno></c> atoms or + <c><anno>Ifopt</anno></c> tuples. There are some rules, though: <list> <item> Immediately after <c>{addr,_}</c> follows <c>{netmask,_}</c> @@ -261,7 +229,7 @@ fe80::204:acff:fe17:bf38 <item> Immediately thereafter follows <c>{broadaddr,_}</c> if the <c>broadcast</c> flag is <em>not</em> set and the - <c>pointtopoint</c>flag <em>is</em> set. + <c>pointtopoint</c> flag <em>is</em> set. </item> <item> Any <c>{netmask,_}</c>, <c>{broadaddr,_}</c> or @@ -277,32 +245,23 @@ fe80::204:acff:fe17:bf38 </p> <p> On Windows, the data is fetched from quite different OS API - functions, so the <c>Netmask</c> and <c>Broadaddr</c> - values may be calculated, just as some <c>Flag</c> values. + functions, so the <c><anno>Netmask</anno></c> and <c><anno>Broadaddr</anno></c> + values may be calculated, just as some <c><anno>Flag</anno></c> values. You have been warned. Report flagrant bugs. </p> </desc> + </func> <func> - <name>getopts(Socket, Options) -> {ok, OptionValues} | {error, posix()}</name> + <name name="getopts" arity="2"/> <fsummary>Get one or more options for a socket</fsummary> - <type> - <v>Socket = term()</v> - <v>Options = [Opt | RawOptReq]</v> - <v>Opt = atom()</v> - <v>RawOptReq = {raw, Protocol, OptionNum, ValueSpec}</v> - <v>Protocol = int()</v> - <v>OptionNum = int()</v> - <v>ValueSpec = ValueSize | ValueBin</v> - <v>ValueSize = int()</v> - <v>ValueBin = binary()</v> - <v>OptionValues = [{Opt, Val} | {raw, Protocol, OptionNum, ValueBin}]</v> - </type> + <type name="socket_getopt"/> + <type name="socket_setopt"/> <desc> <p>Gets one or more options for a socket. See <seealso marker="#setopts/2">setopts/2</seealso> for a list of available options.</p> - <p>The number of elements in the returned <c>OptionValues</c> + <p>The number of elements in the returned <c><anno>OptionValues</anno></c> list does not necessarily correspond to the number of options asked for. If the operating system fails to support an option, it is simply left out in the returned list. An error tuple is only @@ -310,12 +269,12 @@ fe80::204:acff:fe17:bf38 (i.e. the socket is closed or the buffer size in a raw request is too large). This behavior is kept for backward compatibility reasons.</p> - <p>A <c>RawOptReq</c> can be used to get information about + <p>A raw option request <c>RawOptReq = {raw, Protocol, OptionNum, ValueSpec}</c> can be used to get information about socket options not (explicitly) supported by the emulator. The use of raw socket options makes the code non portable, but allows the Erlang programmer to take advantage of unusual features present on the current platform.</p> - <p>The <c>RawOptReq</c> consists of the tag <c>raw</c> followed + <p>The <c>RawOptReq</c> consists of the tag <c>raw</c> followed by the protocol level, the option number and either a binary or the size, in bytes, of the buffer in which the option value is to be stored. A binary @@ -358,19 +317,14 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name>getstat(Socket)</name> - <name>getstat(Socket, Options) -> {ok, OptionValues} | {error, posix()}</name> + <name name="getstat" arity="1"/> + <name name="getstat" arity="2"/> <fsummary>Get one or more statistic options for a socket</fsummary> - <type> - <v>Socket = term()</v> - <v>Options = [Opt]</v> - <v>OptionValues = [{Opt, Val}]</v> - <v> Opt, Val -- see below</v> - </type> + <type name="stat_option"/> <desc> <p>Gets one or more statistic options for a socket.</p> - <p><c>getstat(Socket)</c> is equivalent to - <c>getstat(Socket, [recv_avg, recv_cnt, recv_dvi, recv_max, recv_oct, send_avg, send_cnt, send_dvi, send_max, send_oct])</c></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> <p>The following options are available:</p> <taglist> <tag><c>recv_avg</c></tag> @@ -419,52 +373,31 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name>peername(Socket) -> {ok, {Address, Port}} | {error, posix()}</name> + <name name="peername" arity="1"/> <fsummary>Return the address and port for the other end of a connection</fsummary> - <type> - <v>Socket = socket()</v> - <v>Address = ip_address()</v> - <v>Port = int()</v> - </type> <desc> <p>Returns the address and port for the other end of a connection.</p> </desc> </func> <func> - <name>port(Socket) -> {ok, Port} | {error, any()}</name> + <name name="port" arity="1"/> <fsummary>Return the local port number for a socket</fsummary> - <type> - <v>Socket = socket()</v> - <v>Port = int()</v> - </type> <desc> <p>Returns the local port number for a socket.</p> </desc> </func> <func> - <name>sockname(Socket) -> {ok, {Address, Port}} | {error, posix()}</name> + <name name="sockname" arity="1"/> <fsummary>Return the local address and port number for a socket</fsummary> - <type> - <v>Socket = socket()</v> - <v>Address = ip_address()</v> - <v>Port = int()</v> - </type> <desc> <p>Returns the local address and port number for a socket.</p> </desc> </func> <func> - <name>setopts(Socket, Options) -> ok | {error, posix()}</name> + <name name="setopts" arity="2"/> <fsummary>Set one or more options for a socket</fsummary> - <type> - <v>Socket = term()</v> - <v>Options = [{Opt, Val} | {raw, Protocol, Option, ValueBin}]</v> - <v>Protocol = int()</v> - <v>OptionNum = int()</v> - <v>ValueBin = binary()</v> - <v> Opt, Val -- see below</v> - </type> + <type name="socket_setopt"/> <desc> <p>Sets one or more options for a socket. The following options are available:</p> @@ -622,8 +555,14 @@ fe80::204:acff:fe17:bf38 mode will return <c>{ok, HttpPacket}</c> from <c>gen_tcp:recv</c> while an active socket will send messages like <c>{http, Socket, HttpPacket}</c>.</p> - <p>Note that the packet type <c>httph</c> is not - needed when reading from a socket.</p> + </item> + <tag><c>httph | httph_bin</c></tag> + <item> + <p>These two types are often not needed as the socket will + automatically switch from <c>http</c>/<c>http_bin</c> to + <c>httph</c>/<c>httph_bin</c> internally after the first line + has been read. There might be occasions however when they are + useful, such as parsing trailers from chunked encoding.</p> </item> </taglist> </item> diff --git a/lib/kernel/doc/src/inet_res.xml b/lib/kernel/doc/src/inet_res.xml index d8fe23544b..bf73ccf13d 100644 --- a/lib/kernel/doc/src/inet_res.xml +++ b/lib/kernel/doc/src/inet_res.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2009</year><year>2009</year> + <year>2009</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -76,64 +76,38 @@ query is tried for the <c>alt_nameservers</c>.</p> </section> - - - - <section> - <title>DATA TYPES</title> - <p>As defined in the module - <seealso marker="kernel:inet">inet</seealso>:</p> - <code type="none"> -hostent() = #hostent{} -posix() = some atom()s -ip_address() = tuple of integers of arity 4 or 8</code> - + <datatypes> <p>Resolver types:</p> - <code type="none">These correspond to resolver options: - -res_option() = - [ {alt_nameservers, [ nameserver() ]} - | {edns, 0 | false} % Use EDNS - | {inet6, bool()} % Return IPv6 addresses - | {nameservers, [ nameserver() ]} % List of nameservers - | {recurse, bool()} % Request server recursion - | {retry, integer()} % UDP retries - | {timeout, integer()} % UDP query timeout - | {udp_payload_size, integer()} % EDNS payload size - | {usevc, bool()} ] % Use TCP (Virtual Circuit) - -nameserver() = {ip_address(),Port} - Port = integer(1..65535) - -res_error() = - formerr | - qfmterror | - servfail | - nxdomain | - notimp | - refused | - badvers | - timeout -</code> - - <p>DNS types:</p> - <marker id="dns_types"/> - <code type="none">dns_name() = string() with no adjacent dots - -rr_type() = a | aaaa | cname | gid | hinfo | ns | mb | md | mg | mf - | minfo | mx | naptr | null | ptr | soa | spf | srv | txt - | uid | uinfo | unspec | wks - -query_type() = axfr | mailb | maila | any | rr_type() - -dns_class() = in | chaos | hs | any - + <datatype> + <name name="res_option"/> + </datatype> + <datatype> + <name name="nameserver"/> + </datatype> + <datatype> + <name name="res_error"/> + </datatype> + + <p><marker id="dns_types"/>DNS types:</p> + <datatype> + <name name="dns_name"/> + <desc><p>A string with no adjacent dots.</p></desc> + </datatype> + <datatype> + <name name="rr_type"/> + </datatype> + <datatype> + <name name="dns_class"/> + </datatype> + <datatype> + <name name="dns_msg"/> + <desc> + <p>This is the start of a hiearchy of opaque data structures + that can be examined with access functions in inet_dns that + return lists of {Field,Value} tuples. The arity 2 functions + just return the value for a given field. +<pre> dns_msg() = DnsMsg - This is the start of a hiearchy of opaque data structures - that can be examined with access functions in inet_dns - that return lists of {Field,Value} tuples. The arity 2 - functions just return the value for a given field. - inet_dns:msg(DnsMsg) -> [ {header, dns_header()} | {qdlist, dns_query()} @@ -143,19 +117,21 @@ dns_msg() = DnsMsg inet_dns:msg(DnsMsg, header) -> dns_header() % for example inet_dns:msg(DnsMsg, Field) -> Value -dhs_header() = DnsHeader +dns_header() = DnsHeader inet_dns:header(DnsHeader) -> [ {id, integer()} - | {qr, bool()} + | {qr, boolean()} | {opcode, 'query' | iquery | status | integer()} - | {aa, bool()} - | {tc, bool()} - | {rd, bool()} - | {ra, bool()} - | {pr, bool()} + | {aa, boolean()} + | {tc, boolean()} + | {rd, boolean()} + | {ra, boolean()} + | {pr, boolean()} | {rcode, integer(0..16)} ] inet_dns:header(DnsHeader, Field) -> Value +query_type() = axfr | mailb | maila | any | rr_type() + dns_query() = DnsQuery inet_dns:dns_query(DnsQuery) -> [ {domain, dns_name()} @@ -179,32 +155,6 @@ dns_rr() = DnsRr | {data, dns_data()} ] inet_dns:rr(DnsRr, Field) -> Value -dns_data() = % for dns_type() - [ dns_name() % ns, md, mf, cname, mb, mg, mr, ptr - | ip_address(v4) % a - | ip_address(v6) % aaaa - | {MName,RName,Serial,Refresh,Retry,Expiry,Minimum} % soa - | {ip_address(v4),Proto,BitMap} % wks - | {CpuString,OsString} % hinfo - | {RM,EM} % minfo - | {Prio,dns_name()} % mx - | {Prio,Weight,Port,dns_name()} % srv - | {Order,Preference,Flags,Services,Regexp,dns_name()} % naptr - | [ string() ] % txt, spf - | binary() ] % null, integer() -MName, RName = dns_name() -Serial, Refresh, Retry, Expiry, Minimum = integer(), -Proto = integer() -BitMap = binary() -CpuString, OsString = string() -RM = EM = dns_name() -Prio, Weight, Port = integer() -Order, Preference = integer() -Flags, Services = string(), -Regexp = string(utf8) - - - There is an info function for the types above: inet_dns:record_type(dns_msg()) -> msg; @@ -214,26 +164,25 @@ inet_dns:record_type(dns_rr()) -> rr; inet_dns:record_type(_) -> undefined. So; inet_dns:(inet_dns:record_type(X))(X) will convert -any of these data structures into a {Field,Value} list.</code> - </section> - +any of these data structures into a {Field,Value} list.</pre></p> + </desc> + </datatype> + <datatype> + <name name="dns_data"/> + <desc><p><c><anno>Regexp</anno></c> is a string with characters encoded in the + UTF-8 coding standard.</p> + </desc> + </datatype> + </datatypes> <funcs> <func> - <name>getbyname(Name, Type) -> {ok,hostent()} | {error,Reason}</name> - <name>getbyname(Name, Type, Timeout) -> - {ok,hostent()} | {error,Reason} - </name> + <name name="getbyname" arity="2"/> + <name name="getbyname" arity="3"/> <fsummary>Resolve a DNS record of the given type for the given host </fsummary> - <type> - <v>Name = dns_name()</v> - <v>Type = rr_type()</v> - <v>Timeout = integer() >= 0 | infinity</v> - <v>Reason = posix() | res_error()</v> - </type> <desc> <p>Resolve a DNS record of the given type for the given host, of class <c>in</c>. On success returns a <c>hostent()</c> record with @@ -252,17 +201,10 @@ any of these data structures into a {Field,Value} list.</code> </func> <func> - <name>gethostbyaddr(Address) -> {ok,hostent()} | {error,Reason}</name> - <name>gethostbyaddr(Address, Timeout) -> - {ok,hostent()} | {error,Reason} - </name> + <name name="gethostbyaddr" arity="1"/> + <name name="gethostbyaddr" arity="2"/> <fsummary>Return a hostent record for the host with the given address </fsummary> - <type> - <v>Address = ip_address()</v> - <v>Timeout = integer() >= 0 | infinity</v> - <v>Reason = posix() | res_error()</v> - </type> <desc> <p>Backend functions used by <seealso marker="kernel:inet#gethostbyaddr/1"> @@ -273,20 +215,11 @@ any of these data structures into a {Field,Value} list.</code> </func> <func> - <name>gethostbyname(Name) -> {ok,hostent()} | Reason}</name> - <name>gethostbyname(Name, Family) -> - {ok,hostent()} | {error,Reason}} - </name> - <name>gethostbyname(Name, Family, Timeout) -> - {ok,hostent()} | {error,Reason} - </name> + <name name="gethostbyname" arity="1"/> + <name name="gethostbyname" arity="2"/> + <name name="gethostbyname" arity="3"/> <fsummary>Return a hostent record for the host with the given name </fsummary> - <type> - <v>Name = dns_name()</v> - <v>Timeout = integer() >= 0 | infinity</v> - <v>Reason = posix() | res_error()</v> - </type> <desc> <p>Backend functions used by <seealso marker="kernel:inet#gethostbyname/1"> @@ -305,26 +238,16 @@ any of these data structures into a {Field,Value} list.</code> </func> <func> - <name>lookup(Name, Class, Type) -> [ dns_data() ] - </name> - <name>lookup(Name, Class, Type, Opts) -> [ dns_data() ] - </name> - <name>lookup(Name, Class, Type, Opts, Timeout) -> [ dns_data() ] - </name> + <name name="lookup" arity="3"/> + <name name="lookup" arity="4"/> + <name name="lookup" arity="5"/> <fsummary>Resolve the DNS data for the record of the given type and class for the given name </fsummary> - <type> - <v>Name = dns_name() | ip_address()</v> - <v>Type = rr_type()</v> - <v>Opts = res_option() | verbose</v> - <v>Timeout = integer() >= 0 | infinity</v> - <v>Reason = posix() | res_error()</v> - </type> <desc> <p>Resolve the DNS data for the record of the given type and class for the given name. On success filters out the answer records - with the correct <c>Class</c> and <c>Type</c> and returns + with the correct <c><anno>Class</anno></c> and <c><anno>Type</anno></c> and returns a list of their data fields. So a lookup for type <c>any</c> will give an empty answer since the answer records have specific types that are not <c>any</c>. An empty answer @@ -332,44 +255,33 @@ any of these data structures into a {Field,Value} list.</code> </p><p> Calls <seealso marker="#resolve/3">resolve/2..4</seealso> with the same arguments and filters the result, so - <c>Opts</c> is explained there. + <c><anno>Opts</anno></c> is explained there. </p> </desc> </func> <func> - <name>resolve(Name, Class, Type) -> {ok,dns_msg()} | Error - </name> - <name>resolve(Name, Class, Type, Opts) -> {ok,dns_msg()} | Error - </name> - <name>resolve(Name, Class, Type, Opts, Timeout) -> {ok,dns_msg()} | Error - </name> + <name name="resolve" arity="3"/> + <name name="resolve" arity="4"/> + <name name="resolve" arity="5"/> <fsummary>Resolve a DNS record of the given type and class for the given name </fsummary> - <type> - <v>Name = dns_name() | ip_address()</v> - <v>Type = rr_type()</v> - <v>Opts = res_option() | verbose | atom()</v> - <v>Timeout = integer() >= 0 | infinity</v> - <v>Error = {error,Reason} | {error,{Reason,dns_msg()}}</v> - <v>Reason = posix() | res_error()</v> - </type> <desc> <p>Resolve a DNS record of the given type and class for the given name. The returned <c>dns_msg()</c> can be examined using access functions in <c>inet_db</c> as described in <seealso marker="#dns_types">DNS types</seealso>. </p><p> - If <c>Name</c> is an <c>ip_address()</c>, the domain name + If <c><anno>Name</anno></c> is an <c>ip_address()</c>, the domain name to query for is generated as the standard reverse ".IN-ADDR.ARPA." name for an IPv4 address, or the ".IP6.ARPA." name for an IPv6 address. In this case you most probably want to use - <c>Class = in</c> and <c>Type = ptr</c> but it + <c><anno>Class</anno> = in</c> and <c><anno>Type</anno> = ptr</c> but it is not done automatically. </p><p> - <c>Opts</c> override the corresponding resolver options. + <c><anno>Opts</anno></c> override the corresponding resolver options. If the option <c>nameservers</c> is given, it is also assumed that it is the complete list of nameserves, so the resolver option <c>alt_nameserves</c> is ignored. @@ -382,14 +294,14 @@ any of these data structures into a {Field,Value} list.</code> of queries, replies retransmissions, etc, similar to from utilities like <c>dig</c>, <c>nslookup</c> et.al. </p><p> - If <c>Opt</c> is an arbitrary atom it is interpreted - as <c>{Opt,true}</c> unless the atom string starts with - <c>"no"</c> making the interpretation <c>{Opt,false}</c>. + If <c><anno>Opt</anno></c> is an arbitrary atom it is interpreted + as <c>{<anno>Opt</anno>,true}</c> unless the atom string starts with + <c>"no"</c> making the interpretation <c>{<anno>Opt</anno>,false}</c>. For example: <c>usevc</c> is an alias for <c>{usevc,true}</c>, and <c>nousevc</c> an alias for <c>{usevc,false}</c>. </p><p> The <c>inet6</c> option currently has no effect on this function. - You probably want to use <c>Type = a | aaaa</c> instead. + You probably want to use <c><anno>Type</anno> = a | aaaa</c> instead. </p> </desc> </func> @@ -430,24 +342,18 @@ any of these data structures into a {Field,Value} list.</code> <funcs> <func> - <name>nslookup(Name, Class, Type) -> {ok,dns_msg()} | {error,Reason} - </name> - <name>nslookup(Name, Class, Type, Timeout) -> - {ok,dns_msg()} | {error,Reason} - </name> - <name>nslookup(Name, Class, Type, Nameservers) -> - {ok,dns_msg()} | {error,Reason} - </name> + <name name="nslookup" arity="3"/> + <name name="nslookup" arity="4" clause_i="1"/> + <name name="nslookup" arity="4" clause_i="2"/> <fsummary>Resolve a DNS record of the given type and class for the given name </fsummary> - <type> - <v>Name = dns_name() | ip_address()</v> - <v>Type = rr_type()</v> - <v>Nameservers = [ nameserver() ]</v> - <v>Timeout = integer() >= 0 | infinity</v> - <v>Reason = posix() | res_error()</v> - </type> + <type variable="Name"/> + <type variable="Class"/> + <type variable="Type"/> + <type variable="Timeout" name_i="2"/> + <type variable="Nameservers"/> + <type variable="Reason"/> <desc> <p>Resolve a DNS record of the given type and class for the given name. </p> @@ -455,22 +361,11 @@ any of these data structures into a {Field,Value} list.</code> </func> <func> - <name>nnslookup(Name, Class, Type, Nameservers) -> - {ok,dns_msg()} | {error,posix()} - </name> - <name>nnslookup(Name, Class, Type, Nameservers, Timeout) -> - {ok,dns_msg()} | {error,posix()} - </name> + <name name="nnslookup" arity="4"/> + <name name="nnslookup" arity="5"/> <fsummary>Resolve a DNS record of the given type and class for the given name </fsummary> - <type> - <v>Name = dns_name() | ip_address()</v> - <v>Type = rr_type()</v> - <v>Nameservers = [ nameserver() ]</v> - <v>Timeout = integer() >= 0 | infinity</v> - <v>Reason = posix() | res_error()</v> - </type> <desc> <p>Resolve a DNS record of the given type and class for the given name. </p> diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml index bf513b7815..0f71a4f0f2 100644 --- a/lib/kernel/doc/src/kernel_app.xml +++ b/lib/kernel/doc/src/kernel_app.xml @@ -4,7 +4,7 @@ <appref> <header> <copyright> - <year>1996</year><year>2009</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -231,6 +231,15 @@ MaxT = TickTime + TickTime / 4</code> <p><em>Note:</em> Normally, a terminating node is detected immediately.</p> </item> + <tag><c>shutdown_timeout = integer() | infinity</c></tag> + <item> + <p>Specifies the time <c>application_controller</c> will wait + for an application to terminate during node shutdown. If the + timer expires, <c>application_controller</c> will brutally + kill <c>application_master</c> of the hanging + application. If this parameter is undefined, it defaults + to <c>infinity</c>.</p> + </item> <tag><c>sync_nodes_mandatory = [NodeName]</c></tag> <item> <p>Specifies which other nodes <em>must</em> be alive in order diff --git a/lib/kernel/doc/src/make.dep b/lib/kernel/doc/src/make.dep deleted file mode 100644 index f79d1c6367..0000000000 --- a/lib/kernel/doc/src/make.dep +++ /dev/null @@ -1,28 +0,0 @@ -# ---------------------------------------------------- -# >>>> Do not edit this file <<<< -# This file was automaticly generated by -# /home/otp/bin/docdepend -# ---------------------------------------------------- - - -# ---------------------------------------------------- -# TeX files that the DVI file depend on -# ---------------------------------------------------- - -book.dvi: app.tex application.tex auth.tex book.tex \ - code.tex config.tex disk_log.tex erl_boot_server.tex \ - erl_ddll.tex erl_prim_loader_stub.tex erlang_stub.tex \ - error_handler.tex error_logger.tex file.tex \ - gen_sctp.tex gen_tcp.tex gen_udp.tex global.tex \ - global_group.tex heart.tex inet.tex inet_res.tex \ - init_stub.tex kernel_app.tex net_adm.tex net_kernel.tex \ - os.tex packages.tex pg2.tex ref_man.tex rpc.tex \ - seq_trace.tex user.tex wrap_log_reader.tex \ - zlib_stub.tex - -# ---------------------------------------------------- -# Source inlined when transforming from source to LaTeX -# ---------------------------------------------------- - -book.tex: ref_man.xml - diff --git a/lib/kernel/doc/src/net_adm.xml b/lib/kernel/doc/src/net_adm.xml index 7ec4f7f0e7..f2aac9282c 100644 --- a/lib/kernel/doc/src/net_adm.xml +++ b/lib/kernel/doc/src/net_adm.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2009</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -34,94 +34,70 @@ </description> <funcs> <func> - <name>dns_hostname(Host) -> {ok, Name} | {error, Host}</name> + <name name="dns_hostname" arity="1"/> <fsummary>Official name of a host</fsummary> - <type> - <v>Host = atom() | string()</v> - <v>Name = string()</v> - </type> <desc> - <p>Returns the official name of <c>Host</c>, or - <c>{error, Host}</c> if no such name is found. See also + <p>Returns the official name of <c><anno>Host</anno></c>, or + <c>{error, <anno>Host</anno>}</c> if no such name is found. See also <c>inet(3)</c>.</p> </desc> </func> <func> - <name>host_file() -> Hosts | {error, Reason}</name> + <name name="host_file" arity="0"/> <fsummary>Read the <c>.hosts.erlang</c>file</fsummary> - <type> - <v>Hosts = [Host]</v> - <v> Host = atom()</v> - <v>Reason = term()</v> - </type> <desc> <p>Reads the <c>.hosts.erlang</c> file, see the section <em>Files</em> below. Returns the hosts in this file as a - list, or returns <c>{error, Reason}</c> if the file could not - be read. See <c>file(3)</c> for possible values of - <c>Reason</c>.</p> + list, or returns <c>{error, <anno>Reason</anno>}</c> if the file could not + be read or the Erlang terms on the file could not be interpreted.</p> </desc> </func> <func> - <name>localhost() -> Name</name> + <name name="localhost" arity="0"/> <fsummary>Name of the local host</fsummary> - <type> - <v>Name = string()</v> - </type> <desc> <p>Returns the name of the local host. If Erlang was started - with the <c>-name</c> command line flag, <c>Name</c> is + with the <c>-name</c> command line flag, <c><anno>Name</anno></c> is the fully qualified name.</p> </desc> </func> <func> - <name>names() -> {ok, [{Name, Port}]} | {error, Reason}</name> - <name>names(Host) -> {ok, [{Name, Port}]} | {error, Reason}</name> + <name name="names" arity="0"/> + <name name="names" arity="1"/> <fsummary>Names of Erlang nodes at a host</fsummary> - <type> - <v>Name = string()</v> - <v>Port = int()</v> - <v>Reason = address | term()</v> - </type> <desc> <p>Similar to <c>epmd -names</c>, see <c>epmd(1)</c>. - <c>Host</c> defaults to the local host. Returns the names and + <c><anno>Host</anno></c> defaults to the local host. Returns the names and associated port numbers of the Erlang nodes that <c>epmd</c> at the specified host has registered.</p> <p>Returns <c>{error, address}</c> if <c>epmd</c> is not - running. See <c>inet(3)</c> for other possible values of - <c>Reason</c>.</p> + running.</p> <pre> (arne@dunn)1> <input>net_adm:names().</input> {ok,[{"arne",40262}]}</pre> </desc> </func> <func> - <name>ping(Node) -> pong | pang</name> + <name name="ping" arity="1"/> <fsummary>Set up a connection to a node</fsummary> - <type> - <v>Node = node()</v> - </type> <desc> - <p>Tries to set up a connection to <c>Node</c>. Returns + <p>Tries to set up a connection to <c><anno>Node</anno></c>. Returns <c>pang</c> if it fails, or <c>pong</c> if it is successful.</p> </desc> </func> <func> - <name>world() -> [node()]</name> - <name>world(Arg) -> [node()]</name> + <name name="world" arity="0"/> + <name name="world" arity="1"/> + <type name="verbosity"/> <fsummary>Lookup and connect to all nodes at all hosts in <c>.hosts.erlang</c></fsummary> - <type> - <v>Arg = silent | verbose</v> - </type> <desc> <p>This function calls <c>names(Host)</c> for all hosts which are specified in the Erlang host file <c>.hosts.erlang</c>, collects the replies and then evaluates <c>ping(Node)</c> on all those nodes. Returns the list of all nodes that were, successfully pinged.</p> - <p><c>Arg</c> defaults to <c>silent</c>. - If <c>Arg == verbose</c>, the function writes information about which + <p><c><anno>Arg</anno></c> defaults to <c>silent</c>. + If <c><anno>Arg</anno> == verbose</c>, the function writes information about which nodes it is pinging to stdout.</p> <p>This function can be useful when a node is started, and the names of the other nodes in the network are not initially @@ -131,14 +107,10 @@ </desc> </func> <func> - <name>world_list(Hosts) -> [node()]</name> - <name>world_list(Hosts, Arg) -> [node()]</name> + <name name="world_list" arity="1"/> + <name name="world_list" arity="2"/> + <type name="verbosity"/> <fsummary>Lookup and connect to all nodes at specified hosts</fsummary> - <type> - <v>Hosts = [Host]</v> - <v> Host = atom()</v> - <v>Arg = silent | verbose</v> - </type> <desc> <p>As <c>world/0,1</c>, but the hosts are given as argument instead of being read from <c>.hosts.erlang</c>.</p> diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml index a18226e779..e54a427ff0 100644 --- a/lib/kernel/doc/src/net_kernel.xml +++ b/lib/kernel/doc/src/net_kernel.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2009</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -37,13 +37,10 @@ monitoring of the network.</p> <p>An Erlang node is started using the command line flag <c>-name</c> or <c>-sname</c>:</p> - <pre> -$ <input>erl -sname foobar</input></pre> +<pre>$ <input>erl -sname foobar</input></pre> <p>It is also possible to call <c>net_kernel:start([foobar])</c> directly from the normal Erlang shell prompt:</p> - <p></p> - <pre> -1> <input>net_kernel:start([foobar, shortnames]).</input> +<pre>1> <input>net_kernel:start([foobar, shortnames]).</input> {ok,<0.64.0>} (foobar@gringotts)2></pre> <p>If the node is started with the command line flag <c>-sname</c>, @@ -64,50 +61,38 @@ $ <input>erl -sname foobar</input></pre> </description> <funcs> <func> - <name>allow(Nodes) -> ok | error</name> + <name name="allow" arity="1"/> <fsummary>Limit access to a specified set of nodes</fsummary> - <type> - <v>Nodes = [node()]</v> - </type> <desc> <p>Limits access to the specified set of nodes. Any access - attempts made from (or to) nodes not in <c>Nodes</c> will be + attempts made from (or to) nodes not in <c><anno>Nodes</anno></c> will be rejected.</p> - <p>Returns <c>error</c> if any element in <c>Nodes</c> is not + <p>Returns <c>error</c> if any element in <c><anno>Nodes</anno></c> is not an atom.</p> </desc> </func> <func> - <name>connect_node(Node) -> true | false | ignored</name> + <name name="connect_node" arity="1"/> <fsummary>Establish a connection to a node</fsummary> - <type> - <v>Node = node()</v> - </type> <desc> - <p>Establishes a connection to <c>Node</c>. Returns <c>true</c> + <p>Establishes a connection to <c><anno>Node</anno></c>. Returns <c>true</c> if successful, <c>false</c> if not, and <c>ignored</c> if the local node is not alive.</p> </desc> </func> <func> - <name>monitor_nodes(Flag) -> ok | Error</name> - <name>monitor_nodes(Flag, Options) -> ok | Error</name> + <name name="monitor_nodes" arity="1"/> + <name name="monitor_nodes" arity="2"/> <fsummary>Subscribe to node status change messages</fsummary> - <type> - <v>Flag = true | false</v> - <v>Options = [Option]</v> - <v> Option -- see below</v> - <v>Error = error | {error, term()}</v> - </type> <desc> <p>The calling process subscribes or unsubscribes to node status change messages. A <c>nodeup</c> message is delivered to all subscribing process when a new node is connected, and a <c>nodedown</c> message is delivered when a node is disconnected.</p> - <p>If <c>Flag</c> is <c>true</c>, a new subscription is started. - If <c>Flag</c> is <c>false</c>, all previous subscriptions -- - started with the same <c>Options</c> -- are stopped. Two + <p>If <c><anno>Flag</anno></c> is <c>true</c>, a new subscription is started. + If <c><anno>Flag</anno></c> is <c>false</c>, all previous subscriptions -- + started with the same <c><anno>Options</anno></c> -- are stopped. Two option lists are considered the same if they contain the same set of options.</p> <p>As of <c>kernel</c> version 2.11.4, and <c>erts</c> version @@ -139,23 +124,23 @@ $ <input>erl -sname foobar</input></pre> <p>Note, that this is <em>not</em> guaranteed for <c>kernel</c> versions before 2.13.</p> <p>The format of the node status change messages depends on - <c>Options</c>. If <c>Options</c> is [], which is the default, + <c><anno>Options</anno></c>. If <c><anno>Options</anno></c> is [], which is the default, the format is:</p> <code type="none"> {nodeup, Node} | {nodedown, Node} Node = node()</code> - <p>If <c>Options /= []</c>, the format is:</p> + <p>If <c><anno>Options</anno> /= []</c>, the format is:</p> <code type="none"> {nodeup, Node, InfoList} | {nodedown, Node, InfoList} Node = node() InfoList = [{Tag, Val}]</code> <p><c>InfoList</c> is a list of tuples. Its contents depends on - <c>Options</c>, see below.</p> + <c><anno>Options</anno></c>, see below.</p> <p>Also, when <c>OptionList == []</c> only visible nodes, that is, nodes that appear in the result of <seealso marker="erts:erlang#nodes/0">nodes/0</seealso>, are monitored.</p> - <p><c>Option</c> can be any of the following:</p> + <p><c><anno>Option</anno></c> can be any of the following:</p> <taglist> <tag><c>{node_type, NodeType}</c></tag> <item> @@ -209,61 +194,54 @@ $ <input>erl -sname foobar</input></pre> </desc> </func> <func> - <name>get_net_ticktime() -> Res</name> + <name name="get_net_ticktime" arity="0"/> <fsummary>Get <c>net_ticktime</c></fsummary> - <type> - <v>Res = NetTicktime | {ongoing_change_to, NetTicktime}</v> - <v> NetTicktime = int()</v> - </type> <desc> <p>Gets <c>net_ticktime</c> (see <seealso marker="kernel_app">kernel(6)</seealso>).</p> - <p>Currently defined return values (<c>Res</c>):</p> + <p>Currently defined return values (<c><anno>Res</anno></c>):</p> <taglist> - <tag><c>NetTicktime</c></tag> + <tag><c><anno>NetTicktime</anno></c></tag> <item> - <p><c>net_ticktime</c> is <c>NetTicktime</c> seconds.</p> + <p><c>net_ticktime</c> is <c><anno>NetTicktime</anno></c> seconds.</p> </item> - <tag><c>{ongoing_change_to, NetTicktime}</c></tag> + <tag><c>{ongoing_change_to, <anno>NetTicktime</anno>}</c></tag> <item> <p><c>net_kernel</c> is currently changing - <c>net_ticktime</c> to <c>NetTicktime</c> seconds.</p> + <c>net_ticktime</c> to <c><anno>NetTicktime</anno></c> seconds.</p> + </item> + <tag><c>ignored</c></tag> + <item> + <p>The local node is not alive.</p> </item> </taglist> </desc> </func> <func> - <name>set_net_ticktime(NetTicktime) -> Res</name> - <name>set_net_ticktime(NetTicktime, TransitionPeriod) -> Res</name> + <name name="set_net_ticktime" arity="1"/> + <name name="set_net_ticktime" arity="2"/> <fsummary>Set <c>net_ticktime</c></fsummary> - <type> - <v>NetTicktime = int() > 0</v> - <v>TransitionPeriod = int() >= 0</v> - <v>Res = unchanged | change_initiated | {ongoing_change_to, NewNetTicktime}</v> - <v> NewNetTicktime = int() > 0</v> - </type> <desc> <p>Sets <c>net_ticktime</c> (see <seealso marker="kernel_app">kernel(6)</seealso>) to - <c>NetTicktime</c> seconds. <c>TransitionPeriod</c> defaults + <c><anno>NetTicktime</anno></c> seconds. <c><anno>TransitionPeriod</anno></c> defaults to 60.</p> <p>Some definitions:</p> - <p></p> <taglist> <tag>The minimum transition traffic interval (<c>MTTI</c>)</tag> <item> - <p><c>minimum(NetTicktime, PreviousNetTicktime)*1000 div 4</c> milliseconds.</p> + <p><c>minimum(<anno>NetTicktime</anno>, PreviousNetTicktime)*1000 div 4</c> milliseconds.</p> </item> <tag>The transition period</tag> <item> <p>The time of the least number of consecutive <c>MTTI</c>s - to cover <c>TransitionPeriod</c> seconds following + to cover <c><anno>TransitionPeriod</anno></c> seconds following the call to <c>set_net_ticktime/2</c> (i.e. - ((<c>TransitionPeriod*1000 - 1) div MTTI + 1)*MTTI</c> + ((<c><anno>TransitionPeriod</anno>*1000 - 1) div MTTI + 1)*MTTI</c> milliseconds).</p> </item> </taglist> - <p>If <c><![CDATA[NetTicktime < PreviousNetTicktime]]></c>, the actual + <p>If <c><![CDATA[<anno>NetTicktime</anno> < PreviousNetTicktime]]></c>, the actual <c>net_ticktime</c> change will be done at the end of the transition period; otherwise, at the beginning. During the transition period, <c>net_kernel</c> will ensure that @@ -271,7 +249,7 @@ $ <input>erl -sname foobar</input></pre> every <c>MTTI</c> millisecond.</p> <note> <p>The <c>net_ticktime</c> changes have to be initiated on all - nodes in the network (with the same <c>NetTicktime</c>) + nodes in the network (with the same <c><anno>NetTicktime</anno></c>) before the end of any transition period on any node; otherwise, connections may erroneously be disconnected.</p> </note> @@ -280,18 +258,18 @@ $ <input>erl -sname foobar</input></pre> <tag><c>unchanged</c></tag> <item> <p><c>net_ticktime</c> already had the value of - <c>NetTicktime</c> and was left unchanged.</p> + <c><anno>NetTicktime</anno></c> and was left unchanged.</p> </item> <tag><c>change_initiated</c></tag> <item> <p><c>net_kernel</c> has initiated the change of - <c>net_ticktime</c> to <c>NetTicktime</c> seconds.</p> + <c>net_ticktime</c> to <c><anno>NetTicktime</anno></c> seconds.</p> </item> - <tag><c>{ongoing_change_to, NewNetTicktime}</c></tag> + <tag><c>{ongoing_change_to, <anno>NewNetTicktime</anno>}</c></tag> <item> <p>The request was <em>ignored</em>; because, <c>net_kernel</c> was busy changing <c>net_ticktime</c> to - <c>NewTicktime</c> seconds.</p> + <c><anno>NewNetTicktime</anno></c> seconds.</p> </item> </taglist> </desc> @@ -315,7 +293,7 @@ $ <input>erl -sname foobar</input></pre> </desc> </func> <func> - <name>stop() -> ok | {error, not_allowed | not_found}</name> + <name name="stop" arity="0"/> <fsummary>Turn a node into a non-distributed Erlang runtime system</fsummary> <desc> <p>Turns a distributed node into a non-distributed node. For diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml index 065b24c53d..ec57b03bd9 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2010</year> + <year>2004</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -30,6 +30,127 @@ </header> <p>This document describes the changes made to the Kernel application.</p> +<section><title>Kernel 2.14.5</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix type of Packet arg of gen_tcp:send/2 and + gen_udp:send/4</p> + <p> + The type is marked as a binary() or a string() but in + practice it can be an iodata(). The test suite was + updated to confirm the gen_tcp/2 and gen_udp:send/4 + functions accept iodata() (iolists) packets. (Thanks to + Filipe David Manana)</p> + <p> + Own Id: OTP-9514</p> + </item> + <item> + <p> XML files have been corrected. </p> + <p> + Own Id: OTP-9550 Aux Id: OTP-9541 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> The types and specifications of the inet modules have + been improved. </p> + <p> + Own Id: OTP-9260</p> + </item> + <item> + <p> Types and specifications have been added. </p> + <p> + Own Id: OTP-9356</p> + </item> + <item> + <p> Contracts in STDLIB and Kernel have been improved and + type errors have been corrected. </p> + <p> + Own Id: OTP-9485</p> + </item> + <item> + <p> Update documentation and specifications of some of + the zlib functions. </p> + <p> + Own Id: OTP-9506</p> + </item> + </list> + </section> + +</section> + +<section><title>Kernel 2.14.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The send_timeout option in gen_tcp did not work properly + in active mode or with {active,once} options. This is now + corrected.</p> + <p> + Own Id: OTP-9145</p> + </item> + <item> + <p> + Fixed various typos across the documentation (Thanks to + Tuncer Ayaz)</p> + <p> + Own Id: OTP-9154</p> + </item> + <item> + <p> + Fix typo in doc of rpc:pmap/3 (Thanks to Ricardo + Catalinas Jim�nez)</p> + <p> + Own Id: OTP-9168</p> + </item> + <item> + <p> + A bug in inet_res, the specialized DNS resolver, has been + corrected. A late answer with unfortunate timing could + cause a runtime exception. Some code cleanup and + improvements also tagged along. Thanks to Evegeniy + Khramtsov for a pinpointing bug report and bug fix + testing.</p> + <p> + Own Id: OTP-9221 Aux Id: OTP-8712 </p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> Types and specifications have been added. </p> + <p> + Own Id: OTP-9268</p> + </item> + <item> + <p> Erlang types and specifications are used for + documentation. </p> + <p> + Own Id: OTP-9272</p> + </item> + <item> + <p> Two opaque types that could cause warnings when + running Dialyzer have been modified. </p> + <p> + Own Id: OTP-9337</p> + </item> + </list> + </section> + +</section> + <section><title>Kernel 2.14.3</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -2470,7 +2591,7 @@ <c>badarg</c> if a process is already registered. As it turns out there is no check in <c>global</c> if a process is registered under more than one name. If some process is - accidentaly or by design given several names, it is + accidentally or by design given several names, it is possible that the name registry becomes inconsistent due to the way the resolve function is called when name clashes are discovered (see <c>register_name/3</c> in diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml index 2c9cc33eb7..e94119845a 100644 --- a/lib/kernel/doc/src/os.xml +++ b/lib/kernel/doc/src/os.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -38,13 +38,10 @@ </description> <funcs> <func> - <name>cmd(Command) -> string()</name> + <name name="cmd" arity="1"/> <fsummary>Execute a command in a shell of the target OS</fsummary> - <type> - <v>Command = string() | atom()</v> - </type> <desc> - <p>Executes <c>Command</c> in a command shell of the target OS, + <p>Executes <c><anno>Command</anno></c> in a command shell of the target OS, captures the standard output of the command and returns this result as a string. This function is a replacement of the previous <c>unix:cmd/1</c>; on a Unix platform they are @@ -60,23 +57,18 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </desc> </func> <func> - <name>find_executable(Name) -> Filename | false</name> - <name>find_executable(Name, Path) -> Filename | false</name> + <name name="find_executable" arity="1"/> + <name name="find_executable" arity="2"/> <fsummary>Absolute filename of a program</fsummary> - <type> - <v>Name = string()</v> - <v>Path = string()</v> - <v>Filename = string()</v> - </type> <desc> <p>These two functions look up an executable program given its name and a search path, in the same way as the underlying operating system. <c>find_executable/1</c> uses the current execution path (that is, the environment variable PATH on Unix and Windows).</p> - <p><c>Path</c>, if given, should conform to the syntax of + <p><c><anno>Path</anno></c>, if given, should conform to the syntax of execution paths on the operating system. The absolute - filename of the executable program <c>Name</c> is returned, + filename of the executable program <c><anno>Name</anno></c> is returned, or <c>false</c> if the program was not found.</p> </desc> </func> @@ -134,10 +126,11 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </desc> </func> <func> - <name>timestamp() -> {MegaSecs, Secs, MicroSecs}</name> + <name>timestamp() -> Timestamp</name> <fsummary>Returna a timestamp from the OS in the erlang:now/0 format</fsummary> <type> - <v>MegaSecs = Secs = MicroSecs = int()</v> + <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> @@ -165,19 +158,15 @@ format_utc_timestamp() -> </desc> </func> <func> - <name>type() -> {Osfamily, Osname} | Osfamily</name> + <name name="type" arity="0"/> <fsummary>Return the OS family and, in some cases, OS name of the current operating system</fsummary> - <type> - <v>Osfamily = win32 | unix | vxworks</v> - <v>Osname = atom()</v> - </type> <desc> - <p>Returns the <c>Osfamily</c> and, in some cases, <c>Osname</c> + <p>Returns the <c><anno>Osfamily</anno></c> and, in some cases, <c><anno>Osname</anno></c> of the current operating system.</p> - <p>On Unix, <c>Osname</c> will have same value as + <p>On Unix, <c><anno>Osname</anno></c> will have same value as <c>uname -s</c> returns, but in lower case. For example, on Solaris 1 and 2, it will be <c>sunos</c>.</p> - <p>In Windows, <c>Osname</c> will be either <c>nt</c> (on + <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> @@ -185,17 +174,13 @@ format_utc_timestamp() -> <p>Think twice before using this function. Use the <c>filename</c> module if you want to inspect or build file names in a portable way. - Avoid matching on the <c>Osname</c> atom.</p> + Avoid matching on the <c><anno>Osname</anno></c> atom.</p> </note> </desc> </func> <func> - <name>version() -> {Major, Minor, Release} | VersionString</name> + <name name="version" arity="0"/> <fsummary>Return the Operating System version</fsummary> - <type> - <v>Major = Minor = Release = integer()</v> - <v>VersionString = string()</v> - </type> <desc> <p>Returns the operating system version. On most systems, this function returns a tuple, but a string diff --git a/lib/kernel/doc/src/pg2.xml b/lib/kernel/doc/src/pg2.xml index 7463fd10f5..d26ff0fc6b 100644 --- a/lib/kernel/doc/src/pg2.xml +++ b/lib/kernel/doc/src/pg2.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -60,13 +60,16 @@ to avoid name clashes.</p> </warning> </description> + <datatypes> + <datatype> + <name name="name"/> + <desc><p>The name of a process group.</p></desc> + </datatype> + </datatypes> <funcs> <func> - <name>create(Name) -> void()</name> + <name name="create" arity="1"/> <fsummary>Create a new, empty process group</fsummary> - <type> - <v>Name = term()</v> - </type> <desc> <p>Creates a new, empty process group. The group is globally visible on all nodes. If the group exists, nothing happens. @@ -74,24 +77,16 @@ </desc> </func> <func> - <name>delete(Name) -> void()</name> + <name name="delete" arity="1"/> <fsummary>Delete a process group</fsummary> - <type> - <v>Name = term()</v> - </type> <desc> <p>Deletes a process group. </p> </desc> </func> <func> - <name>get_closest_pid(Name) -> Pid | {error, Reason}</name> + <name name="get_closest_pid" arity="1"/> <fsummary>Common dispatch function</fsummary> - <type> - <v>Name = term()</v> - <v>Pid = pid()</v> - <v>Reason = {no_process, Name} | {no_such_group, Name}</v> - </type> <desc> <p>This is a useful dispatch function which can be used from client functions. It returns a process on the local node, if @@ -100,13 +95,8 @@ </desc> </func> <func> - <name>get_members(Name) -> [Pid] | {error, Reason}</name> + <name name="get_members" arity="1"/> <fsummary>Return all processes in a group</fsummary> - <type> - <v>Name = term()</v> - <v>Pid = pid()</v> - <v>Reason = {no_such_group, Name}</v> - </type> <desc> <p>Returns all processes in the group <c>Name</c>. This function should be used from within a client function that @@ -115,13 +105,8 @@ </desc> </func> <func> - <name>get_local_members(Name) -> [Pid] | {error, Reason}</name> + <name name="get_local_members" arity="1"/> <fsummary>Return all local processes in a group</fsummary> - <type> - <v>Name = term()</v> - <v>Pid = pid()</v> - <v>Reason = {no_such_group, Name}</v> - </type> <desc> <p>Returns all processes running on the local node in the group <c>Name</c>. This function should to be used from @@ -131,13 +116,8 @@ </desc> </func> <func> - <name>join(Name, Pid) -> ok | {error, Reason}</name> + <name name="join" arity="2"/> <fsummary>Join a process to a group</fsummary> - <type> - <v>Name = term()</v> - <v>Pid = pid()</v> - <v>Reason = {no_such_group, Name}</v> - </type> <desc> <p>Joins the process <c>Pid</c> to the group <c>Name</c>. A process can join a group several times; it must then @@ -146,13 +126,8 @@ </desc> </func> <func> - <name>leave(Name, Pid) -> ok | {error, Reason}</name> + <name name="leave" arity="2"/> <fsummary>Make a process leave a group</fsummary> - <type> - <v>Name = term()</v> - <v>Pid = pid()</v> - <v>Reason = {no_such_group, Name}</v> - </type> <desc> <p>Makes the process <c>Pid</c> leave the group <c>Name</c>. If the process is not a member of the group, <c>ok</c> is @@ -161,24 +136,17 @@ </desc> </func> <func> - <name>which_groups() -> [Name]</name> + <name name="which_groups" arity="0"/> <fsummary>Return a list of all known groups</fsummary> - <type> - <v>Name = term()</v> - </type> <desc> <p>Returns a list of all known groups. </p> </desc> </func> <func> - <name>start()</name> - <name>start_link() -> {ok, Pid} | {error, Reason}</name> + <name name="start" arity="0"/> + <name name="start_link" arity="0"/> <fsummary>Start the pg2 server</fsummary> - <type> - <v>Pid = pid()</v> - <v>Reason = term()</v> - </type> <desc> <p>Starts the pg2 server. Normally, the server does not need to be started explicitly, as it is started dynamically if it diff --git a/lib/kernel/doc/src/rpc.xml b/lib/kernel/doc/src/rpc.xml index 2b81de170d..b01ff16c85 100644 --- a/lib/kernel/doc/src/rpc.xml +++ b/lib/kernel/doc/src/rpc.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2009</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -37,40 +37,34 @@ for collecting information on a remote node, or for running a function with some specific side effects on the remote node.</p> </description> + <datatypes> + <datatype> + <name name="key"/> + <desc> + <p>As returned by <seealso marker="#async_call/4"> + <c>async_call/4</c>.</seealso></p> + </desc> + </datatype> + </datatypes> <funcs> <func> - <name>call(Node, Module, Function, Args) -> Res | {badrpc, Reason}</name> + <name name="call" arity="4"/> <fsummary>Evaluate a function call on a node</fsummary> - <type> - <v>Node = node()</v> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - <v>Res = term()</v> - <v>Reason = term()</v> - </type> <desc> - <p>Evaluates <c>apply(Module, Function, Args)</c> on the node - <c>Node</c> and returns the corresponding value <c>Res</c>, or - <c>{badrpc, Reason}</c> if the call fails.</p> + <p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> on the node + <c><anno>Node</anno></c> and returns the corresponding value <c><anno>Res</anno></c>, or + <c>{badrpc, <anno>Reason</anno>}</c> if the call fails.</p> </desc> </func> <func> - <name>call(Node, Module, Function, Args, Timeout) -> Res | {badrpc, Reason}</name> + <name name="call" arity="5"/> <fsummary>Evaluate a function call on a node</fsummary> - <type> - <v>Node = node()</v> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - <v>Res = term()</v> - <v>Reason = timeout | term()</v> - <v>Timeout = int() | infinity</v> - </type> <desc> - <p>Evaluates <c>apply(Module, Function, Args)</c> on the node - <c>Node</c> and returns the corresponding value <c>Res</c>, or - <c>{badrpc, Reason}</c> if the call fails. <c>Timeout</c> is + <p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> on the node + <c><anno>Node</anno></c> and returns the corresponding value <c><anno>Res</anno></c>, or + <c>{badrpc, <anno>Reason</anno>}</c> if the call fails. <c><anno>Timeout</anno></c> is a timeout value in milliseconds. If the call times out, - <c>Reason</c> is <c>timeout</c>.</p> + <c><anno>Reason</anno></c> is <c>timeout</c>.</p> <p>If the reply arrives after the call times out, no message will contaminate the caller's message queue, since this function spawns off a middleman process to act as (a void) @@ -80,17 +74,10 @@ </desc> </func> <func> - <name>block_call(Node, Module, Function, Args) -> Res | {badrpc, Reason}</name> + <name name="block_call" arity="4"/> <fsummary>Evaluate a function call on a node in the RPC server's context</fsummary> - <type> - <v>Node = node()</v> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - <v>Res = term()</v> - <v>Reason = term()</v> - </type> <desc> - <p>Like <c>call/4</c>, but the RPC server at <c>Node</c> does + <p>Like <c>call/4</c>, but the RPC server at <c><anno>Node</anno></c> does not create a separate process to handle the call. Thus, this function can be used if the intention of the call is to block the RPC server from any other incoming requests until @@ -101,50 +88,31 @@ </desc> </func> <func> - <name>block_call(Node, Module, Function, Args, Timeout) -> Res | {badrpc, Reason}</name> + <name name="block_call" arity="5"/> <fsummary>Evaluate a function call on a node in the RPC server's context</fsummary> - <type> - <v>Node = node()</v> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - <v>Timeout = int() | infinity</v> - <v>Res = term()</v> - <v>Reason = term()</v> - </type> <desc> <p>Like <c>block_call/4</c>, but with a timeout value in the same manner as <c>call/5</c>.</p> </desc> </func> <func> - <name>async_call(Node, Module, Function, Args) -> Key</name> + <name name="async_call" arity="4"/> <fsummary>Evaluate a function call on a node, asynchronous version</fsummary> - <type> - <v>Node = node()</v> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - <v>Key -- see below</v> - </type> <desc> <p>Implements <em>call streams with promises</em>, a type of RPC which does not suspend the caller until the result is finished. Instead, a key is returned which can be used at a later stage to collect the value. The key can be viewed as a promise to deliver the answer.</p> - <p>In this case, the key <c>Key</c> is returned, which can be + <p>In this case, the key <c><anno>Key</anno></c> is returned, which can be used in a subsequent call to <c>yield/1</c> or <c>nb_yield/1,2</c> to retrieve the value of evaluating - <c>apply(Module, Function, Args)</c> on the node <c>Node</c>.</p> + <c>apply(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> on the node <c><anno>Node</anno></c>.</p> </desc> </func> <func> - <name>yield(Key) -> Res | {badrpc, Reason}</name> + <name name="yield" arity="1"/> <fsummary>Deliver the result of evaluating a function call on a node (blocking)</fsummary> - <type> - <v>Key -- see async_call/4</v> - <v>Res = term()</v> - <v>Reason = term()</v> - </type> <desc> <p>Returns the promised answer from a previous <c>async_call/4</c>. If the answer is available, it is @@ -153,87 +121,46 @@ </desc> </func> <func> - <name>nb_yield(Key) -> {value, Val} | timeout</name> + <name name="nb_yield" arity="1"/> <fsummary>Deliver the result of evaluating a function call on a node (non-blocking)</fsummary> - <type> - <v>Key -- see async_call/4</v> - <v>Val = Res | {badrpc, Reason}</v> - <v> Res = term()</v> - <v> Reason = term()</v> - </type> <desc> - <p>Equivalent to <c>nb_yield(Key, 0)</c>.</p> + <p>Equivalent to <c>nb_yield(<anno>Key</anno>, 0)</c>.</p> </desc> </func> <func> - <name>nb_yield(Key, Timeout) -> {value, Val} | timeout</name> + <name name="nb_yield" arity="2"/> <fsummary>Deliver the result of evaluating a function call on a node (non-blocking)</fsummary> - <type> - <v>Key -- see async_call/4</v> - <v>Timeout = int() | infinity</v> - <v>Val = Res | {badrpc, Reason}</v> - <v> Res = term()</v> - <v> Reason = term()</v> - </type> <desc> <p>This is a non-blocking version of <c>yield/1</c>. It returns - the tuple <c>{value, Val}</c> when the computation has - finished, or <c>timeout</c> when <c>Timeout</c> milliseconds + the tuple <c>{value, <anno>Val</anno>}</c> when the computation has + finished, or <c>timeout</c> when <c><anno>Timeout</anno></c> milliseconds has elapsed.</p> </desc> </func> <func> - <name>multicall(Module, Function, Args) -> {ResL, BadNodes}</name> + <name name="multicall" arity="3"/> <fsummary>Evaluate a function call on a number of nodes</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - <v>ResL = [term()]</v> - <v>BadNodes = [node()]</v> - </type> <desc> - <p>Equivalent to <c>multicall([node()|nodes()], Module, Function, Args, infinity)</c>.</p> + <p>Equivalent to <c>multicall([node()|nodes()], <anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>, infinity)</c>.</p> </desc> </func> <func> - <name>multicall(Nodes, Module, Function, Args) -> {ResL, BadNodes}</name> + <name name="multicall" arity="4" clause_i="1"/> <fsummary>Evaluate a function call on a number of nodes</fsummary> - <type> - <v>Nodes = [node()]</v> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - <v>ResL = [term()]</v> - <v>BadNodes = [node()]</v> - </type> <desc> - <p>Equivalent to <c>multicall(Nodes, Module, Function, Args, infinity)</c>.</p> + <p>Equivalent to <c>multicall(<anno>Nodes</anno>, <anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>, infinity)</c>.</p> </desc> </func> <func> - <name>multicall(Module, Function, Args, Timeout) -> {ResL, BadNodes}</name> + <name name="multicall" arity="4" clause_i="2"/> <fsummary>Evaluate a function call on a number of nodes</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - <v>Timeout = int() | infinity</v> - <v>ResL = [term()]</v> - <v>BadNodes = [node()]</v> - </type> <desc> - <p>Equivalent to <c>multicall([node()|nodes()], Module, Function, Args, Timeout)</c>.</p> + <p>Equivalent to <c>multicall([node()|nodes()], <anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>, <anno>Timeout</anno>)</c>.</p> </desc> </func> <func> - <name>multicall(Nodes, Module, Function, Args, Timeout) -> {ResL, BadNodes}</name> + <name name="multicall" arity="5"/> <fsummary>Evaluate a function call on a number of nodes</fsummary> - <type> - <v>Nodes = [node()]</v> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - <v>Timeout = int() | infinity</v> - <v>ResL = [term()]</v> - <v>BadNodes = [node()]</v> - </type> <desc> <p>In contrast to an RPC, a multicall is an RPC which is sent concurrently from one client to multiple servers. This is @@ -243,12 +170,12 @@ making a series of RPCs on all the nodes, but the multicall is faster as all the requests are sent at the same time and are collected one by one as they come back.</p> - <p>The function evaluates <c>apply(Module, Function, Args)</c> + <p>The function evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> on the specified nodes and collects the answers. It returns - <c>{ResL, Badnodes}</c>, where <c>Badnodes</c> is a list + <c>{<anno>ResL</anno>, <anno>BadNodes</anno>}</c>, where <c><anno>BadNodes</anno></c> is a list of the nodes that terminated or timed out during computation, - and <c>ResL</c> is a list of the return values. - <c>Timeout</c> is a time (integer) in milliseconds, or + and <c><anno>ResL</anno></c> is a list of the return values. + <c><anno>Timeout</anno></c> is a time (integer) in milliseconds, or <c>infinity</c>.</p> <p>The following example is useful when new object code is to be loaded on all nodes in the network, and also indicates @@ -264,93 +191,60 @@ </desc> </func> <func> - <name>cast(Node, Module, Function, Args) -> void()</name> + <name name="cast" arity="4"/> <fsummary>Run a function on a node ignoring the result</fsummary> - <type> - <v>Node = node()</v> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - </type> <desc> - <p>Evaluates <c>apply(Module, Function, Args)</c> on the node - <c>Node</c>. No response is delivered and the calling + <p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> on the node + <c><anno>Node</anno></c>. No response is delivered and the calling process is not suspended until the evaluation is complete, as is the case with <c>call/4,5</c>.</p> </desc> </func> <func> - <name>eval_everywhere(Module, Funtion, Args) -> void()</name> + <name name="eval_everywhere" arity="3"/> <fsummary>Run a function on all nodes, ignoring the result</fsummary> - <type> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - </type> <desc> - <p>Equivalent to <c>eval_everywhere([node()|nodes()], Module, Function, Args)</c>.</p> + <p>Equivalent to <c>eval_everywhere([node()|nodes()], <anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c>.</p> </desc> </func> <func> - <name>eval_everywhere(Nodes, Module, Function, Args) -> void()</name> + <name name="eval_everywhere" arity="4"/> <fsummary>Run a function on specific nodes, ignoring the result</fsummary> - <type> - <v>Nodes = [node()]</v> - <v>Module = Function = atom()</v> - <v>Args = [term()]</v> - </type> <desc> - <p>Evaluates <c>apply(Module, Function, Args)</c> on + <p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> on the specified nodes. No answers are collected.</p> </desc> </func> <func> - <name>abcast(Name, Msg) -> void()</name> + <name name="abcast" arity="2"/> <fsummary>Broadcast a message asynchronously to a registered process on all nodes</fsummary> - <type> - <v>Name = atom()</v> - <v>Msg = term()</v> - </type> <desc> - <p>Equivalent to <c>abcast([node()|nodes()], Name, Msg)</c>.</p> + <p>Equivalent to <c>abcast([node()|nodes()], <anno>Name</anno>, <anno>Msg</anno>)</c>.</p> </desc> </func> <func> - <name>abcast(Nodes, Name, Msg) -> void()</name> + <name name="abcast" arity="3"/> <fsummary>Broadcast a message asynchronously to a registered process on specific nodes</fsummary> - <type> - <v>Nodes = [node()]</v> - <v>Name = atom()</v> - <v>Msg = term()</v> - </type> <desc> - <p>Broadcasts the message <c>Msg</c> asynchronously to - the registered process <c>Name</c> on the specified nodes.</p> + <p>Broadcasts the message <c><anno>Msg</anno></c> asynchronously to + the registered process <c><anno>Name</anno></c> on the specified nodes.</p> </desc> </func> <func> - <name>sbcast(Name, Msg) -> {GoodNodes, BadNodes}</name> + <name name="sbcast" arity="2"/> <fsummary>Broadcast a message synchronously to a registered process on all nodes</fsummary> - <type> - <v>Name = atom()</v> - <v>Msg = term()</v> - <v>GoodNodes = BadNodes = [node()]</v> - </type> <desc> - <p>Equivalent to <c>sbcast([node()|nodes()], Name, Msg)</c>.</p> + <p>Equivalent to <c>sbcast([node()|nodes()], <anno>Name</anno>, <anno>Msg</anno>)</c>.</p> </desc> </func> <func> - <name>sbcast(Nodes, Name, Msg) -> {GoodNodes, BadNodes}</name> + <name name="sbcast" arity="3"/> <fsummary>Broadcast a message synchronously to a registered process on specific nodes</fsummary> - <type> - <v>Name = atom()</v> - <v>Msg = term()</v> - <v>Nodes = GoodNodes = BadNodes = [node()]</v> - </type> <desc> - <p>Broadcasts the message <c>Msg</c> synchronously to - the registered process <c>Name</c> on the specified nodes.</p> - <p>Returns <c>{GoodNodes, BadNodes}</c>, where <c>GoodNodes</c> - is the list of nodes which have <c>Name</c> as a registered + <p>Broadcasts the message <c><anno>Msg</anno></c> synchronously to + the registered process <c><anno>Name</anno></c> on the specified nodes.</p> + <p>Returns <c>{<anno>GoodNodes</anno>, <anno>BadNodes</anno>}</c>, where <c><anno>GoodNodes</anno></c> + is the list of nodes which have <c><anno>Name</anno></c> as a registered process.</p> <p>The function is synchronous in the sense that it is known that all servers have received the message when the call @@ -362,67 +256,46 @@ </desc> </func> <func> - <name>server_call(Node, Name, ReplyWrapper, Msg) -> Reply | {error, Reason}</name> + <name name="server_call" arity="4"/> <fsummary>Interact with a server on a node</fsummary> - <type> - <v>Node = node()</v> - <v>Name = atom()</v> - <v>ReplyWrapper = Msg = Reply = term()</v> - <v>Reason = term()</v> - </type> <desc> <p>This function can be used when interacting with a server - called <c>Name</c> at node <c>Node</c>. It is assumed that + called <c><anno>Name</anno></c> at node <c><anno>Node</anno></c>. It is assumed that the server receives messages in the format - <c>{From, Msg}</c> and replies using <c>From ! {ReplyWrapper, Node, Reply}</c>. This function makes such + <c>{From, <anno>Msg</anno>}</c> and replies using <c>From ! {<anno>ReplyWrapper</anno>, <anno>Node</anno>, <anno>Reply</anno>}</c>. This function makes such a server call and ensures that the entire call is packed into an atomic transaction which either succeeds or fails. It never hangs, unless the server itself hangs.</p> - <p>The function returns the answer <c>Reply</c> as produced by - the server <c>Name</c>, or <c>{error, Reason}</c>.</p> + <p>The function returns the answer <c><anno>Reply</anno></c> as produced by + the server <c><anno>Name</anno></c>, or <c>{error, <anno>Reason</anno>}</c>.</p> </desc> </func> <func> - <name>multi_server_call(Name, Msg) -> {Replies, BadNodes}</name> + <name name="multi_server_call" arity="2"/> <fsummary>Interact with the servers on a number of nodes</fsummary> - <type> - <v>Name = atom()</v> - <v>Msg = term()</v> - <v>Replies = [Reply]</v> - <v> Reply = term()</v> - <v>BadNodes = [node()]</v> - </type> <desc> - <p>Equivalent to <c>multi_server_call([node()|nodes()], Name, Msg)</c>.</p> + <p>Equivalent to <c>multi_server_call([node()|nodes()], <anno>Name</anno>, <anno>Msg</anno>)</c>.</p> </desc> </func> <func> - <name>multi_server_call(Nodes, Name, Msg) -> {Replies, BadNodes}</name> + <name name="multi_server_call" arity="3"/> <fsummary>Interact with the servers on a number of nodes</fsummary> - <type> - <v>Nodes = [node()]</v> - <v>Name = atom()</v> - <v>Msg = term()</v> - <v>Replies = [Reply]</v> - <v> Reply = term()</v> - <v>BadNodes = [node()]</v> - </type> <desc> <p>This function can be used when interacting with servers - called <c>Name</c> on the specified nodes. It is assumed that - the servers receive messages in the format <c>{From, Msg}</c> - and reply using <c>From ! {Name, Node, Reply}</c>, where + called <c><anno>Name</anno></c> on the specified nodes. It is assumed that + the servers receive messages in the format <c>{From, <anno>Msg</anno>}</c> + and reply using <c>From ! {<anno>Name</anno>, Node, <anno>Reply</anno>}</c>, where <c>Node</c> is the name of the node where the server is - located. The function returns <c>{Replies, Badnodes}</c>, - where <c>Replies</c> is a list of all <c>Reply</c> values and - <c>BadNodes</c> is a list of the nodes which did not exist, or + located. The function returns <c>{<anno>Replies</anno>, <anno>BadNodes</anno>}</c>, + where <c><anno>Replies</anno></c> is a list of all <c><anno>Reply</anno></c> values and + <c><anno>BadNodes</anno></c> is a list of the nodes which did not exist, or where the server did not exist, or where the server terminated before sending any reply.</p> </desc> </func> <func> - <name>safe_multi_server_call(Name, Msg) -> {Replies, BadNodes}</name> - <name>safe_multi_server_call(Nodes, Name, Msg) -> {Replies, BadNodes}</name> + <name name="safe_multi_server_call" arity="2"/> + <name name="safe_multi_server_call" arity="3"/> <fsummary>Interact with the servers on a number of nodes (deprecated)</fsummary> <desc> <warning> @@ -432,66 +305,47 @@ <p>In Erlang/OTP R6B and earlier releases, <c>multi_server_call/2,3</c> could not handle the case where the remote node exists, but there is no server called - <c>Name</c>. Instead this function had to be used. In + <c><anno>Name</anno></c>. Instead this function had to be used. In Erlang/OTP R7B and later releases, however, the functions are equivalent, except for this function being slightly slower.</p> </desc> </func> <func> - <name>parallel_eval(FuncCalls) -> ResL</name> + <name name="parallel_eval" arity="1"/> <fsummary>Evaluate several function calls on all nodes in parallel</fsummary> - <type> - <v>FuncCalls = [{Module, Function, Args}]</v> - <v> Module = Function = atom()</v> - <v> Args = [term()]</v> - <v>ResL = [term()]</v> - </type> <desc> - <p>For every tuple in <c>FuncCalls</c>, evaluates - <c>apply(Module, Function, Args)</c> on some node in + <p>For every tuple in <c><anno>FuncCalls</anno></c>, evaluates + <c>apply(<anno>Module</anno>, <anno>Function</anno>, <anno>Args</anno>)</c> on some node in the network. Returns the list of return values, in the same - order as in <c>FuncCalls</c>.</p> + order as in <c><anno>FuncCalls</anno></c>.</p> </desc> </func> <func> - <name>pmap({Module, Function}, ExtraArgs, List1) -> List2</name> + <name name="pmap" arity="3"/> <fsummary>Parallell evaluation of mapping a function over a list </fsummary> - <type> - <v>Module = Function = atom()</v> - <v>ExtraArgs = [term()]</v> - <v>List1 = [Elem]</v> - <v> Elem = term()</v> - <v>List2 = [term()]</v> - </type> <desc> - <p>Evaluates <c>apply(Module, Function, [Elem|ExtraArgs])</c>, - for every element <c>Elem</c> in <c>List1</c>, in parallel. + <p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, [<anno>Elem</anno>|<anno>ExtraArgs</anno>])</c>, + for every element <c><anno>Elem</anno></c> in <c><anno>List1</anno></c>, in parallel. Returns the list of return values, in the same order as in - <c>List1</c>.</p> + <c><anno>List1</anno></c>.</p> </desc> </func> <func> - <name>pinfo(Pid) -> [{Item, Info}] | undefined</name> + <name name="pinfo" arity="1"/> <fsummary>Information about a process</fsummary> - <type> - <v>Pid = pid()</v> - <v>Item, Info -- see erlang:process_info/1</v> - </type> <desc> <p>Location transparent version of the BIF - <c>process_info/1</c>.</p> + <seealso marker="erts:erlang#process_info/1"> + <c>process_info/1</c></seealso>.</p> </desc> </func> <func> - <name>pinfo(Pid, Item) -> {Item, Info} | undefined | []</name> + <name name="pinfo" arity="2"/> <fsummary>Information about a process</fsummary> - <type> - <v>Pid = pid()</v> - <v>Item, Info -- see erlang:process_info/1</v> - </type> <desc> <p>Location transparent version of the BIF - <c>process_info/2</c>.</p> + <seealso marker="erts:erlang#process_info/2"> + <c>process_info/2</c></seealso>.</p> </desc> </func> </funcs> diff --git a/lib/kernel/doc/src/seq_trace.xml b/lib/kernel/doc/src/seq_trace.xml index 6c043dd767..1ab955bd8a 100644 --- a/lib/kernel/doc/src/seq_trace.xml +++ b/lib/kernel/doc/src/seq_trace.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1998</year><year>2009</year> + <year>1998</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -47,17 +47,22 @@ from users.</p> </note> </description> + <datatypes> + <datatype> + <name name="token"/> + <desc> + <p>An opaque term (a tuple) representing a trace token.</p> + </desc> + </datatype> + </datatypes> <funcs> <func> - <name>set_token(Token) -> PreviousToken</name> + <name name="set_token" arity="1"/> <fsummary>Set the trace token</fsummary> - <type> - <v>Token = PreviousToken = term() | []</v> - </type> <desc> - <p>Sets the trace token for the calling process to <c>Token</c>. - If <c>Token == []</c> then tracing is disabled, otherwise - <c>Token</c> should be an Erlang term returned from + <p>Sets the trace token for the calling process to <c><anno>Token</anno></c>. + If <c><anno>Token</anno> == []</c> then tracing is disabled, otherwise + <c><anno>Token</anno></c> should be an Erlang term returned from <c>get_token/0</c> or <c>set_token/1</c>. <c>set_token/1</c> can be used to temporarily exclude message passing from the trace by setting the trace token to empty like this:</p> @@ -72,18 +77,16 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name>set_token(Component, Val) -> {Component, OldVal}</name> + <name name="set_token" arity="2"/> <fsummary>Set a component of the trace token</fsummary> - <type> - <v>Component = label | serial | Flag</v> - <v> Flag = send | 'receive' | print | timestamp </v> - <v>Val = OldVal -- see below</v> - </type> + <type name="component"/> + <type name="flag"/> + <type name="value"/> <desc> - <p>Sets the individual <c>Component</c> of the trace token to - <c>Val</c>. Returns the previous value of the component.</p> + <p>Sets the individual <c><anno>Component</anno></c> of the trace token to + <c><anno>Val</anno></c>. Returns the previous value of the component.</p> <taglist> - <tag><c>set_token(label, Int)</c></tag> + <tag><c>set_token(label, <anno>Integer</anno>)</c></tag> <item> <p>The <c>label</c> component is an integer which identifies all events belonging to the same sequential @@ -93,31 +96,31 @@ seq_trace:set_token(OldToken), % activate the trace token again </item> <tag><c>set_token(serial, SerialValue)</c></tag> <item> - <p><c>SerialValue = {Previous, Current}</c>. + <p><c>SerialValue = {<anno>Previous</anno>, <anno>Current</anno>}</c>. The <c>serial</c> component contains counters which enables the traced messages to be sorted, should never be set explicitly by the user as these counters are updated automatically. Default is <c>{0, 0}</c>.</p> </item> - <tag><c>set_token(send, Bool)</c></tag> + <tag><c>set_token(send, <anno>Bool</anno>)</c></tag> <item> <p>A trace token flag (<c>true | false</c>) which enables/disables tracing on message sending. Default is <c>false</c>.</p> </item> - <tag><c>set_token('receive', Bool)</c></tag> + <tag><c>set_token('receive', <anno>Bool</anno>)</c></tag> <item> <p>A trace token flag (<c>true | false</c>) which enables/disables tracing on message reception. Default is <c>false</c>.</p> </item> - <tag><c>set_token(print, Bool)</c></tag> + <tag><c>set_token(print, <anno>Bool</anno>)</c></tag> <item> <p>A trace token flag (<c>true | false</c>) which enables/disables tracing on explicit calls to <c>seq_trace:print/1</c>. Default is <c>false</c>.</p> </item> - <tag><c>set_token(timestamp, Bool)</c></tag> + <tag><c>set_token(timestamp, <anno>Bool</anno>)</c></tag> <item> <p>A trace token flag (<c>true | false</c>) which enables/disables a timestamp to be generated for each @@ -127,11 +130,8 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name>get_token() -> TraceToken</name> + <name name="get_token" arity="0"/> <fsummary>Return the value of the trace token</fsummary> - <type> - <v>TraceToken = term() | []</v> - </type> <desc> <p>Returns the value of the trace token for the calling process. If <c>[]</c> is returned, it means that tracing is not active. @@ -141,13 +141,11 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name>get_token(Component) -> {Component, Val}</name> + <name name="get_token" arity="1"/> <fsummary>Return the value of a trace token component</fsummary> - <type> - <v>Component = label | serial | Flag</v> - <v> Flag = send | 'receive' | print | timestamp </v> - <v>Val -- see set_token/2</v> - </type> + <type name="component"/> + <type name="flag"/> + <type name="value"/> <desc> <p>Returns the value of the trace token component <c>Component</c>. See @@ -156,33 +154,26 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name>print(TraceInfo) -> void()</name> + <name name="print" arity="1"/> <fsummary>Put the Erlang term <c>TraceInfo</c>into the sequential trace output</fsummary> - <type> - <v>TraceInfo = term()</v> - </type> <desc> - <p>Puts the Erlang term <c>TraceInfo</c> into the sequential + <p>Puts the Erlang term <c><anno>TraceInfo</anno></c> into the sequential trace output if the calling process currently is executing within a sequential trace and the <c>print</c> flag of the trace token is set.</p> </desc> </func> <func> - <name>print(Label, TraceInfo) -> void()</name> + <name name="print" arity="2"/> <fsummary>Put the Erlang term <c>TraceInfo</c>into the sequential trace output</fsummary> - <type> - <v>Label = int()</v> - <v>TraceInfo = term()</v> - </type> <desc> <p>Same as <c>print/1</c> with the additional condition that - <c>TraceInfo</c> is output only if <c>Label</c> is equal to + <c><anno>TraceInfo</anno></c> is output only if <c>Label</c> is equal to the label component of the trace token.</p> </desc> </func> <func> - <name>reset_trace() -> void()</name> + <name name="reset_trace" arity="0"/> <fsummary>Stop all sequential tracing on the local node</fsummary> <desc> <p>Sets the trace token to empty for all processes on the @@ -194,26 +185,22 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name>set_system_tracer(Tracer) -> OldTracer</name> + <name name="set_system_tracer" arity="1"/> <fsummary>Set the system tracer</fsummary> - <type> - <v>Tracer = OldTracer = pid() | port() | false</v> - </type> + <type name="tracer"/> <desc> <p>Sets the system tracer. The system tracer can be either a - process or port denoted by <c>Tracer</c>. Returns the previous + process or port denoted by <c><anno>Tracer</anno></c>. Returns the previous value (which can be <c>false</c> if no system tracer is active).</p> - <p>Failure: <c>{badarg, Info}}</c> if <c>Pid</c> is not an + <p>Failure: <c>{badarg, Info}}</c> if <c><anno>Pid</anno></c> is not an existing local pid.</p> </desc> </func> <func> - <name>get_system_tracer() -> Tracer</name> + <name name="get_system_tracer" arity="0"/> <fsummary>Return the pid() or port() of the current system tracer.</fsummary> - <type> - <v>Tracer = pid() | port() | false</v> - </type> + <type name="tracer"/> <desc> <p>Returns the pid or port identifier of the current system tracer or <c>false</c> if no system tracer is activated.</p> diff --git a/lib/kernel/doc/src/specs.xml b/lib/kernel/doc/src/specs.xml new file mode 100644 index 0000000000..b41addaa0c --- /dev/null +++ b/lib/kernel/doc/src/specs.xml @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="latin1" ?> +<specs xmlns:xi="http://www.w3.org/2001/XInclude"> + <xi:include href="../specs/specs_application.xml"/> + <xi:include href="../specs/specs_auth.xml"/> + <xi:include href="../specs/specs_code.xml"/> + <xi:include href="../specs/specs_disk_log.xml"/> + <xi:include href="../specs/specs_erl_boot_server.xml"/> + <xi:include href="../specs/specs_erl_ddll.xml"/> + <xi:include href="../specs/specs_erl_prim_loader_stub.xml"/> + <xi:include href="../specs/specs_erlang_stub.xml"/> + <xi:include href="../specs/specs_error_handler.xml"/> + <xi:include href="../specs/specs_error_logger.xml"/> + <xi:include href="../specs/specs_file.xml"/> + <xi:include href="../specs/specs_gen_tcp.xml"/> + <xi:include href="../specs/specs_gen_udp.xml"/> + <xi:include href="../specs/specs_gen_sctp.xml"/> + <xi:include href="../specs/specs_global.xml"/> + <xi:include href="../specs/specs_global_group.xml"/> + <xi:include href="../specs/specs_heart.xml"/> + <xi:include href="../specs/specs_inet.xml"/> + <xi:include href="../specs/specs_inet_res.xml"/> + <xi:include href="../specs/specs_init_stub.xml"/> + <xi:include href="../specs/specs_net_adm.xml"/> + <xi:include href="../specs/specs_net_kernel.xml"/> + <xi:include href="../specs/specs_os.xml"/> + <xi:include href="../specs/specs_pg2.xml"/> + <xi:include href="../specs/specs_rpc.xml"/> + <xi:include href="../specs/specs_seq_trace.xml"/> + <xi:include href="../specs/specs_user.xml"/> + <xi:include href="../specs/specs_wrap_log_reader.xml"/> + <xi:include href="../specs/specs_zlib_stub.xml"/> + <xi:include href="../specs/specs_packages.xml"/> +</specs> diff --git a/lib/kernel/doc/src/wrap_log_reader.xml b/lib/kernel/doc/src/wrap_log_reader.xml index 18664a029f..6cf480b532 100644 --- a/lib/kernel/doc/src/wrap_log_reader.xml +++ b/lib/kernel/doc/src/wrap_log_reader.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1998</year><year>2009</year> + <year>1998</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -50,18 +50,20 @@ the called node, it is entirely up to the user to be sure that all items are read. </p> </description> + <datatypes> + <datatype> + <name name="continuation"/> + <desc><p>Continuation returned by + <c>open/1,2</c> or <c>chunk/1,2</c>.</p> + </desc> + </datatype> + </datatypes> <funcs> <func> - <name>chunk(Continuation)</name> - <name>chunk(Continuation, N) -> {Continuation2, Terms} | {Continuation2, Terms, Badbytes} | {Continuation2, eof} | {error, Reason}</name> + <name name="chunk" arity="1"/> + <name name="chunk" arity="2"/> <fsummary>Read a chunk of objects written to a wrap log.</fsummary> - <type> - <v>Continuation = continuation()</v> - <v>N = int() > 0 | infinity</v> - <v>Continuation2 = continuation()</v> - <v>Terms= [term()]</v> - <v>Badbytes = integer()</v> - </type> + <type name="chunk_ret"/> <desc> <p>This function makes it possible to efficiently read the terms which have been appended to a log. It minimises disk @@ -70,29 +72,29 @@ <p>The first time <c>chunk</c> is called an initial continuation returned from the <c>open/1</c>, <c>open/2</c> must be provided. </p> - <p>When <c>chunk/3</c> is called, <c>N</c> controls the + <p>When <c>chunk/3</c> is called, <c><anno>N</anno></c> controls the maximum number of terms that are read from the log in each chunk. Default is <c>infinity</c>, which means that all the terms contained in the 8K chunk are read. If less than - <c>N</c> terms are returned, this does not necessarily mean + <c><anno>N</anno></c> terms are returned, this does not necessarily mean that end of file is reached. </p> <p>The <c>chunk</c> function returns a tuple - <c>{Continuation2, Terms}</c>, where <c>Terms</c> is a list - of terms found in the log. <c>Continuation2</c> is yet + <c>{<anno>Continuation2</anno>, <anno>Terms</anno>}</c>, where <c><anno>Terms</anno></c> is a list + of terms found in the log. <c><anno>Continuation2</anno></c> is yet another continuation which must be passed on into any subsequent calls to <c>chunk</c>. With a series of calls to <c>chunk</c> it is then possible to extract all terms from a log. </p> <p>The <c>chunk</c> function returns a tuple - <c>{Continuation2, Terms, Badbytes}</c> if the log is opened - in read only mode and the read chunk is corrupt. <c>Badbytes</c> + <c>{<anno>Continuation2</anno>, <anno>Terms</anno>, <anno>Badbytes</anno>}</c> if the log is opened + in read only mode and the read chunk is corrupt. <c><anno>Badbytes</anno></c> indicates the number of non-Erlang terms found in the chunk. Note also that the log is not repaired. </p> - <p><c>chunk</c> returns <c>{Continuation2, eof}</c> when the end of the log is - reached, and <c>{error, Reason}</c> if an error occurs. + <p><c>chunk</c> returns <c>{<anno>Continuation2</anno>, eof}</c> when the end of the log is + reached, and <c>{error, <anno>Reason</anno>}</c> if an error occurs. </p> <p>The returned continuation may or may not be valid in the next call to <c>chunk</c>. This is because the log may wrap and delete @@ -103,37 +105,29 @@ </desc> </func> <func> - <name>close(Continuation) -> ok </name> + <name name="close" arity="1"/> <fsummary>Close a log</fsummary> - <type> - <v>Continuation = continuation()</v> - </type> <desc> <p>This function closes a log file properly. </p> </desc> </func> <func> - <name>open(Filename) -> OpenRet</name> - <name>open(Filename, N) -> OpenRet</name> + <name name="open" arity="1"/> + <name name="open" arity="2"/> <fsummary>Open a log file</fsummary> - <type> - <v>File = string() | atom()</v> - <v>N = integer()</v> - <v>OpenRet = {ok, Continuation} | {error, Reason} </v> - <v>Continuation = continuation()</v> - </type> + <type name="open_ret"/> <desc> - <p><c>Filename</c> specifies the name of the file which is to be read. </p> - <p><c>N</c> specifies the index of the file which is to be read. - If <c>N</c> is omitted the whole wrap log file will be read; if it + <p><c><anno>Filename</anno></c> specifies the name of the file which is to be read. </p> + <p><c><anno>N</anno></c> specifies the index of the file which is to be read. + If <c><anno>N</anno></c> is omitted the whole wrap log file will be read; if it is specified only the specified index file will be read. </p> - <p>The <c>open</c> function returns <c>{ok, Continuation}</c> if the - log/index file was successfully opened. The <c>Continuation</c> + <p>The <c>open</c> function returns <c>{ok, <anno>Continuation</anno>}</c> if the + log/index file was successfully opened. The <c><anno>Continuation</anno></c> is to be used when chunking or closing the file. </p> - <p>The function returns <c>{error, Reason}</c> for all errors. + <p>The function returns <c>{error, <anno>Reason</anno>}</c> for all errors. </p> </desc> </func> diff --git a/lib/kernel/examples/uds_dist/c_src/uds_drv.c b/lib/kernel/examples/uds_dist/c_src/uds_drv.c index fb10a375f4..9327ab19dc 100644 --- a/lib/kernel/examples/uds_dist/c_src/uds_drv.c +++ b/lib/kernel/examples/uds_dist/c_src/uds_drv.c @@ -111,7 +111,7 @@ do { \ typedef enum { portTypeUnknown, /* An uninitialized port */ portTypeListener, /* A listening port/socket */ - portTypeAcceptor, /* An intermidiate stage when accepting + portTypeAcceptor, /* An intermediate stage when accepting on a listen port */ portTypeConnector, /* An intermediate stage when connecting */ portTypeCommand, /* A connected open port in command mode */ @@ -401,7 +401,7 @@ static void uds_finish(void) /* ** Protocol to control: ** 'C': Set port in command mode. -** 'I': Set port in intermidiate mode +** 'I': Set port in intermediate mode ** 'D': Set port in data mode ** 'N': Get identification number for listen port ** 'S': Get statistics @@ -1000,7 +1000,7 @@ static int ensure_dir(char *path) /* ** Try to open a lock file and lock the first byte write-only (advisory) -** return the file descriptor if succesful, otherwise -1 (<0). +** return the file descriptor if successful, otherwise -1 (<0). */ static int try_lock(char *sockname, Byte *p_creation) { diff --git a/lib/kernel/src/dist.hrl b/lib/kernel/include/dist.hrl index aea1ab81ba..aea1ab81ba 100644 --- a/lib/kernel/src/dist.hrl +++ b/lib/kernel/include/dist.hrl diff --git a/lib/kernel/src/dist_util.hrl b/lib/kernel/include/dist_util.hrl index f2b0598532..f2b0598532 100644 --- a/lib/kernel/src/dist_util.hrl +++ b/lib/kernel/include/dist_util.hrl diff --git a/lib/kernel/include/inet.hrl b/lib/kernel/include/inet.hrl index 929b2ee294..3e64d4bb79 100644 --- a/lib/kernel/include/inet.hrl +++ b/lib/kernel/include/inet.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -19,18 +19,11 @@ %% This record is returned by inet:gethostbyaddr/2 and inet:gethostbyname/2. --type hostname() :: atom() | string(). --type ip4_address() :: {0..255,0..255,0..255,0..255}. --type ip6_address() :: {0..65535,0..65535,0..65535,0..65535, - 0..65535,0..65535,0..65535,0..65535}. --type ip_address() :: ip4_address() | ip6_address(). --type ip_port() :: 0..65535. - -record(hostent, { - h_name :: hostname(), %% offical name of host - h_aliases = [] :: [hostname()], %% alias list + h_name :: inet:hostname(), %% offical name of host + h_aliases = [] :: [inet:hostname()], %% alias list h_addrtype :: 'inet' | 'inet6', %% host address type h_length :: non_neg_integer(), %% length of address - h_addr_list = [] :: [ip_address()] %% list of addresses from name server + h_addr_list = [] :: [inet:ip_address()]%% list of addresses from name server }). diff --git a/lib/kernel/src/net_address.hrl b/lib/kernel/include/net_address.hrl index 5342076507..5342076507 100644 --- a/lib/kernel/src/net_address.hrl +++ b/lib/kernel/include/net_address.hrl diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile index 9db6014a7d..02be6b5036 100644 --- a/lib/kernel/src/Makefile +++ b/lib/kernel/src/Makefile @@ -118,11 +118,14 @@ MODULES = \ user_sup \ wrap_log_reader -HRL_FILES= ../include/file.hrl ../include/inet.hrl ../include/inet_sctp.hrl +HRL_FILES= ../include/file.hrl ../include/inet.hrl ../include/inet_sctp.hrl \ + ../include/dist.hrl ../include/dist_util.hrl \ + ../include/net_address.hrl + INTERNAL_HRL_FILES= application_master.hrl disk_log.hrl \ - net_address.hrl inet_dns.hrl inet_res.hrl \ + inet_dns.hrl inet_res.hrl \ inet_boot.hrl inet_config.hrl inet_int.hrl \ - dist.hrl dist_util.hrl inet_dns_record_adts.hrl + inet_dns_record_adts.hrl ERL_FILES= $(MODULES:%=%.erl) @@ -215,7 +218,7 @@ $(EBIN)/code_server.beam: ../include/file.hrl $(EBIN)/disk_log.beam: disk_log.hrl $(EBIN)/disk_log_1.beam: disk_log.hrl ../include/file.hrl $(EBIN)/disk_log_server.beam: disk_log.hrl -$(EBIN)/dist_util.beam: dist_util.hrl dist.hrl +$(EBIN)/dist_util.beam: ../include/dist_util.hrl ../include/dist.hrl $(EBIN)/erl_boot_server.beam: inet_boot.hrl $(EBIN)/erl_epmd.beam: inet_int.hrl erl_epmd.hrl $(EBIN)/file.beam: ../include/file.hrl @@ -226,7 +229,7 @@ $(EBIN)/global.beam: ../../stdlib/include/ms_transform.hrl $(EBIN)/hipe_unified_loader.beam: ../../hipe/main/hipe.hrl hipe_ext_format.hrl $(EBIN)/inet.beam: ../include/inet.hrl inet_int.hrl ../include/inet_sctp.hrl $(EBIN)/inet6_tcp.beam: inet_int.hrl -$(EBIN)/inet6_tcp_dist.beam: net_address.hrl dist.hrl dist_util.hrl +$(EBIN)/inet6_tcp_dist.beam: ../include/net_address.hrl ../include/dist.hrl ../include/dist_util.hrl $(EBIN)/inet6_udp.beam: inet_int.hrl $(EBIN)/inet6_sctp.beam: inet_int.hrl $(EBIN)/inet_config.beam: inet_config.hrl ../include/inet.hrl @@ -237,10 +240,10 @@ $(EBIN)/inet_hosts.beam: ../include/inet.hrl $(EBIN)/inet_parse.beam: ../include/file.hrl $(EBIN)/inet_res.beam: ../include/inet.hrl inet_res.hrl inet_dns.hrl inet_int.hrl $(EBIN)/inet_tcp.beam: inet_int.hrl -$(EBIN)/inet_udp_dist.beam: net_address.hrl dist.hrl dist_util.hrl +$(EBIN)/inet_udp_dist.beam: ../include/net_address.hrl ../include/dist.hrl ../include/dist_util.hrl $(EBIN)/inet_udp.beam: inet_int.hrl $(EBIN)/inet_sctp.beam: inet_int.hrl ../include/inet_sctp.hrl -$(EBIN)/net_kernel.beam: net_address.hrl +$(EBIN)/net_kernel.beam: ../include/net_address.hrl $(EBIN)/os.beam: ../include/file.hrl $(EBIN)/ram_file.beam: ../include/file.hrl $(EBIN)/wrap_log_reader.beam: disk_log.hrl ../include/file.hrl diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl index 2a193affd4..caac4d926c 100644 --- a/lib/kernel/src/application.erl +++ b/lib/kernel/src/application.erl @@ -28,49 +28,70 @@ -export([get_application/0, get_application/1, info/0]). -export([start_type/0]). --export([behaviour_info/1]). - %%%----------------------------------------------------------------- +-type start_type() :: 'normal' + | {'takeover', Node :: node()} + | {'failover', Node :: node()}. -type restart_type() :: 'permanent' | 'transient' | 'temporary'. --type application_opt() :: {'description', string()} - | {'vsn', string()} - | {'id', string()} - | {'modules', [atom() | {atom(), any()}]} - | {'registered', [atom()]} - | {'applications', [atom()]} - | {'included_applications', [atom()]} - | {'env', [{atom(), any()}]} - | {'start_phases', [{atom(), any()}] | 'undefined'} - | {'maxT', timeout()} % max timeout - | {'maxP', integer() | 'infinity'} % max processes - | {'mod', {atom(), any()}}. --type application_spec() :: {'application', atom(), [application_opt()]}. +-type application_opt() :: {'description', Description :: string()} + | {'vsn', Vsn :: string()} + | {'id', Id :: string()} + | {'modules', [(Module :: module()) | + {Module :: module(), Version :: term()}]} + | {'registered', Names :: [Name :: atom()]} + | {'applications', [Application :: atom()]} + | {'included_applications', [Application :: atom()]} + | {'env', [{Par :: atom(), Val :: term()}]} + | {'start_phases', + [{Phase :: atom(), PhaseArgs :: term()}] | 'undefined'} + | {'maxT', MaxT :: timeout()} % max timeout + | {'maxP', + MaxP :: pos_integer() | 'infinity'} % max processes + | {'mod', Start :: {Module :: module(), StartArgs :: term()}}. +-type application_spec() :: {'application', + Application :: atom(), + AppSpecKeys :: [application_opt()]}. + +-type(tuple_of(_T) :: tuple()). %%------------------------------------------------------------------ --spec behaviour_info(atom()) -> 'undefined' | [{atom(), byte()}]. +-callback start(StartType :: normal | {takeover, node()} | {failover, node()}, + StartArgs :: term()) -> + {ok, pid()} | {ok, pid(), State :: term()} | {error, Reason :: term}. -behaviour_info(callbacks) -> - [{start,2},{stop,1}]; -behaviour_info(_Other) -> - undefined. +-callback stop(State :: term()) -> + term(). %%%----------------------------------------------------------------- %%% This module is API towards application_controller and %%% application_master. %%%----------------------------------------------------------------- --spec load(Application :: atom() | application_spec()) -> - 'ok' | {'error', term()}. +-spec load(AppDescr) -> 'ok' | {'error', Reason} when + AppDescr :: Application | (AppSpec :: application_spec()), + Application :: atom(), + Reason :: term(). load(Application) -> - load(Application, []). - --spec load(Application :: atom() | application_spec(), - Distributed :: any()) -> 'ok' | {'error', term()}. + load1(Application, []). + +-spec load(AppDescr, Distributed) -> 'ok' | {'error', Reason} when + AppDescr :: Application | (AppSpec :: application_spec()), + Application :: atom(), + Distributed :: {Application,Nodes} + | {Application,Time,Nodes} + | 'default', + Nodes :: [node() | tuple_of(node())], + Time :: pos_integer(), + Reason :: term(). load(Application, DistNodes) -> + load1(Application, DistNodes). + +%% Workaround due to specs. +load1(Application, DistNodes) -> case application_controller:load_application(Application) of ok when DistNodes =/= [] -> AppName = get_appl_name(Application), @@ -85,18 +106,24 @@ load(Application, DistNodes) -> Else end. --spec unload(Application :: atom()) -> 'ok' | {'error', term()}. +-spec unload(Application) -> 'ok' | {'error', Reason} when + Application :: atom(), + Reason :: term(). unload(Application) -> application_controller:unload_application(Application). --spec start(Application :: atom()) -> 'ok' | {'error', term()}. +-spec start(Application) -> 'ok' | {'error', Reason} when + Application :: atom(), + Reason :: term(). start(Application) -> start(Application, temporary). --spec start(Application :: atom() | application_spec(), - RestartType :: restart_type()) -> any(). +-spec start(Application, Type) -> 'ok' | {'error', Reason} when + Application :: atom(), + Type :: restart_type(), + Reason :: term(). start(Application, RestartType) -> case load(Application) of @@ -120,12 +147,18 @@ start_boot(Application) -> start_boot(Application, RestartType) -> application_controller:start_boot_application(Application, RestartType). --spec takeover(Application :: atom(), RestartType :: restart_type()) -> any(). +-spec takeover(Application, Type) -> 'ok' | {'error', Reason} when + Application :: atom(), + Type :: restart_type(), + Reason :: term(). takeover(Application, RestartType) -> dist_ac:takeover_application(Application, RestartType). --spec permit(Application :: atom(), Bool :: boolean()) -> 'ok' | {'error', term()}. +-spec permit(Application, Permission) -> 'ok' | {'error', Reason} when + Application :: atom(), + Permission :: boolean(), + Reason :: term(). permit(Application, Bool) -> case Bool of @@ -142,105 +175,146 @@ permit(Application, Bool) -> LocalResult end. --spec stop(Application :: atom()) -> 'ok' | {'error', term()}. +-spec stop(Application) -> 'ok' | {'error', Reason} when + Application :: atom(), + Reason :: term(). stop(Application) -> application_controller:stop_application(Application). --spec which_applications() -> [{atom(), string(), string()}]. +-spec which_applications() -> [{Application, Description, Vsn}] when + Application :: atom(), + Description :: string(), + Vsn :: string(). which_applications() -> application_controller:which_applications(). --spec which_applications(timeout()) -> [{atom(), string(), string()}]. +-spec which_applications(Timeout) -> [{Application, Description, Vsn}] when + Timeout :: timeout(), + Application :: atom(), + Description :: string(), + Vsn :: string(). which_applications(infinity) -> application_controller:which_applications(infinity); which_applications(Timeout) when is_integer(Timeout), Timeout>=0 -> application_controller:which_applications(Timeout). --spec loaded_applications() -> [{atom(), string(), string()}]. +-spec loaded_applications() -> [{Application, Description, Vsn}] when + Application :: atom(), + Description :: string(), + Vsn :: string(). loaded_applications() -> application_controller:loaded_applications(). --spec info() -> any(). +-spec info() -> term(). info() -> application_controller:info(). --spec set_env(Application :: atom(), Key :: atom(), Value :: any()) -> 'ok'. +-spec set_env(Application, Par, Val) -> 'ok' when + Application :: atom(), + Par :: atom(), + Val :: term(). set_env(Application, Key, Val) -> application_controller:set_env(Application, Key, Val). --spec set_env(Application :: atom(), Key :: atom(), - Value :: any(), Timeout :: timeout()) -> 'ok'. +-spec set_env(Application, Par, Val, Timeout) -> 'ok' when + Application :: atom(), + Par :: atom(), + Val :: term(), + Timeout :: timeout(). set_env(Application, Key, Val, infinity) -> application_controller:set_env(Application, Key, Val, infinity); set_env(Application, Key, Val, Timeout) when is_integer(Timeout), Timeout>=0 -> application_controller:set_env(Application, Key, Val, Timeout). --spec unset_env(atom(), atom()) -> 'ok'. +-spec unset_env(Application, Par) -> 'ok' when + Application :: atom(), + Par :: atom(). unset_env(Application, Key) -> application_controller:unset_env(Application, Key). --spec unset_env(atom(), atom(), timeout()) -> 'ok'. +-spec unset_env(Application, Par, Timeout) -> 'ok' when + Application :: atom(), + Par :: atom(), + Timeout :: timeout(). unset_env(Application, Key, infinity) -> application_controller:unset_env(Application, Key, infinity); unset_env(Application, Key, Timeout) when is_integer(Timeout), Timeout>=0 -> application_controller:unset_env(Application, Key, Timeout). --spec get_env(atom()) -> 'undefined' | {'ok', term()}. +-spec get_env(Par) -> 'undefined' | {'ok', Val} when + Par :: atom(), + Val :: term(). get_env(Key) -> application_controller:get_pid_env(group_leader(), Key). --spec get_env(atom(), atom()) -> 'undefined' | {'ok', term()}. +-spec get_env(Application, Par) -> 'undefined' | {'ok', Val} when + Application :: atom(), + Par :: atom(), + Val :: term(). get_env(Application, Key) -> application_controller:get_env(Application, Key). --spec get_all_env() -> [{atom(), any()}]. +-spec get_all_env() -> Env when + Env :: [{Par :: atom(), Val :: term()}]. get_all_env() -> application_controller:get_pid_all_env(group_leader()). --spec get_all_env(atom()) -> [{atom(), any()}]. +-spec get_all_env(Application) -> Env when + Application :: atom(), + Env :: [{Par :: atom(), Val :: term()}]. get_all_env(Application) -> application_controller:get_all_env(Application). --spec get_key(atom()) -> 'undefined' | {'ok', term()}. +-spec get_key(Key) -> 'undefined' | {'ok', Val} when + Key :: atom(), + Val :: term(). get_key(Key) -> application_controller:get_pid_key(group_leader(), Key). --spec get_key(atom(), atom()) -> 'undefined' | {'ok', term()}. +-spec get_key(Application, Key) -> 'undefined' | {'ok', Val} when + Application :: atom(), + Key :: atom(), + Val :: term(). get_key(Application, Key) -> application_controller:get_key(Application, Key). --spec get_all_key() -> 'undefined' | [] | {'ok', [{atom(),any()},...]}. +-spec get_all_key() -> [] | {'ok', Keys} when + Keys :: [{Key :: atom(),Val :: term()},...]. get_all_key() -> application_controller:get_pid_all_key(group_leader()). --spec get_all_key(atom()) -> 'undefined' | {'ok', [{atom(),any()},...]}. +-spec get_all_key(Application) -> 'undefined' | Keys when + Application :: atom(), + Keys :: {'ok', [{Key :: atom(),Val :: term()},...]}. get_all_key(Application) -> application_controller:get_all_key(Application). --spec get_application() -> 'undefined' | {'ok', atom()}. +-spec get_application() -> 'undefined' | {'ok', Application} when + Application :: atom(). get_application() -> application_controller:get_application(group_leader()). --spec get_application(Pid :: pid()) -> 'undefined' | {'ok', atom()} - ; (Module :: atom()) -> 'undefined' | {'ok', atom()}. +-spec get_application(PidOrModule) -> 'undefined' | {'ok', Application} when + PidOrModule :: (Pid :: pid()) | (Module :: module()), + Application :: atom(). get_application(Pid) when is_pid(Pid) -> case process_info(Pid, group_leader) of @@ -252,8 +326,8 @@ get_application(Pid) when is_pid(Pid) -> get_application(Module) when is_atom(Module) -> application_controller:get_application_module(Module). --spec start_type() -> 'undefined' | 'local' | 'normal' - | {'takeover', node()} | {'failover', node()}. +-spec start_type() -> StartType | 'undefined' | 'local' when + StartType :: start_type(). start_type() -> application_controller:start_type(group_leader()). diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl index 42f527f400..ebfe84463a 100644 --- a/lib/kernel/src/application_controller.erl +++ b/lib/kernel/src/application_controller.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1180,10 +1180,27 @@ terminate(Reason, S) -> _ -> ok end, + ShutdownTimeout = + case application:get_env(kernel, shutdown_timeout) of + undefined -> infinity; + {ok,T} -> T + end, foreach(fun({_AppName, Id}) when is_pid(Id) -> + Ref = erlang:monitor(process, Id), + unlink(Id), exit(Id, shutdown), receive + %% Proc died before link {'EXIT', Id, _} -> ok + after 0 -> + receive + {'DOWN', Ref, process, Id, _} -> ok + after ShutdownTimeout -> + exit(Id, kill), + receive + {'DOWN', Ref, process, Id, _} -> ok + end + end end; (_) -> ok end, diff --git a/lib/kernel/src/auth.erl b/lib/kernel/src/auth.erl index 5c7fe2421d..c329a5652a 100644 --- a/lib/kernel/src/auth.erl +++ b/lib/kernel/src/auth.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -57,7 +57,8 @@ start_link() -> %%--Deprecated interface------------------------------------------------ --spec is_auth(Node :: node()) -> 'yes' | 'no'. +-spec is_auth(Node) -> 'yes' | 'no' when + Node :: node(). is_auth(Node) -> case net_adm:ping(Node) of @@ -65,12 +66,15 @@ is_auth(Node) -> pang -> no end. --spec cookie() -> cookie(). +-spec cookie() -> Cookie when + Cookie :: cookie(). cookie() -> get_cookie(). --spec cookie(Cookies :: [cookie(),...] | cookie()) -> 'true'. +-spec cookie(TheCookie) -> 'true' when + TheCookie :: Cookie | [Cookie], + Cookie :: cookie(). cookie([Cookie]) -> set_cookie(Cookie); @@ -82,7 +86,9 @@ cookie(Cookie) -> node_cookie([Node, Cookie]) -> node_cookie(Node, Cookie). --spec node_cookie(Node :: node(), Cookie :: cookie()) -> 'yes' | 'no'. +-spec node_cookie(Node, Cookie) -> 'yes' | 'no' when + Node :: node(), + Cookie :: cookie(). node_cookie(Node, Cookie) -> set_cookie(Node, Cookie), @@ -206,7 +212,7 @@ handle_info({From,badcookie,net_kernel,{From,spawn_link,_M,_F,_A,_Gleader}}, O) {noreply, O}; handle_info({_From,badcookie,ddd_server,_Mess}, O) -> %% Ignore bad messages to the ddd server, they will be resent - %% If the authentication is succesful + %% If the authentication is successful {noreply, O}; handle_info({From,badcookie,rex,_Msg}, O) -> auth:print(getnode(From), diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl index b0f99305f2..882e9625fe 100644 --- a/lib/kernel/src/code.erl +++ b/lib/kernel/src/code.erl @@ -82,7 +82,8 @@ %% add_pathsa([Dir]) -> ok %% add_pathsz([Dir]) -> ok %% del_path(Dir) -> boolean() | {error, bad_name} -%% replace_path(Name, Dir) -> true | replace_path_error() +%% 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()} @@ -113,11 +114,16 @@ %% Some types for basic exported functions of this module %%---------------------------------------------------------------------------- --type load_error_rsn() :: 'badfile' | 'native_code' | 'nofile' | 'not_purged' - | 'sticky_directory'. % for some functions only --type load_ret() :: {'error', load_error_rsn()} | {'module', atom()}. +-type load_error_rsn() :: 'badfile' + | 'native_code' + | 'nofile' + | 'not_purged' + | 'on_load' + | 'sticky_directory'. +-type load_ret() :: {'error', What :: load_error_rsn()} + | {'module', Module :: module()}. -type loaded_ret_atoms() :: 'cover_compiled' | 'preloaded'. --type loaded_filename() :: file:filename() | loaded_ret_atoms(). +-type loaded_filename() :: (Filename :: file:filename()) | loaded_ret_atoms(). %%---------------------------------------------------------------------------- %% User interface @@ -127,55 +133,74 @@ objfile_extension() -> init:objfile_extension(). --spec load_file(Module :: atom()) -> load_ret(). +-spec load_file(Module) -> load_ret() when + Module :: module(). load_file(Mod) when is_atom(Mod) -> call({load_file,Mod}). --spec ensure_loaded(Module :: atom()) -> load_ret(). +-spec ensure_loaded(Module) -> {module, Module} | {error, What} when + Module :: module(), + What :: embedded | badfile | native_code | nofile | on_load. ensure_loaded(Mod) when is_atom(Mod) -> call({ensure_loaded,Mod}). %% XXX File as an atom is allowed only for backwards compatibility. --spec load_abs(Filename :: file:filename()) -> load_ret(). +-spec load_abs(Filename) -> load_ret() when + Filename :: file:filename(). load_abs(File) when is_list(File); is_atom(File) -> call({load_abs,File,[]}). %% XXX Filename is also an atom(), e.g. 'cover_compiled' --spec load_abs(Filename :: loaded_filename(), Module :: atom()) -> load_ret(). +-spec load_abs(Filename :: loaded_filename(), Module :: module()) -> load_ret(). load_abs(File, M) when (is_list(File) orelse is_atom(File)), is_atom(M) -> call({load_abs,File,M}). %% XXX Filename is also an atom(), e.g. 'cover_compiled' --spec load_binary(Module :: atom(), Filename :: loaded_filename(), Binary :: binary()) -> load_ret(). +-spec load_binary(Module, Filename, Binary) -> + {module, Module} | {error, What} when + Module :: module(), + Filename :: loaded_filename(), + Binary :: binary(), + What :: badarg | load_error_rsn(). load_binary(Mod, File, Bin) when is_atom(Mod), (is_list(File) orelse is_atom(File)), is_binary(Bin) -> call({load_binary,Mod,File,Bin}). --spec load_native_partial(Module :: atom(), Binary :: binary()) -> load_ret(). +-spec load_native_partial(Module :: module(), Binary :: binary()) -> load_ret(). load_native_partial(Mod, Bin) when is_atom(Mod), is_binary(Bin) -> call({load_native_partial,Mod,Bin}). --spec load_native_sticky(Module :: atom(), Binary :: binary(), WholeModule :: 'false' | binary()) -> load_ret(). +-spec load_native_sticky(Module :: module(), Binary :: binary(), WholeModule :: 'false' | binary()) -> load_ret(). load_native_sticky(Mod, Bin, WholeModule) when is_atom(Mod), is_binary(Bin), (is_binary(WholeModule) orelse WholeModule =:= false) -> call({load_native_sticky,Mod,Bin,WholeModule}). --spec delete(Module :: atom()) -> boolean(). +-spec delete(Module) -> boolean() when + Module :: module(). delete(Mod) when is_atom(Mod) -> call({delete,Mod}). --spec purge(Module :: atom()) -> boolean(). +-spec purge(Module) -> boolean() when + Module :: module(). purge(Mod) when is_atom(Mod) -> call({purge,Mod}). --spec soft_purge(Module :: atom()) -> boolean(). +-spec soft_purge(Module) -> boolean() when + Module :: module(). soft_purge(Mod) when is_atom(Mod) -> call({soft_purge,Mod}). --spec is_loaded(Module :: atom()) -> {'file', loaded_filename()} | 'false'. +-spec is_loaded(Module) -> {'file', Loaded} | false when + Module :: module(), + Loaded :: loaded_filename(). is_loaded(Mod) when is_atom(Mod) -> call({is_loaded,Mod}). --spec get_object_code(Module :: atom()) -> {atom(), binary(), file:filename()} | 'error'. +-spec get_object_code(Module) -> {Module, Binary, Filename} | error when + Module :: module(), + Binary :: binary(), + Filename :: file:filename(). get_object_code(Mod) when is_atom(Mod) -> call({get_object_code, Mod}). --spec all_loaded() -> [{atom(), loaded_filename()}]. +-spec all_loaded() -> [{Module, Loaded}] when + Module :: module(), + Loaded :: loaded_filename(). all_loaded() -> call(all_loaded). -spec stop() -> no_return(). @@ -188,65 +213,86 @@ root_dir() -> call({dir,root_dir}). lib_dir() -> call({dir,lib_dir}). %% XXX is_list() is for backwards compatibility -- take out in future version --spec lib_dir(App :: atom()) -> file:filename() | {'error', 'bad_name'}. +-spec lib_dir(Name) -> file:filename() | {'error', 'bad_name'} when + Name :: atom(). lib_dir(App) when is_atom(App) ; is_list(App) -> call({dir,{lib_dir,App}}). --spec lib_dir(App :: atom(), SubDir :: atom()) -> file:filename() | {'error', 'bad_name'}. +-spec lib_dir(Name, SubDir) -> file:filename() | {'error', 'bad_name'} when + Name :: atom(), + SubDir :: atom(). lib_dir(App, SubDir) when is_atom(App), is_atom(SubDir) -> call({dir,{lib_dir,App,SubDir}}). -spec compiler_dir() -> file:filename(). compiler_dir() -> call({dir,compiler_dir}). %% XXX is_list() is for backwards compatibility -- take out in future version --spec priv_dir(App :: atom()) -> file:filename() | {'error', 'bad_name'}. +-spec priv_dir(Name) -> file:filename() | {'error', 'bad_name'} when + Name :: atom(). priv_dir(App) when is_atom(App) ; is_list(App) -> call({dir,{priv_dir,App}}). --spec stick_dir(Directory :: file:filename()) -> 'ok' | 'error'. +-spec stick_dir(Dir) -> 'ok' | 'error' when + Dir :: file:filename(). stick_dir(Dir) when is_list(Dir) -> call({stick_dir,Dir}). --spec unstick_dir(Directory :: file:filename()) -> 'ok' | 'error'. +-spec unstick_dir(Dir) -> 'ok' | 'error' when + Dir :: file:filename(). unstick_dir(Dir) when is_list(Dir) -> call({unstick_dir,Dir}). --spec stick_mod(Module :: atom()) -> 'true'. +-spec stick_mod(Module :: module()) -> 'true'. stick_mod(Mod) when is_atom(Mod) -> call({stick_mod,Mod}). --spec unstick_mod(Module :: atom()) -> 'true'. +-spec unstick_mod(Module :: module()) -> 'true'. unstick_mod(Mod) when is_atom(Mod) -> call({unstick_mod,Mod}). --spec is_sticky(Module :: atom()) -> boolean(). +-spec is_sticky(Module) -> boolean() when + Module :: module(). is_sticky(Mod) when is_atom(Mod) -> call({is_sticky,Mod}). --spec set_path(Directories :: [file:filename()]) -> - 'true' | {'error', 'bad_directory' | 'bad_path'}. +-spec set_path(Path) -> 'true' | {'error', What} when + Path :: [Dir :: file:filename()], + What :: 'bad_directory' | 'bad_path'. set_path(PathList) when is_list(PathList) -> call({set_path,PathList}). --spec get_path() -> [file:filename()]. +-spec get_path() -> Path when + Path :: [Dir :: file:filename()]. get_path() -> call(get_path). -type add_path_ret() :: 'true' | {'error', 'bad_directory'}. --spec add_path(Directory :: file:filename()) -> add_path_ret(). +-spec add_path(Dir) -> add_path_ret() when + Dir :: file:filename(). add_path(Dir) when is_list(Dir) -> call({add_path,last,Dir}). --spec add_pathz(Directory :: file:filename()) -> add_path_ret(). +-spec add_pathz(Dir) -> add_path_ret() when + Dir :: file:filename(). add_pathz(Dir) when is_list(Dir) -> call({add_path,last,Dir}). --spec add_patha(Directory :: file:filename()) -> add_path_ret(). +-spec add_patha(Dir) -> add_path_ret() when + Dir :: file:filename(). add_patha(Dir) when is_list(Dir) -> call({add_path,first,Dir}). --spec add_paths(Directories :: [file:filename()]) -> 'ok'. +-spec add_paths(Dirs) -> 'ok' when + Dirs :: [Dir :: file:filename()]. add_paths(Dirs) when is_list(Dirs) -> call({add_paths,last,Dirs}). --spec add_pathsz(Directories :: [file:filename()]) -> 'ok'. +-spec add_pathsz(Dirs) -> 'ok' when + Dirs :: [Dir :: file:filename()]. add_pathsz(Dirs) when is_list(Dirs) -> call({add_paths,last,Dirs}). --spec add_pathsa(Directories :: [file:filename()]) -> 'ok'. +-spec add_pathsa(Dirs) -> 'ok' when + Dirs :: [Dir :: file:filename()]. add_pathsa(Dirs) when is_list(Dirs) -> call({add_paths,first,Dirs}). --spec del_path(Name :: file:filename() | atom()) -> boolean() | {'error', 'bad_name'}. +-spec del_path(NameOrDir) -> boolean() | {'error', What} when + NameOrDir :: Name | Dir, + Name :: atom(), + Dir :: file:filename(), + What :: 'bad_name'. del_path(Name) when is_list(Name) ; is_atom(Name) -> call({del_path,Name}). --type replace_path_error() :: {'error', 'bad_directory' | 'bad_name' | {'badarg',_}}. --spec replace_path(Name:: atom(), Dir :: file:filename()) -> 'true' | replace_path_error(). +-spec replace_path(Name, Dir) -> 'true' | {'error', What} when + Name:: atom(), + Dir :: file:filename(), + What :: 'bad_directory' | 'bad_name' | {'badarg',_}. replace_path(Name, Dir) when (is_atom(Name) orelse is_list(Name)), (is_atom(Dir) orelse is_list(Dir)) -> call({replace_path,Name,Dir}). @@ -351,10 +397,9 @@ get_mode(Flags) -> %% In that case return the name of the file which contains %% the loaded object code --type which_ret_atoms() :: loaded_ret_atoms() | 'non_existing'. - --spec which(Module :: atom()) -> file:filename() | which_ret_atoms(). - +-spec which(Module) -> Which when + Module :: module(), + Which :: file:filename() | loaded_ret_atoms() | non_existing. which(Module) when is_atom(Module) -> case is_loaded(Module) of false -> @@ -394,9 +439,9 @@ which(File, Base, [Directory|Tail]) -> %% Search the code path for a specific file. Try to locate %% it in the code path cache if possible. --spec where_is_file(Filename :: file:filename()) -> - 'non_existing' | file:filename(). - +-spec where_is_file(Filename) -> non_existing | Absname when + Filename :: file:filename(), + Absname :: file:filename(). where_is_file(File) when is_list(File) -> case call({is_cached,File}) of no -> diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl index 4a1fc7df34..e3d22e7999 100644 --- a/lib/kernel/src/code_server.erl +++ b/lib/kernel/src/code_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% Copyright Ericsson AB 1998-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1379,8 +1379,12 @@ absname_vr([[X, $:]|Name], _, _AbsBase) -> %% Kill all processes running code from *old* Module, and then purge the %% module. Return true if any processes killed, else false. -do_purge(Mod) -> - do_purge(processes(), to_atom(Mod), false). +do_purge(Mod0) -> + Mod = to_atom(Mod0), + case erlang:check_old_code(Mod) of + false -> false; + true -> do_purge(processes(), Mod, false) + end. do_purge([P|Ps], Mod, Purged) -> case erlang:check_process_code(P, Mod) of @@ -1399,16 +1403,19 @@ do_purge([], Mod, Purged) -> Purged. %% do_soft_purge(Module) -%% Purge old code only if no procs remain that run old code +%% Purge old code only if no procs remain that run old code. %% Return true in that case, false if procs remain (in this %% case old code is not purged) do_soft_purge(Mod) -> - catch do_soft_purge(processes(), Mod). + case erlang:check_old_code(Mod) of + false -> true; + true -> do_soft_purge(processes(), Mod) + end. do_soft_purge([P|Ps], Mod) -> case erlang:check_process_code(P, Mod) of - true -> throw(false); + true -> false; false -> do_soft_purge(Ps, Mod) end; do_soft_purge([], Mod) -> diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl index 7f1b5f9ec6..d6bc23be6d 100644 --- a/lib/kernel/src/disk_log.erl +++ b/lib/kernel/src/disk_log.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -70,9 +70,10 @@ %%% Contract type specifications %%%---------------------------------------------------------------------- +-opaque continuation() :: #continuation{}. + -type bytes() :: binary() | [byte()]. --type log() :: term(). % XXX: refine -type file_error() :: term(). % XXX: refine -type invalid_header() :: term(). % XXX: refine @@ -87,27 +88,30 @@ -type open_error_rsn() :: 'no_such_log' | {'badarg', term()} - | {'size_mismatch', dlog_size(), dlog_size()} - | {'arg_mismatch', dlog_optattr(), term(), term()} - | {'name_already_open', log()} - | {'open_read_write', log()} - | {'open_read_only', log()} - | {'need_repair', log()} - | {'not_a_log_file', string()} - | {'invalid_index_file', string()} + | {'size_mismatch', CurrentSize :: dlog_size(), + NewSize :: dlog_size()} + | {'arg_mismatch', OptionName :: dlog_optattr(), + CurrentValue :: term(), Value :: term()} + | {'name_already_open', Log :: log()} + | {'open_read_write', Log :: log()} + | {'open_read_only', Log :: log()} + | {'need_repair', Log :: log()} + | {'not_a_log_file', FileName :: file:filename()} + | {'invalid_index_file', FileName :: file:filename()} | {'invalid_header', invalid_header()} | {'file_error', file:filename(), file_error()} - | {'node_already_open', log()}. + | {'node_already_open', Log :: log()}. -type dist_error_rsn() :: 'nodedown' | open_error_rsn(). --type ret() :: {'ok', log()} - | {'repaired', log(), {'recovered', non_neg_integer()}, - {'badbytes', non_neg_integer()}}. +-type ret() :: {'ok', Log :: log()} + | {'repaired', Log :: log(), + {'recovered', Rec :: non_neg_integer()}, + {'badbytes', Bad :: non_neg_integer()}}. -type open_ret() :: ret() | {'error', open_error_rsn()}. -type dist_open_ret() :: {[{node(), ret()}], [{node(), {'error', dist_error_rsn()}}]}. --type all_open_ret() :: open_ret() | dist_open_ret(). --spec open(Args :: dlog_options()) -> all_open_ret(). +-spec open(ArgL) -> open_ret() | dist_open_ret() when + ArgL :: dlog_options(). open(A) -> disk_log_server:open(check_arg(A, #arg{options = A})). @@ -116,40 +120,57 @@ open(A) -> | {'full', log()} | {'invalid_header', invalid_header()} | {'file_error', file:filename(), file_error()}. --spec log(Log :: log(), Term :: term()) -> 'ok' | {'error', log_error_rsn()}. +-spec log(Log, Term) -> ok | {error, Reason :: log_error_rsn()} when + Log :: log(), + Term :: term(). log(Log, Term) -> req(Log, {log, term_to_binary(Term)}). --spec blog(Log :: log(), Bytes :: bytes()) -> 'ok' | {'error', log_error_rsn()}. +-spec blog(Log, Bytes) -> ok | {error, Reason :: log_error_rsn()} when + Log :: log(), + Bytes :: bytes(). blog(Log, Bytes) -> req(Log, {blog, check_bytes(Bytes)}). --spec log_terms(Log :: log(), Terms :: [term()]) -> 'ok' | {'error', term()}. +-spec log_terms(Log, TermList) -> ok | {error, Resaon :: log_error_rsn()} when + Log :: log(), + TermList :: [term()]. log_terms(Log, Terms) -> Bs = terms2bins(Terms), req(Log, {log, Bs}). --spec blog_terms(Log :: log(), Bytes :: [bytes()]) -> 'ok' | {'error', term()}. +-spec blog_terms(Log, BytesList) -> + ok | {error, Reason :: log_error_rsn()} when + Log :: log(), + BytesList :: [bytes()]. blog_terms(Log, Bytess) -> Bs = check_bytes_list(Bytess, Bytess), req(Log, {blog, Bs}). -type notify_ret() :: 'ok' | {'error', 'no_such_log'}. --spec alog(Log :: log(), Term :: term()) -> notify_ret(). +-spec alog(Log, Term) -> notify_ret() when + Log :: log(), + Term :: term(). alog(Log, Term) -> notify(Log, {alog, term_to_binary(Term)}). --spec alog_terms(Log :: log(), Terms :: [term()]) -> notify_ret(). +-spec alog_terms(Log, TermList) -> notify_ret() when + Log :: log(), + TermList :: [term()]. alog_terms(Log, Terms) -> Bs = terms2bins(Terms), notify(Log, {alog, Bs}). --spec balog(Log :: log(), Bytes :: bytes()) -> notify_ret(). +-spec balog(Log, Bytes) -> notify_ret() when + Log :: log(), + Bytes :: bytes(). balog(Log, Bytes) -> notify(Log, {balog, check_bytes(Bytes)}). --spec balog_terms(Log :: log(), Bytes :: [bytes()]) -> notify_ret(). +-spec balog_terms(Log, ByteList) -> notify_ret() when + Log :: log(), + ByteList :: [bytes()]. balog_terms(Log, Bytess) -> Bs = check_bytes_list(Bytess, Bytess), notify(Log, {balog, Bs}). @@ -157,18 +178,22 @@ balog_terms(Log, Bytess) -> -type close_error_rsn() ::'no_such_log' | 'nonode' | {'file_error', file:filename(), file_error()}. --spec close(Log :: log()) -> 'ok' | {'error', close_error_rsn()}. +-spec close(Log) -> 'ok' | {'error', close_error_rsn()} when + Log :: log(). close(Log) -> req(Log, close). -type lclose_error_rsn() :: 'no_such_log' | {'file_error', file:filename(), file_error()}. --spec lclose(Log :: log()) -> 'ok' | {'error', lclose_error_rsn()}. +-spec lclose(Log) -> 'ok' | {'error', lclose_error_rsn()} when + Log :: log(). lclose(Log) -> lclose(Log, node()). --spec lclose(Log :: log(), Node :: node()) -> 'ok' | {'error', lclose_error_rsn()}. +-spec lclose(Log, Node) -> 'ok' | {'error', lclose_error_rsn()} when + Log :: log(), + Node :: node(). lclose(Log, Node) -> lreq(Log, close, Node). @@ -178,29 +203,49 @@ lclose(Log, Node) -> | {'invalid_header', invalid_header()} | {'file_error', file:filename(), file_error()}. --spec truncate(Log :: log()) -> 'ok' | {'error', trunc_error_rsn()}. +-spec truncate(Log) -> 'ok' | {'error', trunc_error_rsn()} when + Log :: log(). truncate(Log) -> req(Log, {truncate, none, truncate, 1}). --spec truncate(Log :: log(), Head :: term()) -> 'ok' | {'error', trunc_error_rsn()}. +-spec truncate(Log, Head) -> 'ok' | {'error', trunc_error_rsn()} when + Log :: log(), + Head :: term(). truncate(Log, Head) -> req(Log, {truncate, {ok, term_to_binary(Head)}, truncate, 2}). --spec btruncate(Log :: log(), Head :: bytes()) -> 'ok' | {'error', trunc_error_rsn()}. +-spec btruncate(Log, BHead) -> 'ok' | {'error', trunc_error_rsn()} when + Log :: log(), + BHead :: bytes(). btruncate(Log, Head) -> req(Log, {truncate, {ok, check_bytes(Head)}, btruncate, 2}). --spec reopen(Log :: log(), Filename :: file:filename()) -> 'ok' | {'error', term()}. +-type reopen_error_rsn() :: no_such_log + | nonode + | {read_only_mode, log()} + | {blocked_log, log()} + | {same_file_name, log()} | + {invalid_index_file, file:filename()} + | {invalid_header, invalid_header()} + | {'file_error', file:filename(), file_error()}. + +-spec reopen(Log, File) -> 'ok' | {'error', reopen_error_rsn()} when + Log :: log(), + File :: file:filename(). reopen(Log, NewFile) -> req(Log, {reopen, NewFile, none, reopen, 2}). --spec reopen(Log :: log(), Filename :: file:filename(), Head :: term()) -> - 'ok' | {'error', term()}. +-spec reopen(Log, File, Head) -> 'ok' | {'error', reopen_error_rsn()} when + Log :: log(), + File :: file:filename(), + Head :: term(). reopen(Log, NewFile, NewHead) -> req(Log, {reopen, NewFile, {ok, term_to_binary(NewHead)}, reopen, 3}). --spec breopen(Log :: log(), Filename :: file:filename(), Head :: bytes()) -> - 'ok' | {'error', term()}. +-spec breopen(Log, File, BHead) -> 'ok' | {'error', reopen_error_rsn()} when + Log :: log(), + File :: file:filename(), + BHead :: bytes(). breopen(Log, NewFile, NewHead) -> req(Log, {reopen, NewFile, {ok, check_bytes(NewHead)}, breopen, 3}). @@ -210,21 +255,36 @@ breopen(Log, NewFile, NewHead) -> | {'invalid_header', invalid_header()} | {'file_error', file:filename(), file_error()}. --spec inc_wrap_file(Log :: log()) -> 'ok' | {'error', inc_wrap_error_rsn()}. +-spec inc_wrap_file(Log) -> 'ok' | {'error', inc_wrap_error_rsn()} when + Log :: log(). inc_wrap_file(Log) -> req(Log, inc_wrap_file). --spec change_size(Log :: log(), Size :: dlog_size()) -> 'ok' | {'error', term()}. +-spec change_size(Log, Size) -> 'ok' | {'error', Reason} when + Log :: log(), + Size :: dlog_size(), + Reason :: no_such_log | nonode | {read_only_mode, Log} + | {blocked_log, Log} + | {new_size_too_small, CurrentSize :: pos_integer()} + | {badarg, size} + | {file_error, file:filename(), file_error()}. change_size(Log, NewSize) -> req(Log, {change_size, NewSize}). --spec change_notify(Log :: log(), Pid :: pid(), Notify :: boolean()) -> - 'ok' | {'error', term()}. +-spec change_notify(Log, Owner, Notify) -> 'ok' | {'error', Reason} when + Log :: log(), + Owner :: pid(), + Notify :: boolean(), + Reason :: no_such_log | nonode | {blocked_log, Log} + | {badarg, notify} | {not_owner, Owner}. change_notify(Log, Pid, NewNotify) -> req(Log, {change_notify, Pid, NewNotify}). --spec change_header(Log :: log(), Head :: {atom(), term()}) -> - 'ok' | {'error', term()}. +-spec change_header(Log, Header) -> 'ok' | {'error', Reason} when + Log :: log(), + Header :: {head, dlog_head_opt()} | {head_func, mfa()}, + Reason :: no_such_log | nonode | {read_only_mode, Log} + | {blocked_log, Log} | {badarg, head}. change_header(Log, NewHead) -> req(Log, {change_header, NewHead}). @@ -232,17 +292,21 @@ change_header(Log, NewHead) -> | {'blocked_log', log()} | {'file_error', file:filename(), file_error()}. --spec sync(Log :: log()) -> 'ok' | {'error', sync_error_rsn()}. +-spec sync(Log) -> 'ok' | {'error', sync_error_rsn()} when + Log :: log(). sync(Log) -> req(Log, sync). -type block_error_rsn() :: 'no_such_log' | 'nonode' | {'blocked_log', log()}. --spec block(Log :: log()) -> 'ok' | {'error', block_error_rsn()}. +-spec block(Log) -> 'ok' | {'error', block_error_rsn()} when + Log :: log(). block(Log) -> block(Log, true). --spec block(Log :: log(), QueueLogRecords :: boolean()) -> 'ok' | {'error', term()}. +-spec block(Log, QueueLogRecords) -> 'ok' | {'error', block_error_rsn()} when + Log :: log(), + QueueLogRecords :: boolean(). block(Log, QueueLogRecords) -> req(Log, {block, QueueLogRecords}). @@ -250,19 +314,46 @@ block(Log, QueueLogRecords) -> | {'not_blocked', log()} | {'not_blocked_by_pid', log()}. --spec unblock(Log :: log()) -> 'ok' | {'error', unblock_error_rsn()}. +-spec unblock(Log) -> 'ok' | {'error', unblock_error_rsn()} when + Log :: log(). unblock(Log) -> req(Log, unblock). --spec format_error(Error :: term()) -> string(). +-spec format_error(Error) -> io_lib:chars() when + Error :: term(). format_error(Error) -> do_format_error(Error). --spec info(Log :: log()) -> [{atom(), any()}] | {'error', term()}. +-type dlog_info() :: {name, Log :: log()} + | {file, File :: file:filename()} + | {type, Type :: dlog_type()} + | {format, Format :: dlog_format()} + | {size, Size :: dlog_size()} + | {mode, Mode :: dlog_mode()} + | {owners, [{pid(), Notify :: boolean()}]} + | {users, Users :: non_neg_integer()} + | {status, Status :: + ok | {blocked, QueueLogRecords :: boolean()}} + | {node, Node :: node()} + | {distributed, Dist :: local | [node()]} + | {head, Head :: none | {head, term()} | mfa()} + | {no_written_items, NoWrittenItems ::non_neg_integer()} + | {full, Full :: boolean} + | {no_current_bytes, non_neg_integer()} + | {no_current_items, non_neg_integer()} + | {no_items, non_neg_integer()} + | {current_file, pos_integer()} + | {no_overflows, {SinceLogWasOpened :: non_neg_integer(), + SinceLastInfo :: non_neg_integer()}}. +-spec info(Log) -> InfoList | {'error', no_such_log} when + Log :: log(), + InfoList :: [dlog_info()]. info(Log) -> sreq(Log, info). --spec pid2name(Pid :: pid()) -> {'ok', log()} | 'undefined'. +-spec pid2name(Pid) -> {'ok', Log} | 'undefined' when + Pid :: pid(), + Log :: log(). pid2name(Pid) -> disk_log_server:start(), case ets:lookup(?DISK_LOG_PID_TABLE, Pid) of @@ -274,13 +365,31 @@ pid2name(Pid) -> %% It retuns a {Cont2, ObjList} | eof | {error, Reason} %% The initial continuation is the atom 'start' --spec chunk(Log :: log(), Cont :: any()) -> - {'error', term()} | 'eof' | {any(), [any()]} | {any(), [any()], integer()}. +-type chunk_error_rsn() :: no_such_log + | {format_external, log()} + | {blocked_log, log()} + | {badarg, continuation} + | {not_internal_wrap, log()} + | {corrupt_log_file, FileName :: file:filename()} + | {file_error, file:filename(), file_error()}. + +-type chunk_ret() :: {Continuation2 :: continuation(), Terms :: [term()]} + | {Continuation2 :: continuation(), + Terms :: [term()], + Badbytes :: non_neg_integer()} + | eof + | {error, Reason :: chunk_error_rsn()}. + +-spec chunk(Log, Continuation) -> chunk_ret() when + Log :: log(), + Continuation :: start | continuation(). chunk(Log, Cont) -> chunk(Log, Cont, infinity). --spec chunk(Log :: log(), Cont :: any(), N :: pos_integer() | 'infinity') -> - {'error', term()} | 'eof' | {any(), [any()]} | {any(), [any()], integer()}. +-spec chunk(Log, Continuation, N) -> chunk_ret() when + Log :: log(), + Continuation :: start | continuation(), + N :: pos_integer() | infinity. chunk(Log, Cont, infinity) -> %% There cannot be more than ?MAX_CHUNK_SIZE terms in a chunk. ichunk(Log, Cont, ?MAX_CHUNK_SIZE); @@ -346,13 +455,24 @@ ichunk_bad_end([B | Bs], Mode, Log, C, Bad, A) -> ichunk_bad_end(Bs, Mode, Log, C, Bad, [T | A]) end. --spec bchunk(Log :: log(), Cont :: any()) -> - {'error', any()} | 'eof' | {any(), [binary()]} | {any(), [binary()], integer()}. +-type bchunk_ret() :: {Continuation2 :: continuation(), + Binaries :: [binary()]} + | {Continuation2 :: continuation(), + Binaries :: [binary()], + Badbytes :: non_neg_integer()} + | eof + | {error, Reason :: chunk_error_rsn()}. + +-spec bchunk(Log, Continuation) -> bchunk_ret() when + Log :: log(), + Continuation :: start | continuation(). bchunk(Log, Cont) -> bchunk(Log, Cont, infinity). --spec bchunk(Log :: log(), Cont :: any(), N :: 'infinity' | pos_integer()) -> - {'error', any()} | 'eof' | {any(), [binary()]} | {any(), [binary()], integer()}. +-spec bchunk(Log, Continuation, N) -> bchunk_ret() when + Log :: log(), + Continuation :: start | continuation(), + N :: pos_integer() | infinity. bchunk(Log, Cont, infinity) -> %% There cannot be more than ?MAX_CHUNK_SIZE terms in a chunk. bichunk(Log, Cont, ?MAX_CHUNK_SIZE); @@ -375,8 +495,14 @@ bichunk_end({C = #continuation{}, R, Bad}) -> bichunk_end(R) -> R. --spec chunk_step(Log :: log(), Cont :: any(), N :: integer()) -> - {'ok', any()} | {'error', term()}. +-spec chunk_step(Log, Continuation, Step) -> + {'ok', any()} | {'error', Reason} when + Log :: log(), + Continuation :: start | continuation(), + Step :: integer(), + Reason :: no_such_log | end_of_log | {format_external, Log} + | {blocked_log, Log} | {badarg, continuation} + | {file_error, file:filename(), file_error()}. chunk_step(Log, Cont, N) when is_integer(N) -> ichunk_step(Log, Cont, N). @@ -387,14 +513,18 @@ ichunk_step(_Log, More, N) when is_record(More, continuation) -> ichunk_step(_Log, _, _) -> {error, {badarg, continuation}}. --spec chunk_info(More :: any()) -> - [{'node', node()},...] | {'error', {'no_continuation', any()}}. +-spec chunk_info(Continuation) -> InfoList | {error, Reason} when + Continuation :: continuation(), + InfoList :: [{node, Node :: node()}, ...], + Reason :: {no_continuation, Continuation}. chunk_info(More = #continuation{}) -> [{node, node(More#continuation.pid)}]; chunk_info(BadCont) -> {error, {no_continuation, BadCont}}. --spec accessible_logs() -> {[_], [_]}. +-spec accessible_logs() -> {[LocalLog], [DistributedLog]} when + LocalLog :: log(), + DistributedLog :: log(). accessible_logs() -> disk_log_server:accessible_logs(). @@ -1110,20 +1240,29 @@ is_owner(Pid, L) -> %% ok | throw(Error) rename_file(File, NewFile, halt) -> - file:rename(File, NewFile); + case file:rename(File, NewFile) of + ok -> + ok; + Else -> + file_error(NewFile, Else) + end; rename_file(File, NewFile, wrap) -> rename_file(wrap_file_extensions(File), File, NewFile, ok). -rename_file([Ext|Exts], File, NewFile, Res) -> - NRes = case file:rename(add_ext(File, Ext), add_ext(NewFile, Ext)) of +rename_file([Ext|Exts], File, NewFile0, Res) -> + NewFile = add_ext(NewFile0, Ext), + NRes = case file:rename(add_ext(File, Ext), NewFile) of ok -> Res; Else -> - Else + file_error(NewFile, Else) end, - rename_file(Exts, File, NewFile, NRes); + rename_file(Exts, File, NewFile0, NRes); rename_file([], _File, _NewFiles, Res) -> Res. +file_error(FileName, {error, Error}) -> + {error, {file_error, FileName, Error}}. + %% "Old" error messages have been kept, arg_mismatch has been added. %%-spec compare_arg(dlog_options(), #arg{}, compare_arg([], _A, none, _OrigHead) -> @@ -1817,7 +1956,8 @@ monitor_request(Pid, Req) -> receive {'DOWN', Ref, process, Pid, _Info} -> {error, no_such_log}; - {disk_log, Pid, Reply} -> + {disk_log, Pid, Reply} when not is_tuple(Reply) orelse + element(2, Reply) =/= disk_log_stopped -> erlang:demonitor(Ref), receive {'DOWN', Ref, process, Pid, _Reason} -> diff --git a/lib/kernel/src/disk_log.hrl b/lib/kernel/src/disk_log.hrl index 9a94d4d3b9..259967650f 100644 --- a/lib/kernel/src/disk_log.hrl +++ b/lib/kernel/src/disk_log.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -53,18 +53,34 @@ %% Types -- alphabetically %%------------------------------------------------------------------------ +-type dlog_byte() :: [dlog_byte()] | byte(). -type dlog_format() :: 'external' | 'internal'. -type dlog_format_type() :: 'halt_ext' | 'halt_int' | 'wrap_ext' | 'wrap_int'. -type dlog_head() :: 'none' | {'ok', binary()} | mfa(). +-type dlog_head_opt() :: none | term() | binary() | [dlog_byte()]. +-type log() :: term(). % XXX: refine -type dlog_mode() :: 'read_only' | 'read_write'. -type dlog_name() :: atom() | string(). -type dlog_optattr() :: 'name' | 'file' | 'linkto' | 'repair' | 'type' | 'format' | 'size' | 'distributed' | 'notify' | 'head' | 'head_func' | 'mode'. --type dlog_options() :: [{dlog_optattr(), any()}]. +-type dlog_option() :: {name, Log :: log()} + | {file, FileName :: file:filename()} + | {linkto, LinkTo :: none | pid()} + | {repair, Repair :: true | false | truncate} + | {type, Type :: dlog_type} + | {format, Format :: dlog_format()} + | {size, Size :: dlog_size()} + | {distributed, Nodes :: [node()]} + | {notify, boolean()} + | {head, Head :: dlog_head_opt()} + | {head_func, mfa()} + | {mode, Mode :: dlog_mode()}. +-type dlog_options() :: [dlog_option()]. -type dlog_repair() :: 'truncate' | boolean(). -type dlog_size() :: 'infinity' | pos_integer() - | {pos_integer(), pos_integer()}. + | {MaxNoBytes :: pos_integer(), + MaxNoFiles :: pos_integer()}. -type dlog_status() :: 'ok' | {'blocked', 'false' | [_]}. %QueueLogRecords -type dlog_type() :: 'halt' | 'wrap'. @@ -75,7 +91,7 @@ %% record of args for open -record(arg, {name = 0, version = undefined, - file = none :: 'none' | string(), + file = none :: 'none' | file:filename(), repair = true :: dlog_repair(), size = infinity :: dlog_size(), type = halt :: dlog_type(), diff --git a/lib/kernel/src/erl_boot_server.erl b/lib/kernel/src/erl_boot_server.erl index b4c5f5e27c..0d68d3e198 100644 --- a/lib/kernel/src/erl_boot_server.erl +++ b/lib/kernel/src/erl_boot_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -59,7 +59,11 @@ -type ip4_address() :: {0..255,0..255,0..255,0..255}. --spec start(Slaves :: [atom()]) -> {'ok', pid()} | {'error', any()}. +-spec start(Slaves) -> {'ok', Pid} | {'error', What} when + Slaves :: [Host], + Host :: atom(), + Pid :: pid(), + What :: any(). start(Slaves) -> case check_arg(Slaves) of @@ -69,7 +73,11 @@ start(Slaves) -> {error, {badarg, Slaves}} end. --spec start_link(Slaves :: [atom()]) -> {'ok', pid()} | {'error', any()}. +-spec start_link(Slaves) -> {'ok', Pid} | {'error', What} when + Slaves :: [Host], + Host :: atom(), + Pid :: pid(), + What :: any(). start_link(Slaves) -> case check_arg(Slaves) of @@ -95,7 +103,10 @@ check_arg([], Result) -> check_arg(_, _Result) -> error. --spec add_slave(Slave :: atom()) -> 'ok' | {'error', any()}. +-spec add_slave(Slave) -> 'ok' | {'error', What} when + Slave :: Host, + Host :: atom(), + What :: any(). add_slave(Slave) -> case inet:getaddr(Slave, inet) of @@ -105,7 +116,10 @@ add_slave(Slave) -> {error, {badarg, Slave}} end. --spec delete_slave(Slave :: atom()) -> 'ok' | {'error', any()}. +-spec delete_slave(Slave) -> 'ok' | {'error', What} when + Slave :: Host, + Host :: atom(), + What :: any(). delete_slave(Slave) -> case inet:getaddr(Slave, inet) of @@ -131,7 +145,9 @@ add_subnet(Mask, Addr) when is_tuple(Mask), is_tuple(Addr) -> delete_subnet(Mask, Addr) when is_tuple(Mask), is_tuple(Addr) -> gen_server:call(boot_server, {delete, {Mask, Addr}}). --spec which_slaves() -> [atom()]. +-spec which_slaves() -> Slaves when + Slaves :: [Host], + Host :: atom(). which_slaves() -> gen_server:call(boot_server, which). diff --git a/lib/kernel/src/erl_ddll.erl b/lib/kernel/src/erl_ddll.erl index ce64589a29..646cac99c5 100644 --- a/lib/kernel/src/erl_ddll.erl +++ b/lib/kernel/src/erl_ddll.erl @@ -44,14 +44,18 @@ start() -> stop() -> ok. --spec load_driver(Path :: path(), Driver :: driver()) -> - 'ok' | {'error', any()}. +-spec load_driver(Path, Name) -> 'ok' | {'error', ErrorDesc} when + Path :: path(), + Name :: driver(), + ErrorDesc :: term(). load_driver(Path, Driver) -> do_load_driver(Path, Driver, [{driver_options,[kill_ports]}]). --spec load(Path :: path(), Driver :: driver()) -> - 'ok' | {'error', any()}. +-spec load(Path, Name) -> 'ok' | {'error', ErrorDesc} when + Path :: path(), + Name :: driver(), + ErrorDesc ::term(). load(Path, Driver) -> do_load_driver(Path, Driver, []). @@ -100,30 +104,41 @@ do_unload_driver(Driver,Flags) -> end end. --spec unload_driver(Driver :: driver()) -> 'ok' | {'error', any()}. +-spec unload_driver(Name) -> 'ok' | {'error', ErrorDesc} when + Name :: driver(), + ErrorDesc :: term(). unload_driver(Driver) -> do_unload_driver(Driver,[{monitor,pending_driver},kill_ports]). --spec unload(Driver :: driver()) -> 'ok' | {'error', any()}. +-spec unload(Name) -> 'ok' | {'error', ErrorDesc} when + Name :: driver(), + ErrorDesc :: term(). unload(Driver) -> do_unload_driver(Driver,[]). --spec reload(Path :: path(), Driver :: driver()) -> - 'ok' | {'error', any()}. +-spec reload(Path, Name) -> 'ok' | {'error', ErrorDesc} when + Path :: path(), + Name :: driver(), + ErrorDesc :: pending_process | OpaqueError, + OpaqueError :: term(). reload(Path,Driver) -> do_load_driver(Path, Driver, [{reload,pending_driver}]). --spec reload_driver(Path :: path(), Driver :: driver()) -> - 'ok' | {'error', any()}. +-spec reload_driver(Path, Name) -> 'ok' | {'error', ErrorDesc} when + Path :: path(), + Name :: driver(), + ErrorDesc :: pending_process | OpaqueError, + OpaqueError :: term(). reload_driver(Path,Driver) -> do_load_driver(Path, Driver, [{reload,pending_driver}, {driver_options,[kill_ports]}]). --spec format_error(Code :: atom()) -> string(). +-spec format_error(ErrorDesc) -> string() when + ErrorDesc :: term(). format_error(Code) -> case Code of @@ -135,7 +150,10 @@ format_error(Code) -> erl_ddll:format_error_int(Code) end. --spec info(Driver :: driver()) -> [{atom(), any()}, ...]. +-spec info(Name) -> InfoList when + Name :: driver(), + InfoList :: [InfoItem, ...], + InfoItem :: {Tag :: atom(), Value :: term()}. info(Driver) -> [{processes, erl_ddll:info(Driver,processes)}, @@ -146,7 +164,12 @@ info(Driver) -> {awaiting_load, erl_ddll:info(Driver,awaiting_load)}, {awaiting_unload, erl_ddll:info(Driver,awaiting_unload)}]. --spec info() -> [{string(), [{atom(), any()}]}]. +-spec info() -> AllInfoList when + AllInfoList :: [DriverInfo], + DriverInfo :: {DriverName, InfoList}, + DriverName :: string(), + InfoList :: [InfoItem], + InfoItem :: {Tag :: atom(), Value :: term()}. info() -> {ok,DriverList} = erl_ddll:loaded_drivers(), diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl index 6f69f4ccb9..a67b11a888 100644 --- a/lib/kernel/src/error_handler.erl +++ b/lib/kernel/src/error_handler.erl @@ -28,8 +28,11 @@ -export([undefined_function/3, undefined_lambda/3, stub_function/3, breakpoint/3]). --spec undefined_function(Module :: atom(), Function :: atom(), Args :: [_]) -> - any(). +-spec undefined_function(Module, Function, Args) -> + any() when + Module :: atom(), + Function :: atom(), + Args :: list(). undefined_function(Module, Func, Args) -> case ensure_loaded(Module) of @@ -51,8 +54,10 @@ undefined_function(Module, Func, Args) -> crash(Module, Func, Args) end. --spec undefined_lambda(Module :: atom(), Function :: fun(), Args :: [_]) -> - any(). +-spec undefined_lambda(Module, Fun, Args) -> term() when + Module :: atom(), + Fun :: fun(), + Args :: list(). undefined_lambda(Module, Fun, Args) -> case ensure_loaded(Module) of @@ -83,12 +88,12 @@ int() -> int. -spec crash(atom(), [term()]) -> no_return(). crash(Fun, Args) -> - crash({Fun,Args}). + crash({Fun,Args,[]}). -spec crash(atom(), atom(), arity()) -> no_return(). crash(M, F, A) -> - crash({M,F,A}). + crash({M,F,A,[]}). -spec crash(tuple()) -> no_return(). @@ -96,7 +101,8 @@ crash(Tuple) -> try erlang:error(undef) catch error:undef -> - erlang:raise(error, undef, [Tuple|tl(erlang:get_stacktrace())]) + Stk = [Tuple|tl(erlang:get_stacktrace())], + erlang:raise(error, undef, Stk) end. %% If the code_server has not been started yet dynamic code loading @@ -122,7 +128,7 @@ ensure_loaded(Module) -> -spec stub_function(atom(), atom(), [_]) -> no_return(). stub_function(Mod, Func, Args) -> - exit({undef,[{Mod,Func,Args}]}). + exit({undef,[{Mod,Func,Args,[]}]}). check_inheritance(Module, Args) -> Attrs = erlang:get_module_info(Module, attributes), diff --git a/lib/kernel/src/error_logger.erl b/lib/kernel/src/error_logger.erl index cafdc52e84..f94cca000f 100644 --- a/lib/kernel/src/error_logger.erl +++ b/lib/kernel/src/error_logger.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -69,17 +69,22 @@ start_link() -> %% Used for simple messages; error or information. %%----------------------------------------------------------------- --spec error_msg(Format :: string()) -> 'ok'. +-spec error_msg(Format) -> 'ok' when + Format :: string(). error_msg(Format) -> error_msg(Format,[]). --spec error_msg(Format :: string(), Args :: list()) -> 'ok'. +-spec error_msg(Format, Data) -> 'ok' when + Format :: string(), + Data :: list(). error_msg(Format, Args) -> notify({error, group_leader(), {self(), Format, Args}}). --spec format(Format :: string(), Args :: list()) -> 'ok'. +-spec format(Format, Data) -> 'ok' when + Format :: string(), + Data :: list(). format(Format, Args) -> notify({error, group_leader(), {self(), Format, Args}}). @@ -90,12 +95,18 @@ format(Format, Args) -> %% The 'std_error' error_report type can always be used. %%----------------------------------------------------------------- --spec error_report(Report :: any()) -> 'ok'. +-type report() :: + [{Tag :: term(), Data :: term()} | term()] | string() | term(). + +-spec error_report(Report) -> 'ok' when + Report :: report(). error_report(Report) -> error_report(std_error, Report). --spec error_report(Type :: any(), Report :: any()) -> 'ok'. +-spec error_report(Type, Report) -> 'ok' when + Type :: term(), + Report :: report(). error_report(Type, Report) -> notify({error_report, group_leader(), {self(), Type, Report}}). @@ -109,12 +120,15 @@ error_report(Type, Report) -> %% mapped to std_info or std_error accordingly. %%----------------------------------------------------------------- --spec warning_report(Report :: any()) -> 'ok'. +-spec warning_report(Report) -> 'ok' when + Report :: report(). warning_report(Report) -> warning_report(std_warning, Report). --spec warning_report(Type :: any(), Report :: any()) -> 'ok'. +-spec warning_report(Type, Report) -> 'ok' when + Type :: any(), + Report :: report(). warning_report(Type, Report) -> {Tag, NType} = case error_logger:warning_map() of @@ -143,12 +157,15 @@ warning_report(Type, Report) -> %% other types of reports. %%----------------------------------------------------------------- --spec warning_msg(Format :: string()) -> 'ok'. +-spec warning_msg(Format) -> 'ok' when + Format :: string(). warning_msg(Format) -> warning_msg(Format,[]). --spec warning_msg(Format :: string(), Args :: list()) -> 'ok'. +-spec warning_msg(Format, Data) -> 'ok' when + Format :: string(), + Data :: list(). warning_msg(Format, Args) -> Tag = case error_logger:warning_map() of @@ -167,12 +184,15 @@ warning_msg(Format, Args) -> %% The 'std_info' info_report type can always be used. %%----------------------------------------------------------------- --spec info_report(Report :: any()) -> 'ok'. +-spec info_report(Report) -> 'ok' when + Report :: report(). info_report(Report) -> info_report(std_info, Report). --spec info_report(Type :: any(), Report :: any()) -> 'ok'. +-spec info_report(Type, Report) -> 'ok' when + Type :: any(), + Report :: report(). info_report(Type, Report) -> notify({info_report, group_leader(), {self(), Type, Report}}). @@ -182,12 +202,15 @@ info_report(Type, Report) -> %% information messages. %%----------------------------------------------------------------- --spec info_msg(Format :: string()) -> 'ok'. +-spec info_msg(Format) -> 'ok' when + Format :: string(). info_msg(Format) -> info_msg(Format,[]). --spec info_msg(Format :: string(), Args :: list()) -> 'ok'. +-spec info_msg(Format, Data) -> 'ok' when + Format :: string(), + Data :: list(). info_msg(Format, Args) -> notify({info_msg, group_leader(), {self(), Format, Args}}). @@ -223,17 +246,23 @@ swap_handler(silent) -> swap_handler(false) -> ok. % keep primitive event handler as-is --spec add_report_handler(Module :: atom()) -> any(). +-spec add_report_handler(Handler) -> any() when + Handler :: module(). add_report_handler(Module) when is_atom(Module) -> gen_event:add_handler(error_logger, Module, []). --spec add_report_handler(atom(), any()) -> any(). +-spec add_report_handler(Handler, Args) -> Result when + Handler :: module(), + Args :: gen_event:handler_args(), + Result :: gen_event:add_handler_ret(). add_report_handler(Module, Args) when is_atom(Module) -> gen_event:add_handler(error_logger, Module, Args). --spec delete_report_handler(Module :: atom()) -> any(). +-spec delete_report_handler(Handler) -> Result when + Handler :: module(), + Result :: gen_event:del_handler_ret(). delete_report_handler(Module) when is_atom(Module) -> gen_event:delete_handler(error_logger, Module, []). @@ -250,9 +279,16 @@ simple_logger() -> %% Log all errors to File for all eternity --spec logfile(Request :: {'open', string()}) -> 'ok' | {'error',any()} - ; (Request :: 'close') -> 'ok' | {'error', any()} - ; (Request :: 'filename') -> atom() | string() | {'error', any()}. +-type open_error() :: file:posix() | badarg | system_limit. + +-spec logfile(Request :: {open, Filename}) -> ok | {error, OpenReason} when + Filename ::file:name(), + OpenReason :: allready_have_logfile | open_error() + ; (Request :: close) -> ok | {error, CloseReason} when + CloseReason :: module_not_found + ; (Request :: filename) -> Filename | {error, FilenameReason} when + Filename :: file:name(), + FilenameReason :: no_log_file. logfile({open, File}) -> case lists:member(error_logger_file_h, @@ -280,7 +316,8 @@ logfile(filename) -> %% Possibly turn off all tty printouts, maybe we only want the errors %% to go to a file --spec tty(Flag :: boolean()) -> 'ok'. +-spec tty(Flag) -> 'ok' when + Flag :: boolean(). tty(true) -> Hs = gen_event:which_handlers(error_logger), diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl index 88bcf9a9cc..706c60caaf 100644 --- a/lib/kernel/src/file.erl +++ b/lib/kernel/src/file.erl @@ -79,15 +79,19 @@ -type file_info() :: #file_info{}. -type fd() :: #file_descriptor{}. -type io_device() :: pid() | fd(). --type location() :: integer() | {'bof', integer()} | {'cur', integer()} - | {'eof', integer()} | 'bof' | 'cur' | 'eof'. +-type location() :: integer() | {'bof', Offset :: integer()} + | {'cur', Offset :: integer()} + | {'eof', Offset :: integer()} | 'bof' | 'cur' | 'eof'. -type mode() :: 'read' | 'write' | 'append' | 'exclusive' | 'raw' | 'binary' - | {'delayed_write', non_neg_integer(), non_neg_integer()} - | 'delayed_write' | {'read_ahead', pos_integer()} + | {'delayed_write', + Size :: non_neg_integer(), + Delay :: non_neg_integer()} + | 'delayed_write' | {'read_ahead', Size :: pos_integer()} | 'read_ahead' | 'compressed' | {'encoding', unicode:encoding()}. --type name() :: string() | atom() | [name()] | binary(). +-type deep_list() :: [char() | atom() | deep_list()]. +-type name() :: string() | atom() | deep_list() | (RawFilename :: binary()). -type posix() :: 'eacces' | 'eagain' | 'ebadf' | 'ebusy' | 'edquot' | 'eexist' | 'efault' | 'efbig' | 'eintr' | 'einval' | 'eio' | 'eisdir' | 'eloop' | 'emfile' | 'emlink' @@ -96,19 +100,17 @@ | 'enotblk' | 'enotdir' | 'enotsup' | 'enxio' | 'eperm' | 'epipe' | 'erofs' | 'espipe' | 'esrch' | 'estale' | 'exdev'. --type bindings() :: any(). - --type date() :: {pos_integer(), pos_integer(), pos_integer()}. --type time() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}. --type date_time() :: {date(), time()}. +-type date_time() :: calendar:datetime(). -type posix_file_advise() :: 'normal' | 'sequential' | 'random' | 'no_reuse' | 'will_need' | 'dont_need'. %%%----------------------------------------------------------------- %%% General functions --spec format_error(Reason :: posix() | {integer(), atom(), any()}) -> - string(). +-spec format_error(Reason) -> Chars when + Reason :: posix() | badarg | terminated | system_limit + | {Line :: integer(), Mod :: module(), Term :: term()}, + Chars :: string(). format_error({_Line, ?MODULE, undefined_script}) -> "no value returned from script"; @@ -129,7 +131,9 @@ format_error(terminated) -> format_error(ErrorId) -> erl_posix_msg:message(ErrorId). --spec pid2name(Pid :: pid()) -> {'ok', filename()} | 'undefined'. +-spec pid2name(Pid) -> {ok, Filename} | undefined when + Filename :: filename(), + Pid :: pid(). pid2name(Pid) when is_pid(Pid) -> case whereis(?FILE_SERVER) of @@ -148,42 +152,61 @@ pid2name(Pid) when is_pid(Pid) -> %%% File server functions. %%% Functions that do not operate on a single open file. %%% Stateless. --spec get_cwd() -> {'ok', filename()} | {'error', posix()}. +-spec get_cwd() -> {ok, Dir} | {error, Reason} when + Dir :: filename(), + Reason :: posix(). get_cwd() -> call(get_cwd, []). --spec get_cwd(Drive :: string()) -> {'ok', filename()} | {'error', posix()}. +-spec get_cwd(Drive) -> {ok, Dir} | {error, Reason} when + Drive :: string(), + Dir :: filename(), + Reason :: posix() | badarg. get_cwd(Drive) -> check_and_call(get_cwd, [file_name(Drive)]). --spec set_cwd(Dirname :: name()) -> 'ok' | {'error', posix()}. +-spec set_cwd(Dir) -> ok | {error, Reason} when + Dir :: name(), + Reason :: posix() | badarg. set_cwd(Dirname) -> check_and_call(set_cwd, [file_name(Dirname)]). --spec delete(Name :: name()) -> 'ok' | {'error', posix()}. +-spec delete(Filename) -> ok | {error, Reason} when + Filename :: name(), + Reason :: posix() | badarg. delete(Name) -> check_and_call(delete, [file_name(Name)]). --spec rename(From :: name(), To :: name()) -> 'ok' | {'error', posix()}. +-spec rename(Source, Destination) -> ok | {error, Reason} when + Source :: name(), + Destination :: name(), + Reason :: posix() | badarg. rename(From, To) -> check_and_call(rename, [file_name(From), file_name(To)]). --spec make_dir(Name :: name()) -> 'ok' | {'error', posix()}. +-spec make_dir(Dir) -> ok | {error, Reason} when + Dir :: name(), + Reason :: posix() | badarg. make_dir(Name) -> check_and_call(make_dir, [file_name(Name)]). --spec del_dir(Name :: name()) -> 'ok' | {'error', posix()}. +-spec del_dir(Dir) -> ok | {error, Reason} when + Dir :: name(), + Reason :: posix() | badarg. del_dir(Name) -> check_and_call(del_dir, [file_name(Name)]). --spec read_file_info(Name :: name()) -> {'ok', file_info()} | {'error', posix()}. +-spec read_file_info(Filename) -> {ok, FileInfo} | {error, Reason} when + Filename :: name(), + FileInfo :: file_info(), + Reason :: posix() | badarg. read_file_info(Name) -> check_and_call(read_file_info, [file_name(Name)]). @@ -193,45 +216,66 @@ read_file_info(Name) -> altname(Name) -> check_and_call(altname, [file_name(Name)]). --spec read_link_info(Name :: name()) -> {'ok', file_info()} | {'error', posix()}. +-spec read_link_info(Name) -> {ok, FileInfo} | {error, Reason} when + Name :: name(), + FileInfo :: file_info(), + Reason :: posix() | badarg. read_link_info(Name) -> check_and_call(read_link_info, [file_name(Name)]). --spec read_link(Name :: name()) -> {'ok', filename()} | {'error', posix()}. +-spec read_link(Name) -> {ok, Filename} | {error, Reason} when + Name :: name(), + Filename :: filename(), + Reason :: posix() | badarg. read_link(Name) -> check_and_call(read_link, [file_name(Name)]). --spec write_file_info(Name :: name(), Info :: file_info()) -> - 'ok' | {'error', posix()}. +-spec write_file_info(Filename, FileInfo) -> ok | {error, Reason} when + Filename :: name(), + FileInfo :: file_info(), + Reason :: posix() | badarg. write_file_info(Name, Info = #file_info{}) -> check_and_call(write_file_info, [file_name(Name), Info]). --spec list_dir(Name :: name()) -> {'ok', [filename()]} | {'error', posix()}. +-spec list_dir(Dir) -> {ok, Filenames} | {error, Reason} when + Dir :: name(), + Filenames :: [filename()], + Reason :: posix() | badarg. list_dir(Name) -> check_and_call(list_dir, [file_name(Name)]). --spec read_file(Name :: name()) -> - {'ok', binary()} | {'error', posix() | 'terminated' | 'system_limit'}. +-spec read_file(Filename) -> {ok, Binary} | {error, Reason} when + Filename :: name(), + Binary :: binary(), + Reason :: posix() | badarg | terminated | system_limit. read_file(Name) -> check_and_call(read_file, [file_name(Name)]). --spec make_link(Old :: name(), New :: name()) -> 'ok' | {'error', posix()}. +-spec make_link(Existing, New) -> ok | {error, Reason} when + Existing :: name(), + New :: name(), + Reason :: posix() | badarg. make_link(Old, New) -> check_and_call(make_link, [file_name(Old), file_name(New)]). --spec make_symlink(Old :: name(), New :: name()) -> 'ok' | {'error', posix()}. +-spec make_symlink(Name1, Name2) -> ok | {error, Reason} when + Name1 :: name(), + Name2 :: name(), + Reason :: posix() | badarg. make_symlink(Old, New) -> check_and_call(make_symlink, [file_name(Old), file_name(New)]). --spec write_file(Name :: name(), Bin :: iodata()) -> - 'ok' | {'error', posix() | 'terminated' | 'system_limit'}. +-spec write_file(Filename, Bytes) -> ok | {error, Reason} when + Filename :: name(), + Bytes :: iodata(), + Reason :: posix() | badarg | terminated | system_limit. write_file(Name, Bin) -> check_and_call(write_file, [file_name(Name), make_binary(Bin)]). @@ -240,8 +284,11 @@ write_file(Name, Bin) -> %% when it is time to change file server protocol again. %% Meanwhile, it is implemented here, slightly less efficient. --spec write_file(Name :: name(), Bin :: iodata(), Modes :: [mode()]) -> - 'ok' | {'error', posix()}. +-spec write_file(Filename, Bytes, Modes) -> ok | {error, Reason} when + Filename :: name(), + Bytes :: iodata(), + Modes :: [mode()], + Reason :: posix() | badarg | terminated | system_limit. write_file(Name, Bin, ModeList) when is_list(ModeList) -> case make_binary(Bin) of @@ -295,8 +342,11 @@ raw_write_file_info(Name, #file_info{} = Info) -> %% Contemporary mode specification - list of options --spec open(Name :: name(), Modes :: [mode()]) -> - {'ok', io_device()} | {'error', posix() | 'system_limit'}. +-spec open(Filename, Modes) -> {ok, IoDevice} | {error, Reason} when + Filename :: name(), + Modes :: [mode()], + IoDevice :: io_device(), + Reason :: posix() | badarg | system_limit. open(Item, ModeList) when is_list(ModeList) -> case lists:member(raw, ModeList) of @@ -349,7 +399,9 @@ open(Item, Mode) -> %%% The File argument must be either a Pid or a handle %%% returned from ?PRIM_FILE:open. --spec close(File :: io_device()) -> 'ok' | {'error', posix() | 'terminated'}. +-spec close(IoDevice) -> ok | {error, Reason} when + IoDevice :: io_device(), + Reason :: posix() | badarg | terminated. close(File) when is_pid(File) -> R = file_request(File, close), @@ -367,9 +419,12 @@ close(#file_descriptor{module = Module} = Handle) -> close(_) -> {error, badarg}. --spec advise(File :: io_device(), Offset :: integer(), - Length :: integer(), Advise :: posix_file_advise()) -> - 'ok' | {'error', posix()}. +-spec advise(IoDevice, Offset, Length, Advise) -> ok | {error, Reason} when + IoDevice :: io_device(), + Offset :: integer(), + Length :: integer(), + Advise :: posix_file_advise(), + Reason :: posix() | badarg. advise(File, Offset, Length, Advise) when is_pid(File) -> R = file_request(File, {advise, Offset, Length, Advise}), @@ -379,8 +434,11 @@ advise(#file_descriptor{module = Module} = Handle, Offset, Length, Advise) -> advise(_, _, _, _) -> {error, badarg}. --spec read(File :: io_device() | atom(), Size :: non_neg_integer()) -> - 'eof' | {'ok', [char()] | binary()} | {'error', posix()}. +-spec read(IoDevice, Number) -> {ok, Data} | eof | {error, Reason} when + IoDevice :: io_device() | atom(), + Number :: non_neg_integer(), + Data :: string() | binary(), + Reason :: posix() | badarg | terminated. read(File, Sz) when (is_pid(File) orelse is_atom(File)), is_integer(Sz), Sz >= 0 -> case io:request(File, {get_chars, '', Sz}) of @@ -395,8 +453,10 @@ read(#file_descriptor{module = Module} = Handle, Sz) read(_, _) -> {error, badarg}. --spec read_line(File :: io_device() | atom()) -> - 'eof' | {'ok', [char()] | binary()} | {'error', posix()}. +-spec read_line(IoDevice) -> {ok, Data} | eof | {error, Reason} when + IoDevice :: io_device() | atom(), + Data :: string() | binary(), + Reason :: posix() | badarg | terminated. read_line(File) when (is_pid(File) orelse is_atom(File)) -> case io:request(File, {get_line, ''}) of @@ -410,9 +470,12 @@ read_line(#file_descriptor{module = Module} = Handle) -> read_line(_) -> {error, badarg}. --spec pread(File :: io_device(), - LocationNumbers :: [{location(), non_neg_integer()}]) -> - {'ok', [string() | binary() | 'eof']} | {'error', posix()}. +-spec pread(IoDevice, LocNums) -> {ok, DataL} | eof | {error, Reason} when + IoDevice :: io_device(), + LocNums :: [{Location :: location(), Number :: non_neg_integer()}], + DataL :: [Data], + Data :: string() | binary() | eof, + Reason :: posix() | badarg | terminated. pread(File, L) when is_pid(File), is_list(L) -> pread_int(File, L, []); @@ -435,10 +498,13 @@ pread_int(File, [{At, Sz} | T], R) when is_integer(Sz), Sz >= 0 -> pread_int(_, _, _) -> {error, badarg}. --spec pread(File :: io_device(), - Location :: location(), - Size :: non_neg_integer()) -> - 'eof' | {'ok', string() | binary()} | {'error', posix()}. +-spec pread(IoDevice, Location, Number) -> + {ok, Data} | eof | {error, Reason} when + IoDevice :: io_device(), + Location :: location(), + Number :: non_neg_integer(), + Data :: string() | binary(), + Reason :: posix() | badarg | terminated. pread(File, At, Sz) when is_pid(File), is_integer(Sz), Sz >= 0 -> R = file_request(File, {pread, At, Sz}), @@ -449,8 +515,10 @@ pread(#file_descriptor{module = Module} = Handle, Offs, Sz) pread(_, _, _) -> {error, badarg}. --spec write(File :: io_device() | atom(), Byte :: iodata()) -> - 'ok' | {'error', posix() | 'terminated'}. +-spec write(IoDevice, Bytes) -> ok | {error, Reason} when + IoDevice :: io_device() | atom(), + Bytes :: iodata(), + Reason :: posix() | badarg | terminated. write(File, Bytes) when (is_pid(File) orelse is_atom(File)) -> case make_binary(Bytes) of @@ -464,8 +532,11 @@ write(#file_descriptor{module = Module} = Handle, Bytes) -> write(_, _) -> {error, badarg}. --spec pwrite(File :: io_device(), L :: [{location(), iodata()}]) -> - 'ok' | {'error', {non_neg_integer(), posix()}}. +-spec pwrite(IoDevice, LocBytes) -> ok | {error, {N, Reason}} when + IoDevice :: io_device(), + LocBytes :: [{Location :: location(), Bytes :: iodata()}], + N :: non_neg_integer(), + Reason :: posix() | badarg | terminated. pwrite(File, L) when is_pid(File), is_list(L) -> pwrite_int(File, L, 0); @@ -486,10 +557,11 @@ pwrite_int(File, [{At, Bytes} | T], R) -> pwrite_int(_, _, _) -> {error, badarg}. --spec pwrite(File :: io_device(), - Location :: location(), - Bytes :: iodata()) -> - 'ok' | {'error', posix()}. +-spec pwrite(IoDevice, Location, Bytes) -> ok | {error, Reason} when + IoDevice :: io_device(), + Location :: location(), + Bytes :: iodata(), + Reason :: posix() | badarg | terminated. pwrite(File, At, Bytes) when is_pid(File) -> R = file_request(File, {pwrite, At, Bytes}), @@ -499,7 +571,9 @@ pwrite(#file_descriptor{module = Module} = Handle, Offs, Bytes) -> pwrite(_, _, _) -> {error, badarg}. --spec datasync(File :: io_device()) -> 'ok' | {'error', posix()}. +-spec datasync(IoDevice) -> ok | {error, Reason} when + IoDevice :: io_device(), + Reason :: posix() | badarg | terminated. datasync(File) when is_pid(File) -> R = file_request(File, datasync), @@ -509,7 +583,9 @@ datasync(#file_descriptor{module = Module} = Handle) -> datasync(_) -> {error, badarg}. --spec sync(File :: io_device()) -> 'ok' | {'error', posix()}. +-spec sync(IoDevice) -> ok | {error, Reason} when + IoDevice :: io_device(), + Reason :: posix() | badarg | terminated. sync(File) when is_pid(File) -> R = file_request(File, sync), @@ -519,8 +595,11 @@ sync(#file_descriptor{module = Module} = Handle) -> sync(_) -> {error, badarg}. --spec position(File :: io_device(), Location :: location()) -> - {'ok',integer()} | {'error', posix()}. +-spec position(IoDevice, Location) -> {ok, NewPosition} | {error, Reason} when + IoDevice :: io_device(), + Location :: location(), + NewPosition :: integer(), + Reason :: posix() | badarg | terminated. position(File, At) when is_pid(File) -> R = file_request(File, {position,At}), @@ -530,7 +609,9 @@ position(#file_descriptor{module = Module} = Handle, At) -> position(_, _) -> {error, badarg}. --spec truncate(File :: io_device()) -> 'ok' | {'error', posix()}. +-spec truncate(IoDevice) -> ok | {error, Reason} when + IoDevice :: io_device(), + Reason :: posix() | badarg | terminated. truncate(File) when is_pid(File) -> R = file_request(File, truncate), @@ -540,17 +621,26 @@ truncate(#file_descriptor{module = Module} = Handle) -> truncate(_) -> {error, badarg}. --spec copy(Source :: io_device() | name() | {name(), [mode()]}, - Destination :: io_device() | name() | {name(), [mode()]}) -> - {'ok', non_neg_integer()} | {'error', posix()}. +-spec copy(Source, Destination) -> {ok, BytesCopied} | {error, Reason} when + Source :: io_device() | Filename | {Filename, Modes}, + Destination :: io_device() | Filename | {Filename, Modes}, + Filename :: name(), + Modes :: [mode()], + BytesCopied :: non_neg_integer(), + Reason :: posix() | badarg | terminated. copy(Source, Dest) -> copy_int(Source, Dest, infinity). --spec copy(Source :: io_device() | name() | {name(), [mode()]}, - Destination :: io_device() | name() | {name(), [mode()]}, - Length :: non_neg_integer() | 'infinity') -> - {'ok', non_neg_integer()} | {'error', posix()}. +-spec copy(Source, Destination, ByteCount) -> + {ok, BytesCopied} | {error, Reason} when + Source :: io_device() | Filename | {Filename, Modes}, + Destination :: io_device() | Filename | {Filename, Modes}, + Filename :: name(), + Modes :: [mode()], + ByteCount :: non_neg_integer() | infinity, + BytesCopied :: non_neg_integer(), + Reason :: posix() | badarg | terminated. copy(Source, Dest, Length) when is_integer(Length), Length >= 0; @@ -772,8 +862,11 @@ ipread_s32bu_p32bu_2(File, %%% The following functions, built upon the other interface functions, %%% provide a higher-lever interface to files. --spec consult(File :: name()) -> - {'ok', list()} | {'error', posix() | {integer(), atom(), any()}}. +-spec consult(Filename) -> {ok, Terms} | {error, Reason} when + Filename :: name(), + Terms :: [term()], + Reason :: posix() | badarg | terminated | system_limit + | {Line :: integer(), Mod :: module(), Term :: term()}. consult(File) -> case open(File, [read]) of @@ -785,8 +878,14 @@ consult(File) -> Error end. --spec path_consult(Paths :: [name()], File :: name()) -> - {'ok', list(), filename()} | {'error', posix() | {integer(), atom(), any()}}. +-spec path_consult(Path, Filename) -> {ok, Terms, FullName} | {error, Reason} when + Path :: [Dir], + Dir :: name(), + Filename :: name(), + Terms :: [term()], + FullName :: filename(), + Reason :: posix() | badarg | terminated | system_limit + | {Line :: integer(), Mod :: module(), Term :: term()}. path_consult(Path, File) -> case path_open(Path, File, [read]) of @@ -803,13 +902,19 @@ path_consult(Path, File) -> E2 end. --spec eval(File :: name()) -> 'ok' | {'error', posix()}. +-spec eval(Filename) -> ok | {error, Reason} when + Filename :: name(), + Reason :: posix() | badarg | terminated | system_limit + | {Line :: integer(), Mod :: module(), Term :: term()}. eval(File) -> eval(File, erl_eval:new_bindings()). --spec eval(File :: name(), Bindings :: bindings()) -> - 'ok' | {'error', posix()}. +-spec eval(Filename, Bindings) -> ok | {error, Reason} when + Filename :: name(), + Bindings :: erl_eval:binding_struct(), + Reason :: posix() | badarg | terminated | system_limit + | {Line :: integer(), Mod :: module(), Term :: term()}. eval(File, Bs) -> case open(File, [read]) of @@ -821,14 +926,24 @@ eval(File, Bs) -> Error end. --spec path_eval(Paths :: [name()], File :: name()) -> - {'ok', filename()} | {'error', posix() | {integer(), atom(), any()}}. +-spec path_eval(Path, Filename) -> {ok, FullName} | {error, Reason} when + Path :: [Dir :: name()], + Filename :: name(), + FullName :: filename(), + Reason :: posix() | badarg | terminated | system_limit + | {Line :: integer(), Mod :: module(), Term :: term()}. path_eval(Path, File) -> path_eval(Path, File, erl_eval:new_bindings()). --spec path_eval(Paths :: [name()], File :: name(), Bindings :: bindings()) -> - {'ok', filename()} | {'error', posix() | {integer(), atom(), any()}}. +-spec path_eval(Path, Filename, Bindings) -> + {ok, FullName} | {error, Reason} when + Path :: [Dir :: name()], + Filename :: name(), + Bindings :: erl_eval:binding_struct(), + FullName :: filename(), + Reason :: posix() | badarg | terminated | system_limit + | {Line :: integer(), Mod :: module(), Term :: term()}. path_eval(Path, File, Bs) -> case path_open(Path, File, [read]) of @@ -845,14 +960,21 @@ path_eval(Path, File, Bs) -> E2 end. --spec script(File :: name()) -> - {'ok', any()} | {'error', posix() | {integer(), atom(), any()}}. +-spec script(Filename) -> {ok, Value} | {error, Reason} when + Filename :: name(), + Value :: term(), + Reason :: posix() | badarg | terminated | system_limit + | {Line :: integer(), Mod :: module(), Term :: term()}. script(File) -> script(File, erl_eval:new_bindings()). --spec script(File :: name(), Bindings :: bindings()) -> - {'ok', any()} | {'error', posix() | {integer(), atom(), any()}}. +-spec script(Filename, Bindings) -> {ok, Value} | {error, Reason} when + Filename :: name(), + Bindings :: erl_eval:binding_struct(), + Value :: term(), + Reason :: posix() | badarg | terminated | system_limit + | {Line :: integer(), Mod :: module(), Term :: term()}. script(File, Bs) -> case open(File, [read]) of @@ -864,16 +986,27 @@ script(File, Bs) -> Error end. --spec path_script/2 :: (Paths :: [name()], File :: name()) -> - {'ok', term(), filename()} | {'error', posix() | {integer(), atom(), _}}. +-spec path_script(Path, Filename) -> + {ok, Value, FullName} | {error, Reason} when + Path :: [Dir :: name()], + Filename :: name(), + Value :: term(), + FullName :: filename(), + Reason :: posix() | badarg | terminated | system_limit + | {Line :: integer(), Mod :: module(), Term :: term()}. path_script(Path, File) -> path_script(Path, File, erl_eval:new_bindings()). --spec path_script(Paths :: [name()], - File :: name(), - Bindings :: bindings()) -> - {'ok', term(), filename()} | {'error', posix() | {integer(), atom(), _}}. +-spec path_script(Path, Filename, Bindings) -> + {ok, Value, FullName} | {error, Reason} when + Path :: [Dir :: name()], + Filename :: name(), + Bindings :: erl_eval:binding_struct(), + Value :: term(), + FullName :: filename(), + Reason :: posix() | badarg | terminated | system_limit + | {Line :: integer(), Mod :: module(), Term :: term()}. path_script(Path, File, Bs) -> case path_open(Path, File, [read]) of @@ -898,8 +1031,14 @@ path_script(Path, File, Bs) -> %% Searches the Paths for file Filename which can be opened with Mode. %% The path list is ignored if Filename contains an absolute path. --spec path_open(Paths :: [name()], Name :: name(), Modes :: [mode()]) -> - {'ok', io_device(), filename()} | {'error', posix()}. +-spec path_open(Path, Filename, Modes) -> + {ok, IoDevice, FullName} | {error, Reason} when + Path :: [Dir :: name()], + Filename :: name(), + Modes :: [mode()], + IoDevice :: io_device(), + FullName :: filename(), + Reason :: posix() | badarg | system_limit. path_open(PathList, Name, Mode) -> case file_name(Name) of @@ -919,47 +1058,57 @@ path_open(PathList, Name, Mode) -> end end. --spec change_mode(Name :: name(), Mode :: integer()) -> - 'ok' | {'error', posix()}. +-spec change_mode(Filename, Mode) -> ok | {error, Reason} when + Filename :: name(), + Mode :: integer(), + Reason :: posix() | badarg. change_mode(Name, Mode) when is_integer(Mode) -> write_file_info(Name, #file_info{mode=Mode}). --spec change_owner(Name :: name(), OwnerId :: integer()) -> - 'ok' | {'error', posix()}. +-spec change_owner(Filename, Uid) -> ok | {error, Reason} when + Filename :: name(), + Uid :: integer(), + Reason :: posix() | badarg. change_owner(Name, OwnerId) when is_integer(OwnerId) -> write_file_info(Name, #file_info{uid=OwnerId}). --spec change_owner(Name :: name(), - OwnerId :: integer(), - GroupId :: integer()) -> - 'ok' | {'error', posix()}. +-spec change_owner(Filename, Uid, Gid) -> ok | {error, Reason} when + Filename :: name(), + Uid :: integer(), + Gid :: integer(), + Reason :: posix() | badarg. change_owner(Name, OwnerId, GroupId) when is_integer(OwnerId), is_integer(GroupId) -> write_file_info(Name, #file_info{uid=OwnerId, gid=GroupId}). --spec change_group(Name :: name(), GroupId :: integer()) -> - 'ok' | {'error', posix()}. +-spec change_group(Filename, Gid) -> ok | {error, Reason} when + Filename :: name(), + Gid :: integer(), + Reason :: posix() | badarg. change_group(Name, GroupId) when is_integer(GroupId) -> write_file_info(Name, #file_info{gid=GroupId}). --spec change_time(Name :: name(), Time :: date_time()) -> - 'ok' | {'error', posix()}. +-spec change_time(Filename, Mtime) -> ok | {error, Reason} when + Filename :: name(), + Mtime :: date_time(), + Reason :: posix() | badarg. change_time(Name, Time) when is_tuple(Time) -> write_file_info(Name, #file_info{mtime=Time}). --spec change_time(Name :: name(), - ATime :: date_time(), - MTime :: date_time()) -> - 'ok' | {'error', posix()}. +-spec change_time(Filename, Atime, Mtime) -> ok | {error, Reason} when + Filename :: name(), + Atime :: date_time(), + Mtime :: date_time(), + Reason :: posix() | badarg. change_time(Name, Atime, Mtime) when is_tuple(Atime), is_tuple(Mtime) -> @@ -1014,7 +1163,7 @@ path_open_first([Path|Rest], Name, Mode, LastError) -> {error, _} = Error -> Error; FilePath -> - FileName = filename:join(FilePath, Name), + FileName = fname_join(FilePath, Name), case open(FileName, Mode) of {ok, Fd} -> {ok, Fd, FileName}; @@ -1027,6 +1176,11 @@ path_open_first([Path|Rest], Name, Mode, LastError) -> path_open_first([], _Name, _Mode, LastError) -> {error, LastError}. +fname_join(".", Name) -> + Name; +fname_join(Dir, Name) -> + filename:join(Dir, Name). + %%%----------------------------------------------------------------- %%% Utility functions. diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl index cccfa75005..77ca26b845 100644 --- a/lib/kernel/src/gen_sctp.erl +++ b/lib/kernel/src/gen_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -27,17 +27,96 @@ -include("inet_sctp.hrl"). -export([open/0,open/1,open/2,close/1]). --export([listen/2,connect/4,connect/5,connect_init/4,connect_init/5]). +-export([listen/2,peeloff/2]). +-export([connect/4,connect/5,connect_init/4,connect_init/5]). -export([eof/2,abort/2]). -export([send/3,send/4,recv/1,recv/2]). -export([error_string/1]). -export([controlling_process/2]). - +-type assoc_id() :: term(). +-type option() :: + {active, true | false | once} | + {buffer, non_neg_integer()} | + {dontroute, boolean()} | + {linger, {boolean(), non_neg_integer()}} | + {mode, list | binary} | list | binary | + {priority, non_neg_integer()} | + {recbuf, non_neg_integer()} | + {reuseaddr, boolean()} | + {sctp_adaptation_layer, #sctp_setadaptation{}} | + {sctp_associnfo, #sctp_assocparams{}} | + {sctp_autoclose, non_neg_integer()} | + {sctp_default_send_param, #sctp_sndrcvinfo{}} | + {sctp_delayed_ack_time, #sctp_assoc_value{}} | + {sctp_disable_fragments, boolean()} | + {sctp_events, #sctp_event_subscribe{}} | + {sctp_get_peer_addr_info, #sctp_paddrinfo{}} | + {sctp_i_want_mapped_v4_addr, boolean()} | + {sctp_initmsg, #sctp_initmsg{}} | + {sctp_maxseg, non_neg_integer()} | + {sctp_nodelay, boolean()} | + {sctp_peer_addr_params, #sctp_paddrparams{}} | + {sctp_primary_addr, #sctp_prim{}} | + {sctp_rtoinfo, #sctp_rtoinfo{}} | + {sctp_set_peer_primary_addr, #sctp_setpeerprim{}} | + {sctp_status, #sctp_status{}} | + {sndbuf, non_neg_integer()} | + {tos, non_neg_integer()}. +-type option_name() :: + active | + buffer | + dontroute | + linger | + mode | + priority | + recbuf | + reuseaddr | + sctp_adaptation_layer | + sctp_associnfo | + sctp_autoclose | + sctp_default_send_param | + sctp_delayed_ack_time | + sctp_disable_fragments | + sctp_events | + sctp_get_peer_addr_info | + sctp_i_want_mapped_v4_addr | + sctp_initmsg | + sctp_maxseg | + sctp_nodelay | + sctp_peer_addr_params | + sctp_primary_addr | + sctp_rtoinfo | + sctp_set_peer_primary_addr | + sctp_status | + sndbuf | + tos. +-type sctp_socket() :: port(). + +-export_type([assoc_id/0, option/0, option_name/0, sctp_socket/0]). + +-spec open() -> {ok, Socket} | {error, inet:posix()} when + Socket :: sctp_socket(). open() -> open([]). +-spec open(Port) -> {ok, Socket} | {error, inet:posix()} when + Port :: inet:port_number(), + Socket :: sctp_socket(); + (Opts) -> {ok, Socket} | {error, inet:posix()} when + Opts :: [Opt], + Opt :: {ip,IP} + | {ifaddr,IP} + | inet:address_family() + | {port,Port} + | {type,SockType} + | option(), + IP :: inet:ip_address() | any | loopback, + Port :: inet:port_number(), + SockType :: seqpacket | stream, + Socket :: sctp_socket(). + open(Opts) when is_list(Opts) -> Mod = mod(Opts, undefined), case Mod:open(Opts) of @@ -52,11 +131,27 @@ open(Port) when is_integer(Port) -> open(X) -> erlang:error(badarg, [X]). +-spec open(Port, Opts) -> {ok, Socket} | {error, inet:posix()} when + Opts :: [Opt], + Opt :: {ip,IP} + | {ifaddr,IP} + | inet:address_family() + | {port,Port} + | {type,SockType} + | option(), + IP :: inet:ip_address() | any | loopback, + Port :: inet:port_number(), + SockType :: seqpacket | stream, + Socket :: sctp_socket(). + open(Port, Opts) when is_integer(Port), is_list(Opts) -> open([{port,Port}|Opts]); open(Port, Opts) -> erlang:error(badarg, [Port,Opts]). +-spec close(Socket) -> ok | {error, inet:posix()} when + Socket :: sctp_socket(). + close(S) when is_port(S) -> case inet_db:lookup_socket(S) of {ok,Mod} -> @@ -68,18 +163,60 @@ close(S) -> -listen(S, Flag) when is_port(S), is_boolean(Flag) -> +-spec listen(Socket, IsServer) -> ok | {error, Reason} when + Socket :: sctp_socket(), + IsServer :: boolean(), + Reason :: term(); + (Socket, Backlog) -> ok | {error, Reason} when + Socket :: sctp_socket(), + Backlog :: integer(), + Reason :: term(). + +listen(S, Backlog) + when is_port(S), is_boolean(Backlog); + is_port(S), is_integer(Backlog) -> case inet_db:lookup_socket(S) of {ok,Mod} -> - Mod:listen(S, Flag); + Mod:listen(S, Backlog); Error -> Error end; listen(S, Flag) -> erlang:error(badarg, [S,Flag]). +-spec peeloff(Socket, Assoc) -> {ok, NewSocket} | {error, Reason} when + Socket :: sctp_socket(), + Assoc :: #sctp_assoc_change{} | assoc_id(), + NewSocket :: sctp_socket(), + Reason :: term(). + +peeloff(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) -> + peeloff(S, AssocId); +peeloff(S, AssocId) when is_port(S), is_integer(AssocId) -> + case inet_db:lookup_socket(S) of + {ok,Mod} -> + Mod:peeloff(S, AssocId); + Error -> Error + end. + +-spec connect(Socket, Addr, Port, Opts) -> {ok, Assoc} | {error, inet:posix()} when + Socket :: sctp_socket(), + Addr :: inet:ip_address() | inet:hostname(), + Port :: inet:port_number(), + Opts :: [Opt :: option()], + Assoc :: #sctp_assoc_change{}. + connect(S, Addr, Port, Opts) -> connect(S, Addr, Port, Opts, infinity). +-spec connect(Socket, Addr, Port, Opts, Timeout) -> + {ok, Assoc} | {error, inet:posix()} when + Socket :: sctp_socket(), + Addr :: inet:ip_address() | inet:hostname(), + Port :: inet:port_number(), + Opts :: [Opt :: option()], + Timeout :: timeout(), + Assoc :: #sctp_assoc_change{}. + connect(S, Addr, Port, Opts, Timeout) -> case do_connect(S, Addr, Port, Opts, Timeout, true) of badarg -> @@ -88,9 +225,24 @@ connect(S, Addr, Port, Opts, Timeout) -> Result end. +-spec connect_init(Socket, Addr, Port, Opts) -> + ok | {error, inet:posix()} when + Socket :: sctp_socket(), + Addr :: inet:ip_address() | inet:hostname(), + Port :: inet:port_number(), + Opts :: [option()]. + connect_init(S, Addr, Port, Opts) -> connect_init(S, Addr, Port, Opts, infinity). +-spec connect_init(Socket, Addr, Port, Opts, Timeout) -> + ok | {error, inet:posix()} when + Socket :: sctp_socket(), + Addr :: inet:ip_address() | inet:hostname(), + Port :: inet:port_number(), + Opts :: [option()], + Timeout :: timeout(). + connect_init(S, Addr, Port, Opts, Timeout) -> case do_connect(S, Addr, Port, Opts, Timeout, false) of badarg -> @@ -130,12 +282,20 @@ do_connect(_S, _Addr, _Port, _Opts, _Timeout, _ConnWait) -> badarg. +-spec eof(Socket, Assoc) -> ok | {error, Reason} when + Socket :: sctp_socket(), + Assoc :: #sctp_assoc_change{}, + Reason :: term(). eof(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) -> eof_or_abort(S, AssocId, eof); eof(S, Assoc) -> erlang:error(badarg, [S,Assoc]). +-spec abort(Socket, Assoc) -> ok | {error, inet:posix()} when + Socket :: sctp_socket(), + Assoc :: #sctp_assoc_change{}. + abort(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) -> eof_or_abort(S, AssocId, abort); abort(S, Assoc) -> @@ -151,6 +311,11 @@ eof_or_abort(S, AssocId, Action) -> end. +-spec send(Socket, SndRcvInfo, Data) -> ok | {error, Reason} when + Socket :: sctp_socket(), + SndRcvInfo :: #sctp_sndrcvinfo{}, + Data :: binary | iolist(), + Reason :: term(). %% Full-featured send. Rarely needed. send(S, #sctp_sndrcvinfo{}=SRI, Data) when is_port(S) -> @@ -162,6 +327,13 @@ send(S, #sctp_sndrcvinfo{}=SRI, Data) when is_port(S) -> send(S, SRI, Data) -> erlang:error(badarg, [S,SRI,Data]). +-spec send(Socket, Assoc, Stream, Data) -> ok | {error, Reason} when + Socket :: sctp_socket(), + Assoc :: #sctp_assoc_change{} | assoc_id(), + Stream :: integer(), + Data :: binary | iolist(), + Reason :: term(). + send(S, #sctp_assoc_change{assoc_id=AssocId}, Stream, Data) when is_port(S), is_integer(Stream) -> case inet_db:lookup_socket(S) of @@ -179,9 +351,36 @@ send(S, AssocId, Stream, Data) send(S, AssocChange, Stream, Data) -> erlang:error(badarg, [S,AssocChange,Stream,Data]). +-spec recv(Socket) -> {ok, {FromIP, FromPort, AncData, Data}} + | {error, Reason} when + Socket :: sctp_socket(), + FromIP :: inet:ip_address(), + FromPort :: inet:port_number(), + AncData :: [#sctp_sndrcvinfo{}], + Data :: binary() | string() | #sctp_sndrcvinfo{} + | #sctp_assoc_change{} | #sctp_paddr_change{} + | #sctp_adaptation_event{}, + Reason :: inet:posix() | #sctp_send_failed{} | #sctp_paddr_change{} + | #sctp_pdapi_event{} | #sctp_remote_error{} + | #sctp_shutdown_event{}. + recv(S) -> recv(S, infinity). +-spec recv(Socket, Timeout) -> {ok, {FromIP, FromPort, AncData, Data}} + | {error, Reason} when + Socket :: sctp_socket(), + Timeout :: timeout(), + FromIP :: inet:ip_address(), + FromPort :: inet:port_number(), + AncData :: [#sctp_sndrcvinfo{}], + Data :: binary() | string() | #sctp_sndrcvinfo{} + | #sctp_assoc_change{} | #sctp_paddr_change{} + | #sctp_adaptation_event{}, + Reason :: inet:posix() | #sctp_send_failed{} | #sctp_paddr_change{} + | #sctp_pdapi_event{} | #sctp_remote_error{} + | #sctp_shutdown_event{}. + recv(S, Timeout) when is_port(S) -> case inet_db:lookup_socket(S) of {ok,Mod} -> @@ -192,6 +391,8 @@ recv(S, Timeout) -> erlang:error(badarg, [S,Timeout]). +-spec error_string(ErrorNumber) -> ok | string() | unknown_error when + ErrorNumber :: integer(). error_string(0) -> ok; @@ -224,6 +425,9 @@ error_string(X) -> erlang:error(badarg, [X]). +-spec controlling_process(Socket, Pid) -> ok when + Socket :: sctp_socket(), + Pid :: pid(). controlling_process(S, Pid) when is_port(S), is_pid(Pid) -> inet:udp_controlling_process(S, Pid); diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl index 16a87d71b6..8ab18c01b4 100644 --- a/lib/kernel/src/gen_tcp.erl +++ b/lib/kernel/src/gen_tcp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -28,12 +28,109 @@ -include("inet_int.hrl"). +-type option() :: + {active, true | false | once} | + {bit8, clear | set | on | off} | + {buffer, non_neg_integer()} | + {delay_send, boolean()} | + {deliver, port | term} | + {dontroute, boolean()} | + {exit_on_close, boolean()} | + {header, non_neg_integer()} | + {high_watermark, non_neg_integer()} | + {keepalive, boolean()} | + {linger, {boolean(), non_neg_integer()}} | + {low_watermark, non_neg_integer()} | + {mode, list | binary} | list | binary | + {nodelay, boolean()} | + {packet, + 0 | 1 | 2 | 4 | raw | sunrm | asn1 | + cdr | fcgi | line | tpkt | http | httph | http_bin | httph_bin } | + {packet_size, non_neg_integer()} | + {priority, non_neg_integer()} | + {raw, + Protocol :: non_neg_integer(), + OptionNum :: non_neg_integer(), + ValueBin :: binary()} | + {recbuf, non_neg_integer()} | + {reuseaddr, boolean()} | + {send_timeout, non_neg_integer() | infinity} | + {send_timeout_close, boolean()} | + {sndbuf, non_neg_integer()} | + {tos, non_neg_integer()}. +-type option_name() :: + active | + bit8 | + buffer | + delay_send | + deliver | + dontroute | + exit_on_close | + header | + high_watermark | + keepalive | + linger | + low_watermark | + mode | + nodelay | + packet | + packet_size | + priority | + {raw, + Protocol :: non_neg_integer(), + OptionNum :: non_neg_integer(), + ValueSpec :: (ValueSize :: non_neg_integer()) | + (ValueBin :: binary())} | + recbuf | + reuseaddr | + send_timeout | + send_timeout_close | + sndbuf | + tos. +-type connect_option() :: + {ip, inet:ip_address()} | + {fd, Fd :: non_neg_integer()} | + {ifaddr, inet:ip_address()} | + inet:address_family() | + {port, inet:port_number()} | + {tcp_module, module()} | + option(). +-type listen_option() :: + {ip, inet:ip_address()} | + {fd, Fd :: non_neg_integer()} | + {ifaddr, inet:ip_address()} | + inet:address_family() | + {port, inet:port_number()} | + {backlog, B :: non_neg_integer()} | + {tcp_module, module()} | + option(). +-type socket() :: port(). + +-export_type([option/0, option_name/0, connect_option/0, listen_option/0]). + %% %% Connect a socket %% + +-spec connect(Address, Port, Options) -> {ok, Socket} | {error, Reason} when + Address :: inet:ip_address() | inet:hostname(), + Port :: inet:port_number(), + Options :: [connect_option()], + Socket :: socket(), + Reason :: inet:posix(). + connect(Address, Port, Opts) -> connect(Address,Port,Opts,infinity). +-spec connect(Address, Port, Options, Timeout) -> + {ok, Socket} | {error, Reason} when + Address :: inet:ip_address() | inet:hostname(), + Port :: inet:port_number(), + Options :: [connect_option()], + Timeout :: timeout(), + Socket :: socket(), + Reason :: inet:posix(). + connect(Address, Port, Opts, Time) -> Timer = inet:start_timer(Time), Res = (catch connect1(Address,Port,Opts,Timer)), @@ -72,6 +169,13 @@ try_connect([], _Port, _Opts, _Timer, _Mod, Err) -> %% %% Listen on a tcp port %% + +-spec listen(Port, Options) -> {ok, ListenSocket} | {error, Reason} when + Port :: inet:port_number(), + Options :: [listen_option()], + ListenSocket :: socket(), + Reason :: inet:posix(). + listen(Port, Opts) -> Mod = mod(Opts, undefined), case Mod:getserv(Port) of @@ -85,6 +189,12 @@ listen(Port, Opts) -> %% %% Generic tcp accept %% + +-spec accept(ListenSocket) -> {ok, Socket} | {error, Reason} when + ListenSocket :: socket(), + Socket :: socket(), + Reason :: closed | timeout | inet:posix(). + accept(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -93,6 +203,12 @@ accept(S) -> Error end. +-spec accept(ListenSocket, Timeout) -> {ok, Socket} | {error, Reason} when + ListenSocket :: socket(), + Timeout :: timeout(), + Socket :: socket(), + Reason :: closed | timeout | inet:posix(). + accept(S, Time) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -104,6 +220,12 @@ accept(S, Time) when is_port(S) -> %% %% Generic tcp shutdown %% + +-spec shutdown(Socket, How) -> ok | {error, Reason} when + Socket :: socket(), + How :: read | write | read_write, + Reason :: inet:posix(). + shutdown(S, How) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -115,12 +237,22 @@ shutdown(S, How) when is_port(S) -> %% %% Close %% + +-spec close(Socket) -> ok when + Socket :: socket(). + close(S) -> inet:tcp_close(S). %% %% Send %% + +-spec send(Socket, Packet) -> ok | {error, Reason} when + Socket :: socket(), + Packet :: iodata(), + Reason :: inet:posix(). + send(S, Packet) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -132,6 +264,14 @@ send(S, Packet) when is_port(S) -> %% %% Receive data from a socket (passive mode) %% + +-spec recv(Socket, Length) -> {ok, Packet} | {error, Reason} when + Socket :: socket(), + Length :: non_neg_integer(), + Packet :: string() | binary() | HttpPacket, + Reason :: closed | inet:posix(), + HttpPacket :: term(). + recv(S, Length) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -140,6 +280,14 @@ recv(S, Length) when is_port(S) -> Error end. +-spec recv(Socket, Length, Timeout) -> {ok, Packet} | {error, Reason} when + Socket :: socket(), + Length :: non_neg_integer(), + Timeout :: timeout(), + Packet :: string() | binary() | HttpPacket, + Reason :: closed | inet:posix(), + HttpPacket :: term(). + recv(S, Length, Time) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -159,6 +307,12 @@ unrecv(S, Data) when is_port(S) -> %% %% Set controlling process %% + +-spec controlling_process(Socket, Pid) -> ok | {error, Reason} when + Socket :: socket(), + Pid :: pid(), + Reason :: closed | not_owner | inet:posix(). + controlling_process(S, NewOwner) -> case inet_db:lookup_socket(S) of {ok, _Mod} -> % Just check that this is an open socket diff --git a/lib/kernel/src/gen_udp.erl b/lib/kernel/src/gen_udp.erl index 99020c7b6c..8688799ae9 100644 --- a/lib/kernel/src/gen_udp.erl +++ b/lib/kernel/src/gen_udp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -25,17 +25,93 @@ -include("inet_int.hrl"). +-type option() :: + {active, true | false | once} | + {add_membership, {inet:ip_address(), inet:ip_address()}} | + {broadcast, boolean()} | + {buffer, non_neg_integer()} | + {deliver, port | term} | + {dontroute, boolean()} | + {drop_membership, {inet:ip_address(), inet:ip_address()}} | + {header, non_neg_integer()} | + {mode, list | binary} | list | binary | + {multicast_if, inet:ip_address()} | + {multicast_loop, boolean()} | + {multicast_ttl, non_neg_integer()} | + {priority, non_neg_integer()} | + {raw, + Protocol :: non_neg_integer(), + OptionNum :: non_neg_integer(), + ValueBin :: binary()} | + {read_packets, non_neg_integer()} | + {recbuf, non_neg_integer()} | + {reuseaddr, boolean()} | + {sndbuf, non_neg_integer()} | + {tos, non_neg_integer()}. +-type option_name() :: + active | + broadcast | + buffer | + deliver | + dontroute | + header | + mode | + multicast_if | + multicast_loop | + multicast_ttl | + priority | + {raw, + Protocol :: non_neg_integer(), + OptionNum :: non_neg_integer(), + ValueSpec :: (ValueSize :: non_neg_integer()) | + (ValueBin :: binary())} | + read_packets | + recbuf | + reuseaddr | + sndbuf | + tos. +-type socket() :: port(). + +-export_type([option/0, option_name/0]). + +-spec open(Port) -> {ok, Socket} | {error, Reason} when + Port :: inet:port_number(), + Socket :: socket(), + Reason :: inet:posix(). + open(Port) -> open(Port, []). +-spec open(Port, Opts) -> {ok, Socket} | {error, Reason} when + Port :: inet:port_number(), + Opts :: [Option], + Option :: {ip, inet:ip_address()} + | {fd, non_neg_integer()} + | {ifaddr, inet:ip_address()} + | inet:address_family() + | {port, inet:port_number()} + | option(), + Socket :: socket(), + Reason :: inet:posix(). + open(Port, Opts) -> Mod = mod(Opts, undefined), {ok,UP} = Mod:getserv(Port), Mod:open(UP, Opts). +-spec close(Socket) -> ok when + Socket :: socket(). + close(S) -> inet:udp_close(S). +-spec send(Socket, Address, Port, Packet) -> ok | {error, Reason} when + Socket :: socket(), + Address :: inet:ip_address() | inet:hostname(), + Port :: inet:port_number(), + Packet :: iodata(), + Reason :: not_owner | inet:posix(). + send(S, Address, Port, Packet) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -61,6 +137,15 @@ send(S, Packet) when is_port(S) -> Error end. +-spec recv(Socket, Length) -> + {ok, {Address, Port, Packet}} | {error, Reason} when + Socket :: socket(), + Length :: non_neg_integer(), + Address :: inet:ip_address(), + Port :: inet:port_number(), + Packet :: string() | binary(), + Reason :: not_owner | inet:posix(). + recv(S,Len) when is_port(S), is_integer(Len) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -69,6 +154,16 @@ recv(S,Len) when is_port(S), is_integer(Len) -> Error end. +-spec recv(Socket, Length, Timeout) -> + {ok, {Address, Port, Packet}} | {error, Reason} when + Socket :: socket(), + Length :: non_neg_integer(), + Timeout :: timeout(), + Address :: inet:ip_address(), + Port :: inet:port_number(), + Packet :: string() | binary(), + Reason :: not_owner | inet:posix(). + recv(S,Len,Time) when is_port(S) -> case inet_db:lookup_socket(S) of {ok, Mod} -> @@ -90,6 +185,10 @@ connect(S, Address, Port) when is_port(S) -> Error end. +-spec controlling_process(Socket, Pid) -> ok when + Socket :: socket(), + Pid :: pid(). + controlling_process(S, NewOwner) -> inet:udp_controlling_process(S, NewOwner). diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl index 6343acd000..fa97614eca 100644 --- a/lib/kernel/src/global.erl +++ b/lib/kernel/src/global.erl @@ -28,7 +28,7 @@ %% External exports -export([start/0, start_link/0, stop/0, sync/0, sync/1, - safe_whereis_name/1, whereis_name/1, register_name/2, + whereis_name/1, register_name/2, register_name/3, register_name_external/2, register_name_external/3, unregister_name_external/1,re_register_name/2, re_register_name/3, unregister_name/1, registered_names/0, send/2, node_disconnected/1, @@ -166,7 +166,7 @@ start_link() -> stop() -> gen_server:call(global_name_server, stop, infinity). --spec sync() -> 'ok' | {'error', term()}. +-spec sync() -> 'ok' | {'error', Reason :: term()}. sync() -> case check_sync_nodes() of {error, _} = Error -> @@ -175,7 +175,7 @@ sync() -> gen_server:call(global_name_server, {sync, SyncNodes}, infinity) end. --spec sync([node()]) -> 'ok' | {'error', term()}. +-spec sync([node()]) -> 'ok' | {'error', Reason :: term()}. sync(Nodes) -> case check_sync_nodes(Nodes) of {error, _} = Error -> @@ -184,7 +184,10 @@ sync(Nodes) -> gen_server:call(global_name_server, {sync, SyncNodes}, infinity) end. --spec send(term(), term()) -> pid(). +-spec send(Name, Msg) -> Pid when + Name :: term(), + Msg :: term(), + Pid :: pid(). send(Name, Msg) -> case whereis_name(Name) of Pid when is_pid(Pid) -> @@ -195,14 +198,11 @@ send(Name, Msg) -> end. %% See OTP-3737. --spec whereis_name(term()) -> pid() | 'undefined'. +-spec whereis_name(Name) -> pid() | 'undefined' when + Name :: term(). whereis_name(Name) -> where(Name). --spec safe_whereis_name(term()) -> pid() | 'undefined'. -safe_whereis_name(Name) -> - gen_server:call(global_name_server, {whereis, Name}, infinity). - node_disconnected(Node) -> global_name_server ! {nodedown, Node}. @@ -219,13 +219,19 @@ node_disconnected(Node) -> %% undefined which one of them is used. %% Method blocks the name registration, but does not affect global locking. %%----------------------------------------------------------------- --spec register_name(term(), pid()) -> 'yes' | 'no'. +-spec register_name(Name, Pid) -> 'yes' | 'no' when + Name :: term(), + Pid :: pid(). register_name(Name, Pid) when is_pid(Pid) -> register_name(Name, Pid, fun random_exit_name/3). --type method() :: fun((term(), pid(), pid()) -> pid() | 'none'). +-type method() :: fun((Name :: term(), Pid :: pid(), Pid2 :: pid()) -> + pid() | 'none'). --spec register_name(term(), pid(), method()) -> 'yes' | 'no'. +-spec register_name(Name, Pid, Resolve) -> 'yes' | 'no' when + Name :: term(), + Pid :: pid(), + Resolve :: method(). register_name(Name, Pid, Method) when is_pid(Pid) -> Fun = fun(Nodes) -> case (where(Name) =:= undefined) andalso check_dupname(Name, Pid) of @@ -257,7 +263,8 @@ check_dupname(Name, Pid) -> end end. --spec unregister_name(term()) -> _. +-spec unregister_name(Name) -> _ when + Name :: term(). unregister_name(Name) -> case where(Name) of undefined -> @@ -273,11 +280,16 @@ unregister_name(Name) -> gen_server:call(global_name_server, {registrar, Fun}, infinity) end. --spec re_register_name(term(), pid()) -> _. +-spec re_register_name(Name, Pid) -> _ when + Name :: term(), + Pid :: pid(). re_register_name(Name, Pid) when is_pid(Pid) -> re_register_name(Name, Pid, fun random_exit_name/3). --spec re_register_name(term(), pid(), method()) -> _. +-spec re_register_name(Name, Pid, Resolve) -> _ when + Name :: term(), + Pid :: pid(), + Resolve :: method(). re_register_name(Name, Pid, Method) when is_pid(Pid) -> Fun = fun(Nodes) -> gen_server:multi_call(Nodes, @@ -288,7 +300,8 @@ re_register_name(Name, Pid, Method) when is_pid(Pid) -> ?trace({re_register_name, self(), Name, Pid, Method}), gen_server:call(global_name_server, {registrar, Fun}, infinity). --spec registered_names() -> [term()]. +-spec registered_names() -> [Name] when + Name :: term(). registered_names() -> MS = ets:fun2ms(fun({Name,_Pid,_M,_RP,_R}) -> Name end), ets:select(global_names, MS). @@ -329,19 +342,25 @@ register_name_external(Name, Pid, Method) when is_pid(Pid) -> unregister_name_external(Name) -> unregister_name(Name). --type id() :: {term(), term()}. +-type id() :: {ResourceId :: term(), LockRequesterId :: term()}. --spec set_lock(id()) -> boolean(). +-spec set_lock(Id) -> boolean() when + Id :: id(). set_lock(Id) -> set_lock(Id, [node() | nodes()], infinity, 1). -type retries() :: non_neg_integer() | 'infinity'. --spec set_lock(id(), [node()]) -> boolean(). +-spec set_lock(Id, Nodes) -> boolean() when + Id :: id(), + Nodes :: [node()]. set_lock(Id, Nodes) -> set_lock(Id, Nodes, infinity, 1). --spec set_lock(id(), [node()], retries()) -> boolean(). +-spec set_lock(Id, Nodes, Retries) -> boolean() when + Id :: id(), + Nodes :: [node()], + Retries :: retries(). set_lock(Id, Nodes, Retries) when is_integer(Retries), Retries >= 0 -> set_lock(Id, Nodes, Retries, 1); set_lock(Id, Nodes, infinity) -> @@ -363,11 +382,14 @@ set_lock({_ResourceId, _LockRequesterId} = Id, Nodes, Retries, Times) -> set_lock(Id, Nodes, dec(Retries), Times+1) end. --spec del_lock(id()) -> 'true'. +-spec del_lock(Id) -> 'true' when + Id :: id(). del_lock(Id) -> del_lock(Id, [node() | nodes()]). --spec del_lock(id(), [node()]) -> 'true'. +-spec del_lock(Id, Nodes) -> 'true' when + Id :: id(), + Nodes :: [node()]. del_lock({_ResourceId, _LockRequesterId} = Id, Nodes) -> ?trace({del_lock, {me,self()}, Id, {nodes,Nodes}}), gen_server:multi_call(Nodes, global_name_server, {del_lock, Id}), @@ -375,13 +397,25 @@ del_lock({_ResourceId, _LockRequesterId} = Id, Nodes) -> -type trans_fun() :: function() | {module(), atom()}. --spec trans(id(), trans_fun()) -> term(). +-spec trans(Id, Fun) -> Res | aborted when + Id :: id(), + Fun :: trans_fun(), + Res :: term(). trans(Id, Fun) -> trans(Id, Fun, [node() | nodes()], infinity). --spec trans(id(), trans_fun(), [node()]) -> term(). +-spec trans(Id, Fun, Nodes) -> Res | aborted when + Id :: id(), + Fun :: trans_fun(), + Nodes :: [node()], + Res :: term(). trans(Id, Fun, Nodes) -> trans(Id, Fun, Nodes, infinity). --spec trans(id(), trans_fun(), [node()], retries()) -> term(). +-spec trans(Id, Fun, Nodes, Retries) -> Res | aborted when + Id :: id(), + Fun :: trans_fun(), + Nodes :: [node()], + Retries :: retries(), + Res :: term(). trans(Id, Fun, Nodes, Retries) -> case set_lock(Id, Nodes, Retries) of true -> @@ -472,8 +506,7 @@ init([]) -> %% delay can sometimes be quite substantial. Global guarantees that %% the name will eventually be removed, but there is no %% synchronization between nodes; the name can be removed from some -%% node(s) long before it is removed from other nodes. Using -%% safe_whereis_name is no cure. +%% node(s) long before it is removed from other nodes. %% %% - Global cannot handle problems with the distribution very well. %% Depending on the value of the kernel variable 'net_ticktime' long @@ -551,10 +584,6 @@ init([]) -> {'reply', term(), state()} | {'stop', 'normal', 'stopped', state()}. -handle_call({whereis, Name}, From, S) -> - do_whereis(Name, From), - {noreply, S}; - handle_call({registrar, Fun}, From, S) -> S#state.the_registrar ! {trans_all_known, Fun, From}, {noreply, S}; @@ -1197,7 +1226,15 @@ ins_name_ext(Name, Pid, Method, RegNode, FromPidOrNode, ExtraInfo, S0) -> where(Name) -> case ets:lookup(global_names, Name) of - [{_Name, Pid, _Method, _RPid, _Ref}] -> Pid; + [{_Name, Pid, _Method, _RPid, _Ref}] -> + if node(Pid) == node() -> + case is_process_alive(Pid) of + true -> Pid; + false -> undefined + end; + true -> + Pid + end; [] -> undefined end. @@ -1928,7 +1965,10 @@ resolve_it(Method, Name, Pid1, Pid2) -> minmax(P1,P2) -> if node(P1) < node(P2) -> {P1, P2}; true -> {P2, P1} end. --spec random_exit_name(term(), pid(), pid()) -> pid(). +-spec random_exit_name(Name, Pid1, Pid2) -> 'none' when + Name :: term(), + Pid1 :: pid(), + Pid2 :: pid(). random_exit_name(Name, Pid, Pid2) -> {Min, Max} = minmax(Pid, Pid2), error_logger:info_msg("global: Name conflict terminating ~w\n", @@ -1936,12 +1976,19 @@ random_exit_name(Name, Pid, Pid2) -> exit(Max, kill), Min. +-spec random_notify_name(Name, Pid1, Pid2) -> 'none' when + Name :: term(), + Pid1 :: pid(), + Pid2 :: pid(). random_notify_name(Name, Pid, Pid2) -> {Min, Max} = minmax(Pid, Pid2), Max ! {global_name_conflict, Name}, Min. --spec notify_all_name(term(), pid(), pid()) -> 'none'. +-spec notify_all_name(Name, Pid1, Pid2) -> 'none' when + Name :: term(), + Pid1 :: pid(), + Pid2 :: pid(). notify_all_name(Name, Pid, Pid2) -> Pid ! {global_name_conflict, Name, Pid2}, Pid2 ! {global_name_conflict, Name, Pid}, diff --git a/lib/kernel/src/global_group.erl b/lib/kernel/src/global_group.erl index 7e141ac5c7..025a9b8a5b 100644 --- a/lib/kernel/src/global_group.erl +++ b/lib/kernel/src/global_group.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% Copyright Ericsson AB 1998-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -62,9 +62,10 @@ -type sync_state() :: 'no_conf' | 'synced'. -type group_name() :: atom(). --type group_tuple() :: {group_name(), [node()]} - | {group_name(), publish_type(), [node()]}. - +-type group_tuple() :: {GroupName :: group_name(), [node()]} + | {GroupName :: group_name(), + PublishType :: publish_type(), + [node()]}. %%%==================================================================================== %%% The state of the global_group process @@ -97,11 +98,14 @@ %%% External exported %%%==================================================================================== --spec global_groups() -> {group_name(), [group_name()]} | 'undefined'. +-spec global_groups() -> {GroupName, GroupNames} | undefined when + GroupName :: group_name(), + GroupNames :: [GroupName]. global_groups() -> request(global_groups). --spec monitor_nodes(boolean()) -> 'ok'. +-spec monitor_nodes(Flag) -> 'ok' when + Flag :: boolean(). monitor_nodes(Flag) -> case Flag of true -> request({monitor_nodes, Flag}); @@ -109,30 +113,41 @@ monitor_nodes(Flag) -> _ -> {error, not_boolean} end. --spec own_nodes() -> [node()]. +-spec own_nodes() -> Nodes when + Nodes :: [Node :: node()]. own_nodes() -> request(own_nodes). -type name() :: atom(). -type where() :: {'node', node()} | {'group', group_name()}. --spec registered_names(where()) -> [name()]. +-spec registered_names(Where) -> Names when + Where :: where(), + Names :: [Name :: name()]. registered_names(Arg) -> request({registered_names, Arg}). --spec send(name(), term()) -> pid() | {'badarg', {name(), term()}}. +-spec send(Name, Msg) -> pid() | {'badarg', {Name, Msg}} when + Name :: name(), + Msg :: term(). send(Name, Msg) -> request({send, Name, Msg}). --spec send(where(), name(), term()) -> pid() | {'badarg', {name(), term()}}. +-spec send(Where, Name, Msg) -> pid() | {'badarg', {Name, Msg}} when + Where :: where(), + Name :: name(), + Msg :: term(). send(Group, Name, Msg) -> request({send, Group, Name, Msg}). --spec whereis_name(name()) -> pid() | 'undefined'. +-spec whereis_name(Name) -> pid() | 'undefined' when + Name :: name(). whereis_name(Name) -> request({whereis_name, Name}). --spec whereis_name(where(), name()) -> pid() | 'undefined'. +-spec whereis_name(Where, Name) -> pid() | 'undefined' when + Where :: where(), + Name :: name(). whereis_name(Group, Name) -> request({whereis_name, Group, Name}). @@ -155,14 +170,14 @@ ng_add_check(Node, OthersNG) -> ng_add_check(Node, PubType, OthersNG) -> request({ng_add_check, Node, PubType, OthersNG}). --type info_item() :: {'state', sync_state()} - | {'own_group_name', group_name()} - | {'own_group_nodes', [node()]} - | {'synched_nodes', [node()]} - | {'sync_error', [node()]} - | {'no_contact', [node()]} - | {'other_groups', [group_tuple()]} - | {'monitoring', [pid()]}. +-type info_item() :: {'state', State :: sync_state()} + | {'own_group_name', GroupName :: group_name()} + | {'own_group_nodes', Nodes :: [node()]} + | {'synched_nodes', Nodes :: [node()]} + | {'sync_error', Nodes :: [node()]} + | {'no_contact', Nodes :: [node()]} + | {'other_groups', Groups :: [group_tuple()]} + | {'monitoring', Pids :: [pid()]}. -spec info() -> [info_item()]. info() -> @@ -1012,6 +1027,7 @@ grp_tuple({Name, normal, Nodes}) -> %%% The special process which checks that all nodes in the own global group %%% agrees on the configuration. %%%==================================================================================== +-spec sync_init(_, _, _, _) -> no_return(). sync_init(Type, Cname, PubType, Nodes) -> {Up, Down} = sync_check_node(lists:delete(node(), Nodes), [], []), sync_check_init(Type, Up, Cname, Nodes, Down, PubType). @@ -1032,9 +1048,11 @@ sync_check_node([Node|Nodes], Up, Down) -> %%% Check that all nodes are in agreement of the global %%% group configuration. %%%------------------------------------------------------------- +-spec sync_check_init(_, _, _, _, _, _) -> no_return(). sync_check_init(Type, Up, Cname, Nodes, Down, PubType) -> sync_check_init(Type, Up, Cname, Nodes, 3, [], Down, PubType). +-spec sync_check_init(_, _, _, _, _, _, _, _) -> no_return(). sync_check_init(_Type, NoContact, _Cname, _Nodes, 0, ErrorNodes, Down, _PubType) -> case ErrorNodes of [] -> diff --git a/lib/kernel/src/global_search.erl b/lib/kernel/src/global_search.erl index b723e18a1b..0bf53e29b8 100644 --- a/lib/kernel/src/global_search.erl +++ b/lib/kernel/src/global_search.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% Copyright Ericsson AB 1998-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -69,6 +69,7 @@ start(Flag, Arg) -> %%%==================================================================================== %%%==================================================================================== +-spec init_send(_) -> no_return(). init_send({any, NodesList, Name, Msg, From}) -> case whereis_any_loop(NodesList, Name) of undefined -> @@ -115,6 +116,7 @@ init_send({node, Node, Name, Msg, From}) -> %%%==================================================================================== %%%==================================================================================== +-spec init_whereis(_) -> no_return(). init_whereis({any, NodesList, Name, From}) -> R = whereis_any_loop(NodesList, Name), gen_server:cast(global_group, {find_name_res, R, self(), From}), @@ -146,6 +148,7 @@ init_whereis({node, Node, Name, From}) -> %%%==================================================================================== %%%==================================================================================== %%%==================================================================================== +-spec init_names(_) -> no_return(). init_names({group, Nodes, From}) -> case names_group_loop(Nodes) of group_down -> diff --git a/lib/kernel/src/heart.erl b/lib/kernel/src/heart.erl index e78acfc7a6..255ae4e51b 100644 --- a/lib/kernel/src/heart.erl +++ b/lib/kernel/src/heart.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -85,19 +85,21 @@ init(Starter, Parent) -> Starter ! {start_error, self()} end. --spec set_cmd(string()) -> 'ok' | {'error', {'bad_cmd', string()}}. +-spec set_cmd(Cmd) -> 'ok' | {'error', {'bad_cmd', Cmd}} when + Cmd :: string(). set_cmd(Cmd) -> heart ! {self(), set_cmd, Cmd}, wait(). --spec get_cmd() -> 'ok'. +-spec get_cmd() -> {ok, Cmd} when + Cmd :: string(). get_cmd() -> heart ! {self(), get_cmd}, wait(). --spec clear_cmd() -> {'ok', string()}. +-spec clear_cmd() -> ok. clear_cmd() -> heart ! {self(), clear_cmd}, diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 327e0f93f1..b60c68e3a1 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -36,7 +36,7 @@ -export([i/0, i/1, i/2]). --export([getll/1, getfd/1, open/7, fdopen/5]). +-export([getll/1, getfd/1, open/8, fdopen/6]). -export([tcp_controlling_process/2, udp_controlling_process/2, tcp_close/1, udp_close/1]). @@ -63,7 +63,9 @@ %% timer interface -export([start_timer/1, timeout/1, timeout/2, stop_timer/1]). --export_type([ip_address/0, socket/0]). +-export_type([address_family/0, hostent/0, hostname/0, ip4_address/0, + ip6_address/0, ip_address/0, posix/0, socket/0, + port_number/0]). %% imports -import(lists, [append/1, duplicate/2, filter/2, foldl/3]). @@ -79,97 +81,22 @@ %%% --------------------------------- %%% Contract type definitions + +-type hostent() :: #hostent{}. +-type hostname() :: atom() | string(). +-type ip4_address() :: {0..255,0..255,0..255,0..255}. +-type ip6_address() :: {0..65535,0..65535,0..65535,0..65535, + 0..65535,0..65535,0..65535,0..65535}. +-type ip_address() :: ip4_address() | ip6_address(). +-type port_number() :: 0..65535. +-type posix() :: exbadport | exbadseq | file:posix(). -type socket() :: port(). --type posix() :: atom(). -type socket_setopt() :: - {'raw', non_neg_integer(), non_neg_integer(), binary()} | - %% TCP/UDP options - {'reuseaddr', boolean()} | - {'keepalive', boolean()} | - {'dontroute', boolean()} | - {'linger', {boolean(), non_neg_integer()}} | - {'broadcast', boolean()} | - {'sndbuf', non_neg_integer()} | - {'recbuf', non_neg_integer()} | - {'priority', non_neg_integer()} | - {'tos', non_neg_integer()} | - {'nodelay', boolean()} | - {'multicast_ttl', non_neg_integer()} | - {'multicast_loop', boolean()} | - {'multicast_if', ip_address()} | - {'add_membership', {ip_address(), ip_address()}} | - {'drop_membership', {ip_address(), ip_address()}} | - {'header', non_neg_integer()} | - {'buffer', non_neg_integer()} | - {'active', boolean() | 'once'} | - {'packet', - 0 | 1 | 2 | 4 | 'raw' | 'sunrm' | 'asn1' | - 'cdr' | 'fcgi' | 'line' | 'tpkt' | 'http' | 'httph' | 'http_bin' | 'httph_bin' } | - {'mode', list() | binary()} | - {'port', 'port', 'term'} | - {'exit_on_close', boolean()} | - {'low_watermark', non_neg_integer()} | - {'high_watermark', non_neg_integer()} | - {'bit8', 'clear' | 'set' | 'on' | 'off'} | - {'send_timeout', non_neg_integer() | 'infinity'} | - {'send_timeout_close', boolean()} | - {'delay_send', boolean()} | - {'packet_size', non_neg_integer()} | - {'read_packets', non_neg_integer()} | - %% SCTP options - {'sctp_rtoinfo', #sctp_rtoinfo{}} | - {'sctp_associnfo', #sctp_assocparams{}} | - {'sctp_initmsg', #sctp_initmsg{}} | - {'sctp_nodelay', boolean()} | - {'sctp_autoclose', non_neg_integer()} | - {'sctp_disable_fragments', boolean()} | - {'sctp_i_want_mapped_v4_addr', boolean()} | - {'sctp_maxseg', non_neg_integer()} | - {'sctp_primary_addr', #sctp_prim{}} | - {'sctp_set_peer_primary_addr', #sctp_setpeerprim{}} | - {'sctp_adaptation_layer', #sctp_setadaptation{}} | - {'sctp_peer_addr_params', #sctp_paddrparams{}} | - {'sctp_default_send_param', #sctp_sndrcvinfo{}} | - {'sctp_events', #sctp_event_subscribe{}} | - {'sctp_delayed_ack_time', #sctp_assoc_value{}}. + gen_sctp:option() | gen_tcp:option() | gen_udp:option(). -type socket_getopt() :: - {'raw', - non_neg_integer(), non_neg_integer(), binary()|non_neg_integer()} | - %% TCP/UDP options - 'reuseaddr' | 'keepalive' | 'dontroute' | 'linger' | - 'broadcast' | 'sndbuf' | 'recbuf' | 'priority' | 'tos' | 'nodelay' | - 'multicast_ttl' | 'multicast_loop' | 'multicast_if' | - 'add_membership' | 'drop_membership' | - 'header' | 'buffer' | 'active' | 'packet' | 'mode' | 'port' | - 'exit_on_close' | 'low_watermark' | 'high_watermark' | 'bit8' | - 'send_timeout' | 'send_timeout_close' | - 'delay_send' | 'packet_size' | 'read_packets' | - %% SCTP options - {'sctp_status', #sctp_status{}} | - 'sctp_get_peer_addr_info' | - {'sctp_get_peer_addr_info', #sctp_status{}} | - 'sctp_rtoinfo' | - {'sctp_rtoinfo', #sctp_rtoinfo{}} | - 'sctp_associnfo' | - {'sctp_associnfo', #sctp_assocparams{}} | - 'sctp_initmsg' | - {'sctp_initmsg', #sctp_initmsg{}} | - 'sctp_nodelay' | 'sctp_autoclose' | 'sctp_disable_fragments' | - 'sctp_i_want_mapped_v4_addr' | 'sctp_maxseg' | - {'sctp_primary_addr', #sctp_prim{}} | - {'sctp_set_peer_primary_addr', #sctp_setpeerprim{}} | - 'sctp_adaptation_layer' | - {'sctp_adaptation_layer', #sctp_setadaptation{}} | - {'sctp_peer_addr_params', #sctp_paddrparams{}} | - 'sctp_default_send_param' | - {'sctp_default_send_param', #sctp_sndrcvinfo{}} | - 'sctp_events' | - {'sctp_events', #sctp_event_subscribe{}} | - 'sctp_delayed_ack_time' | - {'sctp_delayed_ack_time', #sctp_assoc_value{}}. - + gen_sctp:option_name() | gen_tcp:option_name() | gen_udp:option_name(). -type ether_address() :: [0..255]. -type if_setopt() :: @@ -187,20 +114,22 @@ 'addr' | 'broadaddr' | 'dstaddr' | 'mtu' | 'netmask' | 'flags' |'hwaddr'. --type family_option() :: 'inet' | 'inet6'. --type protocol_option() :: 'tcp' | 'udp' | 'sctp'. +-type address_family() :: 'inet' | 'inet6'. +-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'. +-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'. -type stat_option() :: 'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' | 'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'. %%% --------------------------------- --spec get_rc() -> [{any(),any()}]. +-spec get_rc() -> [{Par :: any(), Val :: any()}]. get_rc() -> inet_db:get_rc(). --spec close(Socket :: socket()) -> 'ok'. +-spec close(Socket) -> 'ok' when + Socket :: socket(). close(Socket) -> prim_inet:close(Socket), @@ -211,13 +140,15 @@ close(Socket) -> ok end. --spec peername(Socket :: socket()) -> - {'ok', {ip_address(), non_neg_integer()}} | {'error', posix()}. +-spec peername(Socket) -> {ok, {Address, Port}} | {error, posix()} when + Socket :: socket(), + Address :: ip_address(), + Port :: non_neg_integer(). peername(Socket) -> prim_inet:peername(Socket). --spec setpeername(Socket :: socket(), Address :: {ip_address(), ip_port()}) -> +-spec setpeername(Socket :: socket(), Address :: {ip_address(), port_number()}) -> 'ok' | {'error', any()}. setpeername(Socket, {IP,Port}) -> @@ -226,13 +157,15 @@ setpeername(Socket, undefined) -> prim_inet:setpeername(Socket, undefined). --spec sockname(Socket :: socket()) -> - {'ok', {ip_address(), non_neg_integer()}} | {'error', posix()}. +-spec sockname(Socket) -> {ok, {Address, Port}} | {error, posix()} when + Socket :: socket(), + Address :: ip_address(), + Port :: non_neg_integer(). sockname(Socket) -> prim_inet:sockname(Socket). --spec setsockname(Socket :: socket(), Address :: {ip_address(), ip_port()}) -> +-spec setsockname(Socket :: socket(), Address :: {ip_address(), port_number()}) -> 'ok' | {'error', any()}. setsockname(Socket, {IP,Port}) -> @@ -240,7 +173,9 @@ setsockname(Socket, {IP,Port}) -> setsockname(Socket, undefined) -> prim_inet:setsockname(Socket, undefined). --spec port(Socket :: socket()) -> {'ok', ip_port()} | {'error', any()}. +-spec port(Socket) -> {'ok', Port} | {'error', any()} when + Socket :: socket(), + Port :: port_number(). port(Socket) -> case prim_inet:sockname(Socket) of @@ -254,14 +189,18 @@ port(Socket) -> send(Socket, Packet) -> prim_inet:send(Socket, Packet). --spec setopts(Socket :: socket(), Opts :: [socket_setopt()]) -> - 'ok' | {'error', posix()}. +-spec setopts(Socket, Options) -> ok | {error, posix()} when + Socket :: socket(), + Options :: [socket_setopt()]. setopts(Socket, Opts) -> prim_inet:setopts(Socket, Opts). --spec getopts(Socket :: socket(), Opts :: [socket_getopt()]) -> - {'ok', [socket_setopt()]} | {'error', posix()}. +-spec getopts(Socket, Options) -> + {'ok', OptionValues} | {'error', posix()} when + Socket :: socket(), + Options :: [socket_getopt()], + OptionValues :: [socket_setopt()]. getopts(Socket, Opts) -> prim_inet:getopts(Socket, Opts). @@ -272,7 +211,19 @@ getopts(Socket, Opts) -> getifaddrs(Socket) -> prim_inet:getifaddrs(Socket). --spec getifaddrs() -> {'ok', [string()]} | {'error', posix()}. +-spec getifaddrs() -> {ok, Iflist} | {error, posix()} when + Iflist :: [{Ifname,[Ifopt]}], + Ifname :: string(), + Ifopt :: {flag,[Flag]} | {addr,Addr} | {netmask,Netmask} + | {broadaddr,Broadaddr} | {dstaddr,Dstaddr} + | {hwaddr,Hwaddr}, + Flag :: up | broadcast | loopback | pointtopoint + | running | multicast, + Addr :: ip_address(), + Netmask :: ip_address(), + Broadaddr :: ip_address(), + Dstaddr :: ip_address(), + Hwaddr :: [byte()]. getifaddrs() -> withsocket(fun(S) -> prim_inet:getifaddrs(S) end). @@ -371,7 +322,8 @@ popf(_Socket) -> % use of the DHCP-protocol % should never fail --spec gethostname() -> {'ok', string()}. +-spec gethostname() -> {'ok', Hostname} when + Hostname :: string(). gethostname() -> case inet_udp:open(0,[]) of @@ -390,32 +342,41 @@ gethostname() -> gethostname(Socket) -> prim_inet:gethostname(Socket). --spec getstat(Socket :: socket()) -> - {'ok', [{stat_option(), integer()}]} | {'error', posix()}. +-spec getstat(Socket) -> + {ok, OptionValues} | {error, posix()} when + Socket :: socket(), + OptionValues :: [{stat_option(), integer()}]. getstat(Socket) -> prim_inet:getstat(Socket, stats()). --spec getstat(Socket :: socket(), Statoptions :: [stat_option()]) -> - {'ok', [{stat_option(), integer()}]} | {'error', posix()}. +-spec getstat(Socket, Options) -> + {ok, OptionValues} | {error, posix()} when + Socket :: socket(), + Options :: [stat_option()], + OptionValues :: [{stat_option(), integer()}]. getstat(Socket,What) -> prim_inet:getstat(Socket, What). --spec gethostbyname(Name :: string() | atom()) -> - {'ok', #hostent{}} | {'error', posix()}. +-spec gethostbyname(Hostname) -> {ok, Hostent} | {error, posix()} when + Hostname :: hostname(), + Hostent :: hostent(). gethostbyname(Name) -> gethostbyname_tm(Name, inet, false). --spec gethostbyname(Name :: string() | atom(), Family :: family_option()) -> - {'ok', #hostent{}} | {'error', posix()}. +-spec gethostbyname(Hostname, Family) -> + {ok, Hostent} | {error, posix()} when + Hostname :: hostname(), + Family :: address_family(), + Hostent :: hostent(). gethostbyname(Name,Family) -> gethostbyname_tm(Name, Family, false). --spec gethostbyname(Name :: string() | atom(), - Family :: family_option(), +-spec gethostbyname(Name :: hostname(), + Family :: address_family(), Timeout :: non_neg_integer() | 'infinity') -> {'ok', #hostent{}} | {'error', posix()}. @@ -439,8 +400,9 @@ gethostbyname_tm(Name,Family,Timer) -> gethostbyname_tm(Name, Family, Timer, Opts). --spec gethostbyaddr(Address :: string() | ip_address()) -> - {'ok', #hostent{}} | {'error', posix()}. +-spec gethostbyaddr(Address) -> {ok, Hostent} | {error, posix()} when + Address :: string() | ip_address(), + Hostent :: hostent(). gethostbyaddr(Address) -> gethostbyaddr_tm(Address, false). @@ -491,15 +453,16 @@ getfd(Socket) -> %% Lookup an ip address %% --spec getaddr(Host :: ip_address() | string() | atom(), - Family :: family_option()) -> - {'ok', ip_address()} | {'error', posix()}. +-spec getaddr(Host, Family) -> {ok, Address} | {error, posix()} when + Host :: ip_address() | hostname(), + Family :: address_family(), + Address :: ip_address(). getaddr(Address, Family) -> getaddr(Address, Family, infinity). --spec getaddr(Host :: ip_address() | string() | atom(), - Family :: family_option(), +-spec getaddr(Host :: ip_address() | hostname(), + Family :: address_family(), Timeout :: non_neg_integer() | 'infinity') -> {'ok', ip_address()} | {'error', posix()}. @@ -515,15 +478,17 @@ getaddr_tm(Address, Family, Timer) -> Error -> Error end. --spec getaddrs(Host :: ip_address() | string() | atom(), - Family :: family_option()) -> - {'ok', [ip_address()]} | {'error', posix()}. +-spec getaddrs(Host, Family) -> + {ok, Addresses} | {error, posix()} when + Host :: ip_address() | hostname(), + Family :: address_family(), + Addresses :: [ip_address()]. getaddrs(Address, Family) -> getaddrs(Address, Family, infinity). -spec getaddrs(Host :: ip_address() | string() | atom(), - Family :: family_option(), + Family :: address_family(), Timeout :: non_neg_integer() | 'infinity') -> {'ok', [ip_address()]} | {'error', posix()}. @@ -533,7 +498,7 @@ getaddrs(Address, Family, Timeout) -> stop_timer(Timer), Res. --spec getservbyport(Port :: ip_port(), Protocol :: atom() | string()) -> +-spec getservbyport(Port :: port_number(), Protocol :: atom() | string()) -> {'ok', string()} | {'error', posix()}. getservbyport(Port, Proto) -> @@ -547,7 +512,7 @@ getservbyport(Port, Proto) -> -spec getservbyname(Name :: atom() | string(), Protocol :: atom() | string()) -> - {'ok', ip_port()} | {'error', posix()}. + {'ok', port_number()} | {'error', posix()}. getservbyname(Name, Protocol) when is_atom(Name) -> case inet_udp:open(0, []) of @@ -784,6 +749,8 @@ sctp_opt([Opt|Opts], Mod, R, As) -> sctp_opt(Opts, Mod, R#sctp_opts{port=P}, As); Error -> Error end; + {type,Type} when Type =:= seqpacket; Type =:= stream -> + sctp_opt(Opts, Mod, R#sctp_opts{type=Type}, As); binary -> sctp_opt (Opts, Mod, R, As, mode, binary); list -> sctp_opt (Opts, Mod, R, As, mode, list); {sctp_module,_} -> sctp_opt (Opts, Mod, R, As); % Done with @@ -1030,15 +997,16 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) -> -spec open(Fd :: integer(), Addr :: ip_address(), - Port :: ip_port(), + Port :: port_number(), Opts :: [socket_setopt()], - Protocol :: protocol_option(), - Family :: 'inet' | 'inet6', + Protocol :: socket_protocol(), + Family :: address_family(), + Type :: socket_type(), Module :: atom()) -> {'ok', socket()} | {'error', posix()}. -open(Fd, Addr, Port, Opts, Protocol, Family, Module) when Fd < 0 -> - case prim_inet:open(Protocol, Family) of +open(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) when Fd < 0 -> + case prim_inet:open(Protocol, Family, Type) of {ok,S} -> case prim_inet:setopts(S, Opts) of ok -> @@ -1065,18 +1033,19 @@ open(Fd, Addr, Port, Opts, Protocol, Family, Module) when Fd < 0 -> Error -> Error end; -open(Fd, _Addr, _Port, Opts, Protocol, Family, Module) -> - fdopen(Fd, Opts, Protocol, Family, Module). +open(Fd, _Addr, _Port, Opts, Protocol, Family, Type, Module) -> + fdopen(Fd, Opts, Protocol, Family, Type, Module). -spec fdopen(Fd :: non_neg_integer(), Opts :: [socket_setopt()], - Protocol :: protocol_option(), - Family :: family_option(), + Protocol :: socket_protocol(), + Family :: address_family(), + Type :: socket_type(), Module :: atom()) -> {'ok', socket()} | {'error', posix()}. -fdopen(Fd, Opts, Protocol, Family, Module) -> - case prim_inet:fdopen(Protocol, Fd, Family) of +fdopen(Fd, Opts, Protocol, Family, Type, Module) -> + case prim_inet:fdopen(Protocol, Family, Type, Fd) of {ok, S} -> case prim_inet:setopts(S, Opts) of ok -> @@ -1092,18 +1061,24 @@ fdopen(Fd, Opts, Protocol, Family, Module) -> %% socket stat %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -i() -> i(tcp), i(udp). +i() -> i(tcp), i(udp), i(sctp). i(Proto) -> i(Proto, [port, module, recv, sent, owner, - local_address, foreign_address, state]). + local_address, foreign_address, state, type]). i(tcp, Fs) -> ii(tcp_sockets(), Fs, tcp); i(udp, Fs) -> - ii(udp_sockets(), Fs, udp). + ii(udp_sockets(), Fs, udp); +i(sctp, Fs) -> + ii(sctp_sockets(), Fs, sctp). ii(Ss, Fs, Proto) -> - LLs = [h_line(Fs) | info_lines(Ss, Fs, Proto)], + LLs = + case info_lines(Ss, Fs, Proto) of + [] -> []; + InfoLines -> [h_line(Fs) | InfoLines] + end, Maxs = foldl( fun(Line,Max0) -> smax(Max0,Line) end, duplicate(length(Fs),0),LLs), @@ -1171,6 +1146,7 @@ info(S, F, Proto) -> case prim_inet:gettype(S) of {ok,{_,stream}} -> "STREAM"; {ok,{_,dgram}} -> "DGRAM"; + {ok,{_,seqpacket}} -> "SEQPACKET"; _ -> " " end; fd -> @@ -1222,6 +1198,7 @@ fmt_port(N, Proto) -> %% Return a list of all tcp sockets tcp_sockets() -> port_list("tcp_inet"). udp_sockets() -> port_list("udp_inet"). +sctp_sockets() -> port_list("sctp_inet"). %% Return all ports having the name 'Name' port_list(Name) -> @@ -1237,7 +1214,8 @@ port_list(Name) -> %% utils %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% --spec format_error(posix()) -> string(). +-spec format_error(Posix) -> string() when + Posix :: posix(). format_error(exbadport) -> "invalid port state"; format_error(exbadseq) -> "bad command sequence"; diff --git a/lib/kernel/src/inet6_sctp.erl b/lib/kernel/src/inet6_sctp.erl index 5bf3fca647..c47483bbdd 100644 --- a/lib/kernel/src/inet6_sctp.erl +++ b/lib/kernel/src/inet6_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -32,7 +32,8 @@ -define(FAMILY, inet6). -export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]). --export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]). +-export([open/1,close/1,listen/2,peeloff/2,connect/5]). +-export([sendmsg/3,send/4,recv/2]). @@ -54,8 +55,8 @@ translate_ip(IP) -> open(Opts) -> case inet:sctp_options(Opts, ?MODULE) of - {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,opts=SOs}} -> - inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, ?MODULE); + {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} -> + inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE); Error -> Error end. @@ -65,6 +66,14 @@ close(S) -> listen(S, Flag) -> prim_inet:listen(S, Flag). +peeloff(S, AssocId) -> + case prim_inet:peeloff(S, AssocId) of + {ok, NewS}=Result -> + inet_db:register_socket(NewS, ?MODULE), + Result; + Error -> Error + end. + connect(S, Addr, Port, Opts, Timer) -> inet_sctp:connect(S, Addr, Port, Opts, Timer). diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl index cc45f6c7f6..c714b2bee0 100644 --- a/lib/kernel/src/inet6_tcp.erl +++ b/lib/kernel/src/inet6_tcp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -93,7 +93,7 @@ do_connect(Addr = {A,B,C,D,E,F,G,H}, Port, Opts, Time) when port=BPort, opts=SockOpts}} when ?ip6(Ab,Bb,Cb,Db,Eb,Fb,Gb,Hb), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of {ok, S} -> case prim_inet:connect(S, Addr, Port, Time) of ok -> {ok,S}; @@ -115,7 +115,7 @@ listen(Port, Opts) -> port=BPort, opts=SockOpts}=R} when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of {ok, S} -> case prim_inet:listen(S, R#listen_opts.backlog) of ok -> {ok, S}; @@ -149,5 +149,5 @@ accept(L,Timeout) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, tcp, inet6, ?MODULE). + inet:fdopen(Fd, Opts, tcp, inet6, stream, ?MODULE). diff --git a/lib/kernel/src/inet6_udp.erl b/lib/kernel/src/inet6_udp.erl index e81d417151..ca43c94211 100644 --- a/lib/kernel/src/inet6_udp.erl +++ b/lib/kernel/src/inet6_udp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -45,7 +45,7 @@ open(Port, Opts) -> port=BPort, opts=SockOpts}} when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) -> - inet:open(Fd,BAddr,BPort,SockOpts,udp,inet6,?MODULE); + inet:open(Fd,BAddr,BPort,SockOpts,udp,inet6,dgram,?MODULE); {ok, _} -> exit(badarg) end. @@ -84,4 +84,4 @@ controlling_process(Socket, NewOwner) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, udp, inet6, ?MODULE). + inet:fdopen(Fd, Opts, udp, inet6, dgram, ?MODULE). diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl index 2458876326..1ddbdcec25 100644 --- a/lib/kernel/src/inet_config.erl +++ b/lib/kernel/src/inet_config.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -44,26 +44,6 @@ %% -spec init() -> 'ok'. init() -> - OsType = os:type(), - case OsType of - {ose,_} -> - case init:get_argument(loader) of - {ok,[["ose_inet"]]} -> - %% port already started by prim_loader - ok; - _Other -> - %% Setup reserved port for ose_inet driver (only OSE) - case catch erlang:open_port({spawn,"ose_inet"}, [binary]) of - {'EXIT',Why} -> - error("can't open port for ose_inet: ~p", [Why]); - OseInetPort -> - erlang:display({ose_inet_port,OseInetPort}) - end - end; - _ -> - ok - end, - set_hostname(), %% Note: In shortnames (or non-distributed) mode we don't need to know @@ -71,6 +51,7 @@ init() -> %% the user to provide it (by means of inetrc), so we need to look %% for it ourselves. + OsType = os:type(), do_load_resolv(OsType, erl_dist_mode()), case OsType of @@ -226,35 +207,6 @@ do_load_resolv(vxworks, _) -> load_resolv(Resolv, resolv) end; -do_load_resolv({ose,_Type}, _) -> - inet_db:set_lookup([file, dns]), - case os:getenv("NAMESERVER") of - false -> - case os:getenv("RESOLVFILE") of - false -> - erlang:display('Warning: No NAMESERVER or RESOLVFILE specified!'), - no_resolv; - Resolv -> - load_resolv(Resolv, resolv) - end; - Ns -> - {ok,IP} = inet_parse:address(Ns), - inet_db:add_rc_list([{nameserver,IP}]) - end, - case os:getenv("DOMAIN") of - false -> - no_domain; - D -> - ok = inet_db:add_rc_list([{domain,D}]) - end, - case os:getenv("HOSTSFILE") of - false -> - erlang:display('Warning: No HOSTSFILE specified!'), - no_hosts_file; - File -> - load_hosts(File, ose) - end; - do_load_resolv(_, _) -> inet_db:set_lookup([native]). diff --git a/lib/kernel/src/inet_dns_record_adts.pl b/lib/kernel/src/inet_dns_record_adts.pl index b1d8fab939..da50c7114f 100644 --- a/lib/kernel/src/inet_dns_record_adts.pl +++ b/lib/kernel/src/inet_dns_record_adts.pl @@ -2,7 +2,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2009. All Rights Reserved. +# Copyright Ericsson AB 2009-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -73,6 +73,10 @@ while( my ($Name, $r) = each(%Names)) { # "@Values" = "V1,V2"...",VN" my @D = @DATA; foreach my $line (@D) { + # Ignore !name lines + if ($line =~ s/^\!(\S+)\s+//) { + next if $1 eq $Name; + } my $m = 1; # For leading * iterate $n times, otherwise once $line =~ s/^\s*[*]// and $m = $n; @@ -155,9 +159,9 @@ make_Name() -> \ make_Name(L) when is_list(L) -> \ make_Name(#Record{}, L). -%% Generate #Record{} with one updated field -%% -*make_Name(Field, Value) -> \ +!dns_rr_opt %% Generate #Record{} with one updated field +!dns_rr_opt %% +!dns_rr_opt *make_Name(Field, Value) -> \ #Record{Field=Value}; %% %% Update #Record{} from property list diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index 6f1688c6a2..f8984b13fe 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -29,7 +29,7 @@ -define(INET_AF_ANY, 3). % Fake for ANY in any address family -define(INET_AF_LOOPBACK, 4). % Fake for LOOPBACK in any address family -%% type codes (gettype, INET_REQ_GETTYPE) +%% type codes to open and gettype - INET_REQ_GETTYPE -define(INET_TYPE_STREAM, 1). -define(INET_TYPE_DGRAM, 2). -define(INET_TYPE_SEQPACKET, 3). @@ -83,16 +83,19 @@ -define(INET_REQ_IFSET, 23). -define(INET_REQ_SUBSCRIBE, 24). -define(INET_REQ_GETIFADDRS, 25). +-define(INET_REQ_ACCEPT, 26). +-define(INET_REQ_LISTEN, 27). %% TCP requests --define(TCP_REQ_ACCEPT, 40). --define(TCP_REQ_LISTEN, 41). +%%-define(TCP_REQ_ACCEPT, 40). MOVED +%%-define(TCP_REQ_LISTEN, 41). MERGED -define(TCP_REQ_RECV, 42). -define(TCP_REQ_UNRECV, 43). -define(TCP_REQ_SHUTDOWN, 44). %% UDP and SCTP requests -define(PACKET_REQ_RECV, 60). --define(SCTP_REQ_LISTEN, 61). +%%-define(SCTP_REQ_LISTEN, 61). MERGED -define(SCTP_REQ_BINDX, 62). %% Multi-home SCTP bind +-define(SCTP_REQ_PEELOFF, 63). %% subscribe codes, INET_REQ_SUBSCRIBE -define(INET_SUBS_EMPTY_OUT_Q, 1). @@ -100,7 +103,7 @@ %% reply codes for *_REQ_* -define(INET_REP_ERROR, 0). -define(INET_REP_OK, 1). --define(INET_REP_SCTP, 2). +-define(INET_REP, 2). %% INET, TCP and UDP options: -define(INET_OPT_REUSEADDR, 0). @@ -399,6 +402,7 @@ ifaddr, port = 0, fd = -1, + type = seqpacket, opts = [{mode, binary}, {buffer, ?SCTP_DEF_BUFSZ}, {sndbuf, ?SCTP_DEF_BUFSZ}, diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl index de0f23bf24..59ba408d7a 100644 --- a/lib/kernel/src/inet_res.erl +++ b/lib/kernel/src/inet_res.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -47,18 +47,93 @@ false -> ok end). +-type res_option() :: + {alt_nameservers, [nameserver()]} + | {edns, 0 | false} + | {inet6, boolean()} + | {nameservers, [nameserver()]} + | {recurse, boolean()} + | {retry, integer()} + | {timeout, integer()} + | {udp_payload_size, integer()} + | {usevc, boolean()}. + +-type nameserver() :: {inet:ip_address(), Port :: 1..65535}. + +-type res_error() :: formerr | qfmterror | servfail | nxdomain | + notimp | refused | badvers | timeout. + +-type dns_name() :: string(). + +-type rr_type() :: a | aaaa | cname | gid | hinfo | ns | mb | md | mg | mf + | minfo | mx | naptr | null | ptr | soa | spf | srv | txt + | uid | uinfo | unspec | wks. + +-type dns_class() :: in | chaos | hs | any. + +-type dns_msg() :: term(). + +-type dns_data() :: + dns_name() + | inet:ip4_address() + | inet:ip6_address() + | {MName :: dns_name(), + RName :: dns_name(), + Serial :: integer(), + Refresh :: integer(), + Retry :: integer(), + Expiry :: integer(), + Minimum :: integer()} + | {inet:ip4_address(), Proto :: integer(), BitMap :: binary()} + | {CpuString :: string(), OsString :: string()} + | {RM :: dns_name(), EM :: dns_name()} + | {Prio :: integer(), dns_name()} + | {Prio :: integer(),Weight :: integer(),Port :: integer(),dns_name()} + | {Order :: integer(),Preference :: integer(),Flags :: string(), + Services :: string(),Regexp :: string(), dns_name()} + | [string()] + | binary(). + %% -------------------------------------------------------------------------- %% resolve: %% %% Nameserver query %% +-spec resolve(Name, Class, Type) -> {ok, dns_msg()} | Error when + Name :: dns_name() | inet:ip_address(), + Class :: dns_class(), + Type :: rr_type(), + Error :: {error, Reason} | {error,{Reason,dns_msg()}}, + Reason :: inet:posix() | res_error(). + resolve(Name, Class, Type) -> resolve(Name, Class, Type, [], infinity). +-spec resolve(Name, Class, Type, Opts) -> + {ok, dns_msg()} | Error when + Name :: dns_name() | inet:ip_address(), + Class :: dns_class(), + Type :: rr_type(), + Opts :: [Opt], + Opt :: res_option() | verbose | atom(), + Error :: {error, Reason} | {error,{Reason,dns_msg()}}, + Reason :: inet:posix() | res_error(). + resolve(Name, Class, Type, Opts) -> resolve(Name, Class, Type, Opts, infinity). +-spec resolve(Name, Class, Type, Opts, Timeout) -> + {ok, dns_msg()} | Error when + Name :: dns_name() | inet:ip_address(), + Class :: dns_class(), + Type :: rr_type(), + Opts :: [Opt], + Opt :: res_option() | verbose | atom(), + Timeout :: timeout(), + Error :: {error, Reason} | {error,{Reason,dns_msg()}}, + Reason :: inet:posix() | res_error(). + resolve(Name, Class, Type, Opts, Timeout) -> case nsdname(Name) of {ok, Nm} -> @@ -76,12 +151,30 @@ resolve(Name, Class, Type, Opts, Timeout) -> %% Convenience wrapper to resolve/3,4,5 that filters out all answer data %% fields of the class and type asked for. +-spec lookup(Name, Class, Type) -> [dns_data()] when + Name :: dns_name() | inet:ip_address(), + Class :: dns_class(), + Type :: rr_type(). + lookup(Name, Class, Type) -> lookup(Name, Class, Type, []). +-spec lookup(Name, Class, Type, Opts) -> [dns_data()] when + Name :: dns_name() | inet:ip_address(), + Class :: dns_class(), + Type :: rr_type(), + Opts :: [res_option() | verbose]. + lookup(Name, Class, Type, Opts) -> lookup(Name, Class, Type, Opts, infinity). +-spec lookup(Name, Class, Type, Opts, Timeout) -> [dns_data()] when + Name :: dns_name() | inet:ip_address(), + Class :: dns_class(), + Type :: rr_type(), + Opts :: [res_option() | verbose], + Timeout :: timeout(). + lookup(Name, Class, Type, Opts, Timeout) -> lookup_filter(resolve(Name, Class, Type, Opts, Timeout), Class, Type). @@ -101,17 +194,55 @@ lookup_filter({error,_}, _, _) -> []. %% %% To be deprecated +-spec nslookup(Name, Class, Type) -> {ok, dns_msg()} | {error, Reason} when + Name :: dns_name() | inet:ip_address(), + Class :: dns_class(), + Type :: rr_type(), + Reason :: inet:posix() | res_error(). + nslookup(Name, Class, Type) -> do_nslookup(Name, Class, Type, [], infinity). +-spec nslookup(Name, Class, Type, Timeout) -> + {ok, dns_msg()} | {error, Reason} when + Name :: dns_name() | inet:ip_address(), + Class :: dns_class(), + Type :: rr_type(), + Timeout :: timeout(), + Reason :: inet:posix() | res_error(); + (Name, Class, Type, Nameservers) -> + {ok, dns_msg()} | {error, Reason} when + Name :: dns_name() | inet:ip_address(), + Class :: dns_class(), + Type :: rr_type(), + Nameservers :: [nameserver()], + Reason :: inet:posix() | res_error(). + nslookup(Name, Class, Type, Timeout) when is_integer(Timeout), Timeout >= 0 -> do_nslookup(Name, Class, Type, [], Timeout); nslookup(Name, Class, Type, NSs) -> % For backwards compatibility nnslookup(Name, Class, Type, NSs). % with OTP R6B only +-spec nnslookup(Name, Class, Type, Nameservers) -> + {ok, dns_msg()} | {error, Reason} when + Name :: dns_name() | inet:ip_address(), + Class :: dns_class(), + Type :: rr_type(), + Nameservers :: [nameserver()], + Reason :: inet:posix(). + nnslookup(Name, Class, Type, NSs) -> nnslookup(Name, Class, Type, NSs, infinity). +-spec nnslookup(Name, Class, Type, Nameservers, Timeout) -> + {ok, dns_msg()} | {error, Reason} when + Name :: dns_name() | inet:ip_address(), + Class :: dns_class(), + Type :: rr_type(), + Timeout :: timeout(), + Nameservers :: [nameserver()], + Reason :: inet:posix(). + nnslookup(Name, Class, Type, NSs, Timeout) -> do_nslookup(Name, Class, Type, [{nameservers,NSs}], Timeout). @@ -192,8 +323,19 @@ make_options(Opts, [Name|Names]) -> %% %% -------------------------------------------------------------------------- +-spec gethostbyaddr(Address) -> {ok, Hostent} | {error, Reason} when + Address :: inet:ip_address(), + Hostent :: inet:hostent(), + Reason :: inet:posix() | res_error(). + gethostbyaddr(IP) -> gethostbyaddr_tm(IP,false). +-spec gethostbyaddr(Address, Timeout) -> {ok, Hostent} | {error, Reason} when + Address :: inet:ip_address(), + Timeout :: timeout(), + Hostent :: inet:hostent(), + Reason :: inet:posix() | res_error(). + gethostbyaddr(IP,Timeout) -> Timer = inet:start_timer(Timeout), Res = gethostbyaddr_tm(IP,Timer), @@ -249,6 +391,11 @@ res_gethostbyaddr(Addr, IP, Timer) -> %% Caches the answer. %% -------------------------------------------------------------------------- +-spec gethostbyname(Name) -> {ok, Hostent} | {error, Reason} when + Name :: dns_name(), + Hostent :: inet:hostent(), + Reason :: inet:posix() | res_error(). + gethostbyname(Name) -> case inet_db:res_option(inet6) of true -> @@ -257,9 +404,23 @@ gethostbyname(Name) -> gethostbyname_tm(Name, inet, false) end. +-spec gethostbyname(Name, Family) -> {ok, Hostent} | {error, Reason} when + Name :: dns_name(), + Hostent :: inet:hostent(), + Family :: inet:address_family(), + Reason :: inet:posix() | res_error(). + gethostbyname(Name,Family) -> gethostbyname_tm(Name,Family,false). +-spec gethostbyname(Name, Family, Timeout) -> + {ok, Hostent} | {error, Reason} when + Name :: dns_name(), + Hostent :: inet:hostent(), + Timeout :: timeout(), + Family :: inet:address_family(), + Reason :: inet:posix() | res_error(). + gethostbyname(Name,Family,Timeout) -> Timer = inet:start_timer(Timeout), Res = gethostbyname_tm(Name,Family,Timer), @@ -298,14 +459,27 @@ gethostbyname_tm(_Name, _Family, _Timer) -> %% %% getbyname(domain_name(), Type) => {ok, hostent()} | {error, Reason} %% -%% where domain_name() is domain string or atom and Type is ?S_A, ?S_MX ... +%% where domain_name() is domain string and Type is ?S_A, ?S_MX ... %% %% Caches the answer. %% -------------------------------------------------------------------------- +-spec getbyname(Name, Type) -> {ok, Hostent} | {error, Reason} when + Name :: dns_name(), + Type :: rr_type(), + Hostent :: inet:hostent(), + Reason :: inet:posix() | res_error(). + getbyname(Name, Type) -> getbyname_tm(Name,Type,false). +-spec getbyname(Name, Type, Timeout) -> {ok, Hostent} | {error, Reason} when + Name :: dns_name(), + Type :: rr_type(), + Timeout :: timeout(), + Hostent :: inet:hostent(), + Reason :: inet:posix() | res_error(). + getbyname(Name, Type, Timeout) -> Timer = inet:start_timer(Timeout), Res = getbyname_tm(Name, Type, Timer), @@ -539,27 +713,41 @@ udp_send(#sock{inet=I}, {A,B,C,D}=IP, Port, Buffer) when ?ip(A,B,C,D), ?port(Port) -> gen_udp:send(I, IP, Port, Buffer). -udp_recv(#sock{inet6=I}, {A,B,C,D,E,F,G,H}=IP, Port, Timeout) +udp_recv(#sock{inet6=I}, {A,B,C,D,E,F,G,H}=IP, Port, Timeout, Decode) when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) -> - do_udp_recv(fun(T) -> gen_udp:recv(I, 0, T) end, IP, Port, Timeout); -udp_recv(#sock{inet=I}, {A,B,C,D}=IP, Port, Timeout) + do_udp_recv(I, IP, Port, Timeout, Decode, erlang:now(), Timeout); +udp_recv(#sock{inet=I}, {A,B,C,D}=IP, Port, Timeout, Decode) when ?ip(A,B,C,D), ?port(Port) -> - do_udp_recv(fun(T) -> gen_udp:recv(I, 0, T) end, IP, Port, Timeout). - -do_udp_recv(Recv, IP, Port, Timeout) -> - do_udp_recv(Recv, IP, Port, Timeout, - if Timeout =/= 0 -> erlang:now(); true -> undefined end). - -do_udp_recv(Recv, IP, Port, Timeout, Then) -> - case Recv(Timeout) of - {ok,{IP,Port,Answer}} -> - {ok,Answer,erlang:max(0, Timeout - now_ms(erlang:now(), Then))}; - {ok,_} when Timeout =:= 0 -> - {error,timeout}; - {ok,_} -> - Now = erlang:now(), - T = erlang:max(0, Timeout - now_ms(Now, Then)), - do_udp_recv(Recv, IP, Port, T, Now); + do_udp_recv(I, IP, Port, Timeout, Decode, erlang:now(), Timeout). + +do_udp_recv(_I, _IP, _Port, 0, _Decode, _Start, _T) -> + timeout; +do_udp_recv(I, IP, Port, Timeout, Decode, Start, T) -> + case gen_udp:recv(I, 0, T) of + {ok,Reply} -> + case Decode(Reply) of + false when T =:= 0 -> + %% This is a compromize between the hard way i.e + %% in the clause below if NewT becomes 0 bailout + %% immediately and risk that the right reply lies + %% ahead after some bad id replies, and the + %% forgiving way i.e go on with Timeout 0 until + %% the right reply comes or no reply (timeout) + %% which opens for a DOS attack by a malicious + %% DNS server flooding with bad id replies causing + %% an infinite loop here. + %% + %% Timeout is used as a sanity limit counter + %% just to put an end to the loop. + NewTimeout = erlang:max(0, Timeout - 50), + do_udp_recv(I, IP, Port, NewTimeout, Decode, Start, T); + false -> + Now = erlang:now(), + NewT = erlang:max(0, Timeout - now_ms(Now, Start)), + do_udp_recv(I, IP, Port, Timeout, Decode, Start, NewT); + Result -> + Result + end; Error -> Error end. @@ -580,6 +768,17 @@ udp_close(#sock{inet=I,inet6=I6}) -> %% end %% end %% +%% But that man page also says dig always use num_servers = 1. +%% +%% Our man page says: timeout/retry, then double for next retry, i.e +%% for i = 0 to retry - 1 +%% foreach nameserver +%% send query +%% wait((time * (2**i)) / retry) +%% end +%% end +%% +%% And that is what the code seems to do, now fixed, hopefully... do_query(_Q, [], _Timer) -> {error,nxdomain}; @@ -589,19 +788,16 @@ do_query(#q{options=#options{retry=Retry}}=Q, NSs, Timer) -> query_retries(_Q, _NSs, _Timer, Retry, Retry, S) -> udp_close(S), {error,timeout}; +query_retries(_Q, [], _Timer, _Retry, _I, S) -> + udp_close(S), + {error,timeout}; query_retries(Q, NSs, Timer, Retry, I, S0) -> - Num = length(NSs), - if Num =:= 0 -> - udp_close(S0), - {error,timeout}; - true -> - case query_nss(Q, NSs, Timer, Retry, I, S0, []) of - {S,{noanswer,ErrNSs}} -> %% remove unreachable nameservers - query_retries(Q, NSs--ErrNSs, Timer, Retry, I+1, S); - {S,Result} -> - udp_close(S), - Result - end + case query_nss(Q, NSs, Timer, Retry, I, S0, []) of + {S,{noanswer,ErrNSs}} -> %% remove unreachable nameservers + query_retries(Q, NSs--ErrNSs, Timer, Retry, I+1, S); + {S,Result} -> + udp_close(S), + Result end. query_nss(_Q, [], _Timer, _Retry, _I, S, ErrNSs) -> @@ -611,13 +807,13 @@ query_nss(#q{edns=undefined}=Q, NSs, Timer, Retry, I, S, ErrNSs) -> query_nss(Q, NSs, Timer, Retry, I, S, ErrNSs) -> query_nss_edns(Q, NSs, Timer, Retry, I, S, ErrNSs). -query_nss_edns(#q{options=#options{udp_payload_size=PSz}=Options, - edns={Id,Buffer}}=Q, - [{IP,Port}=NS|NSs]=NSs0, Timer, Retry, I, S0, ErrNSs) -> - {S,Res}=Reply = query_ns(S0, Id, Buffer, IP, Port, Timer, - Retry, I, Options, PSz), +query_nss_edns( + #q{options=#options{udp_payload_size=PSz}=Options,edns={Id,Buffer}}=Q, + [{IP,Port}=NS|NSs]=NSs0, Timer, Retry, I, S0, ErrNSs) -> + {S,Res}=Reply = + query_ns(S0, Id, Buffer, IP, Port, Timer, Retry, I, Options, PSz), case Res of - timeout -> {S,{error,timeout}}; + timeout -> {S,{error,timeout}}; % Bailout timeout {ok,_} -> Reply; {error,{nxdomain,_}} -> Reply; {error,{E,_}} when E =:= qfmterror; E =:= notimp; E =:= servfail; @@ -629,17 +825,19 @@ query_nss_edns(#q{options=#options{udp_payload_size=PSz}=Options, query_nss(Q, NSs, Timer, Retry, I, S, ErrNSs) end. -query_nss_dns(#q{dns=Qdns}=Q0, [{IP,Port}=NS|NSs], - Timer, Retry, I, S0, ErrNSs) -> +query_nss_dns( + #q{dns=Qdns}=Q0, + [{IP,Port}=NS|NSs], Timer, Retry, I, S0, ErrNSs) -> #q{options=Options,dns={Id,Buffer}}=Q = if is_function(Qdns, 0) -> Q0#q{dns=Qdns()}; true -> Q0 end, - {S,Res}=Reply = query_ns(S0, Id, Buffer, IP, Port, Timer, - Retry, I, Options, ?PACKETSZ), + {S,Res}=Reply = + query_ns( + S0, Id, Buffer, IP, Port, Timer, Retry, I, Options, ?PACKETSZ), case Res of - timeout -> {S,{error,timeout}}; + timeout -> {S,{error,timeout}}; % Bailout timeout {ok,_} -> Reply; {error,{E,_}} when E =:= nxdomain; E =:= qfmterror -> Reply; {error,E} when E =:= fmt; E =:= enetunreach; E =:= econnrefused -> @@ -653,48 +851,66 @@ query_ns(S0, Id, Buffer, IP, Port, Timer, Retry, I, PSz) -> case UseVC orelse iolist_size(Buffer) > PSz of true -> - {S0,query_tcp(Tm, Id, Buffer, IP, Port, Timer, Verbose)}; + TcpTimeout = inet:timeout(Tm*5, Timer), + {S0,query_tcp(TcpTimeout, Id, Buffer, IP, Port, Verbose)}; false -> case udp_open(S0, IP) of {ok,S} -> - {S,case query_udp(S, Id, Buffer, IP, Port, Timer, - Retry, I, Tm, Verbose) of - {ok,#dns_rec{header=H}} when H#dns_header.tc -> - query_tcp(Tm, Id, Buffer, - IP, Port, Timer, Verbose); - Reply -> Reply - end}; + Timeout = + inet:timeout( (Tm * (1 bsl I)) div Retry, Timer), + {S, + case query_udp( + S, Id, Buffer, IP, Port, Timeout, Verbose) of + {ok,#dns_rec{header=H}} when H#dns_header.tc -> + TcpTimeout = inet:timeout(Tm*5, Timer), + query_tcp( + TcpTimeout, Id, Buffer, IP, Port, Verbose); + Reply -> Reply + end}; Error -> {S0,Error} end end. -query_udp(S, Id, Buffer, IP, Port, Timer, Retry, I, Tm, Verbose) -> - Timeout = inet:timeout( (Tm * (1 bsl I)) div Retry, Timer), +query_udp(_S, _Id, _Buffer, _IP, _Port, 0, _Verbose) -> + timeout; +query_udp(S, Id, Buffer, IP, Port, Timeout, Verbose) -> ?verbose(Verbose, "Try UDP server : ~p:~p (timeout=~w)\n", - [IP, Port, Timeout]), - udp_connect(S, IP, Port), - udp_send(S, IP, Port, Buffer), - query_udp_recv(S, IP, Port, Id, Timeout, Verbose). - -query_udp_recv(S, IP, Port, Id, Timeout, Verbose) -> - case udp_recv(S, IP, Port, Timeout) of - {ok,Answer,T} -> - case decode_answer(Answer, Id, Verbose) of - {error, badid} -> - query_udp_recv(S, IP, Port, Id, T, Verbose); - Reply -> Reply + [IP,Port,Timeout]), + case + case udp_connect(S, IP, Port) of + ok -> + udp_send(S, IP, Port, Buffer); + E1 -> + E1 end of + ok -> + Decode = + fun ({RecIP,RecPort,Answer}) + when RecIP =:= IP, RecPort =:= Port -> + case decode_answer(Answer, Id, Verbose) of + {error,badid} -> + false; + Reply -> + Reply + end; + ({_,_,_}) -> + false + end, + case udp_recv(S, IP, Port, Timeout, Decode) of + {ok,_}=Result -> + Result; + E2 -> + ?verbose(Verbose, "UDP server error: ~p\n", [E2]), + E2 end; - {error, timeout} when Timeout =:= 0 -> - ?verbose(Verbose, "UDP server timeout\n", []), - timeout; - Error -> - ?verbose(Verbose, "UDP server error: ~p\n", [Error]), - Error + E3 -> + ?verbose(Verbose, "UDP send failed: ~p\n", [E3]), + {error,econnrefused} end. -query_tcp(Tm, Id, Buffer, IP, Port, Timer, Verbose) -> - Timeout = inet:timeout(Tm*5, Timer), +query_tcp(0, _Id, _Buffer, _IP, _Port, _Verbose) -> + timeout; +query_tcp(Timeout, Id, Buffer, IP, Port, Verbose) -> ?verbose(Verbose, "Try TCP server : ~p:~p (timeout=~w)\n", [IP, Port, Timeout]), Family = case IP of @@ -716,19 +932,10 @@ query_tcp(Tm, Id, Buffer, IP, Port, Timer, Verbose) -> end; Error -> gen_tcp:close(S), - case Error of - {error, timeout} when Timeout =:= 0 -> - ?verbose(Verbose, "TCP server recv timeout\n", []), - timeout; - _ -> - ?verbose(Verbose, "TCP server recv error: ~p\n", - [Error]), - Error - end + ?verbose(Verbose, "TCP server recv error: ~p\n", + [Error]), + Error end; - {error, timeout} when Timeout =:= 0 -> - ?verbose(Verbose, "TCP server connect timeout\n", []), - timeout; Error -> ?verbose(Verbose, "TCP server error: ~p\n", [Error]), Error diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl index de74b573bd..2d799d79fa 100644 --- a/lib/kernel/src/inet_sctp.erl +++ b/lib/kernel/src/inet_sctp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -31,7 +31,8 @@ -define(FAMILY, inet). -export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]). --export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]). +-export([open/1,close/1,listen/2,peeloff/2,connect/5]). +-export([sendmsg/3,send/4,recv/2]). @@ -53,8 +54,8 @@ translate_ip(IP) -> open(Opts) -> case inet:sctp_options(Opts, ?MODULE) of - {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,opts=SOs}} -> - inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, ?MODULE); + {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} -> + inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE); Error -> Error end. @@ -64,6 +65,14 @@ close(S) -> listen(S, Flag) -> prim_inet:listen(S, Flag). +peeloff(S, AssocId) -> + case prim_inet:peeloff(S, AssocId) of + {ok, NewS}=Result -> + inet_db:register_socket(NewS, ?MODULE), + Result; + Error -> Error + end. + %% A non-blocking connect is implemented when the initial call is to %% gen_sctp:connect_init which passes the value nowait as the Timer connect(S, Addr, Port, Opts, Timer) -> @@ -102,7 +111,7 @@ connect(S, Addr, Port, Opts, Timer) -> connect_get_assoc(S, Addr, Port, false, Timer) -> case recv(S, inet:timeout(Timer)) of - {ok, {Addr, Port, [], #sctp_assoc_change{state=St}=Ev}} -> + {ok, {Addr, Port, _, #sctp_assoc_change{state=St}=Ev}} -> if St =:= comm_up -> %% Yes, successfully connected, return the whole %% sctp_assoc_change event (containing, in particular, @@ -123,7 +132,7 @@ connect_get_assoc(S, Addr, Port, false, Timer) -> connect_get_assoc(S, Addr, Port, Active, Timer) -> Timeout = inet:timeout(Timer), receive - {sctp,S,Addr,Port,{[],#sctp_assoc_change{state=St}=Ev}} -> + {sctp,S,Addr,Port,{_,#sctp_assoc_change{state=St}=Ev}} -> case Active of once -> prim_inet:setopt(S, active, once); diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl index 6dadccd6a9..4c2db16ce3 100644 --- a/lib/kernel/src/inet_tcp.erl +++ b/lib/kernel/src/inet_tcp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -95,7 +95,7 @@ do_connect({A,B,C,D}, Port, Opts, Time) when ?ip(A,B,C,D), ?port(Port) -> port=BPort, opts=SockOpts}} when ?ip(Ab,Bb,Cb,Db), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of {ok, S} -> case prim_inet:connect(S, {A,B,C,D}, Port, Time) of ok -> {ok,S}; @@ -117,7 +117,7 @@ listen(Port, Opts) -> port=BPort, opts=SockOpts}=R} when ?ip(A,B,C,D), ?port(BPort) -> - case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,?MODULE) of + case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of {ok, S} -> case prim_inet:listen(S, R#listen_opts.backlog) of ok -> {ok, S}; @@ -150,4 +150,4 @@ accept(L,Timeout) -> %% Create a port/socket from a file descriptor %% fdopen(Fd, Opts) -> - inet:fdopen(Fd, Opts, tcp, inet, ?MODULE). + inet:fdopen(Fd, Opts, tcp, inet, stream, ?MODULE). diff --git a/lib/kernel/src/inet_udp.erl b/lib/kernel/src/inet_udp.erl index 9a4089ab19..80d930fe10 100644 --- a/lib/kernel/src/inet_udp.erl +++ b/lib/kernel/src/inet_udp.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -39,8 +39,10 @@ getserv(Name) when is_atom(Name) -> inet:getservbyname(Name,udp). getaddr(Address) -> inet:getaddr(Address, inet). getaddr(Address,Timer) -> inet:getaddr_tm(Address, inet, Timer). +-spec open(_) -> {ok, inet:socket()} | {error, atom()}. open(Port) -> open(Port, []). +-spec open(_, _) -> {ok, inet:socket()} | {error, atom()}. open(Port, Opts) -> case inet:udp_options( [{port,Port}, {recbuf, ?RECBUF} | Opts], @@ -50,7 +52,7 @@ open(Port, Opts) -> ifaddr=BAddr={A,B,C,D}, port=BPort, opts=SockOpts}} when ?ip(A,B,C,D), ?port(BPort) -> - inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,?MODULE); + inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,dgram,?MODULE); {ok, _} -> exit(badarg) end. @@ -69,6 +71,8 @@ recv(S,Len) -> recv(S,Len,Time) -> prim_inet:recvfrom(S, Len, Time). +-spec close(inet:socket()) -> ok. + close(S) -> inet:udp_close(S). @@ -89,7 +93,7 @@ controlling_process(Socket, NewOwner) -> fdopen(Fd, Opts) -> inet:fdopen(Fd, optuniquify([{recbuf, ?RECBUF} | Opts]), - udp, inet, ?MODULE). + udp, inet, dgram, ?MODULE). %% Remove all duplicate options from an option list. diff --git a/lib/kernel/src/net_adm.erl b/lib/kernel/src/net_adm.erl index 737b1ecee9..9b2dac9544 100644 --- a/lib/kernel/src/net_adm.erl +++ b/lib/kernel/src/net_adm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -35,7 +35,11 @@ %% Try to read .hosts.erlang file in %% 1. cwd , 2. $HOME 3. init:root_dir() --spec host_file() -> [atom()] | {'error',atom() | {integer(),atom(),_}}. +-spec host_file() -> Hosts | {error, Reason} when + Hosts :: [Host :: atom()], + %% Copied from file:path_consult/2: + Reason :: file:posix() | badarg | terminated | system_limit + | {Line :: integer(), Mod :: module(), Term :: term()}. host_file() -> Home = case init:get_argument(home) of @@ -50,7 +54,8 @@ host_file() -> %% Check whether a node is up or down %% side effect: set up a connection to Node if there not yet is one. --spec ping(atom()) -> 'pang' | 'pong'. +-spec ping(Node) -> pong | pang when + Node :: atom(). ping(Node) when is_atom(Node) -> case catch gen:call({net_kernel, Node}, @@ -63,7 +68,8 @@ ping(Node) when is_atom(Node) -> pang end. --spec localhost() -> string(). +-spec localhost() -> Name when + Name :: string(). localhost() -> {ok, Host} = inet:gethostname(), @@ -73,12 +79,20 @@ localhost() -> end. --spec names() -> {'ok', [{string(), integer()}]} | {'error', _}. +-spec names() -> {ok, [{Name, Port}]} | {error, Reason} when + Name :: string(), + Port :: non_neg_integer(), + Reason :: address | file:posix(). names() -> names(localhost()). --spec names(atom() | string()) -> {'ok', [{string(), integer()}]} | {'error', _}. + +-spec names(Host) -> {ok, [{Name, Port}]} | {error, Reason} when + Host :: atom() | string(), + Name :: string(), + Port :: non_neg_integer(), + Reason :: address | file:posix(). names(Hostname) -> case inet:gethostbyname(Hostname) of @@ -88,8 +102,9 @@ names(Hostname) -> Else end. --spec dns_hostname(atom() | string()) -> - {'ok', string()} | {'error', atom() | string()}. +-spec dns_hostname(Host) -> {ok, Name} | {error, Host} when + Host :: atom() | string(), + Name :: string(). dns_hostname(Hostname) -> case inet:gethostbyname(Hostname) of @@ -164,7 +179,8 @@ collect_new(Sofar, Nodelist) -> world() -> world(silent). --spec world(verbosity()) -> [node()]. +-spec world(Arg) -> [node()] when + Arg :: verbosity(). world(Verbose) -> case net_adm:host_file() of @@ -172,12 +188,15 @@ world(Verbose) -> Hosts -> expand_hosts(Hosts, Verbose) end. --spec world_list([atom()]) -> [node()]. +-spec world_list(Hosts) -> [node()] when + Hosts :: [atom()]. world_list(Hosts) when is_list(Hosts) -> expand_hosts(Hosts, silent). --spec world_list([atom()], verbosity()) -> [node()]. +-spec world_list(Hosts, Arg) -> [node()] when + Hosts :: [atom()], + Arg :: verbosity(). world_list(Hosts, Verbose) when is_list(Hosts) -> expand_hosts(Hosts, Verbose). diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl index 5228d4fe01..9e3d730cee 100644 --- a/lib/kernel/src/net_kernel.erl +++ b/lib/kernel/src/net_kernel.erl @@ -145,8 +145,15 @@ %% Interface functions kernel_apply(M,F,A) -> request({apply,M,F,A}). + +-spec allow(Nodes) -> ok | error when + Nodes :: [node()]. allow(Nodes) -> request({allow, Nodes}). + longnames() -> request(longnames). + +-spec stop() -> ok | {error, Reason} when + Reason :: not_allowed | not_found. stop() -> erl_distribution:stop(). node_info(Node) -> get_node_info(Node). @@ -158,10 +165,28 @@ i(Node) -> print_info(Node). verbose(Level) when is_integer(Level) -> request({verbose, Level}). +-spec set_net_ticktime(NetTicktime, TransitionPeriod) -> Res when + NetTicktime :: pos_integer(), + TransitionPeriod :: non_neg_integer(), + Res :: unchanged + | change_initiated + | {ongoing_change_to, NewNetTicktime}, + NewNetTicktime :: pos_integer(). set_net_ticktime(T, TP) when is_integer(T), T > 0, is_integer(TP), TP >= 0 -> ticktime_res(request({new_ticktime, T*250, TP*1000})). + +-spec set_net_ticktime(NetTicktime) -> Res when + NetTicktime :: pos_integer(), + Res :: unchanged + | change_initiated + | {ongoing_change_to, NewNetTicktime}, + NewNetTicktime :: pos_integer(). set_net_ticktime(T) when is_integer(T) -> set_net_ticktime(T, ?DEFAULT_TRANSITION_PERIOD). + +-spec get_net_ticktime() -> Res when + Res :: NetTicktime | {ongoing_change_to, NetTicktime} | ignored, + NetTicktime :: pos_integer(). get_net_ticktime() -> ticktime_res(request(ticktime)). @@ -171,6 +196,9 @@ get_net_ticktime() -> %% flags (we may want to move it elsewhere later). In order to easily %% be backward compatible, errors are created here when process_flag() %% fails. +-spec monitor_nodes(Flag) -> ok | Error when + Flag :: boolean(), + Error :: error | {error, term()}. monitor_nodes(Flag) -> case catch process_flag(monitor_nodes, Flag) of true -> ok; @@ -178,6 +206,13 @@ monitor_nodes(Flag) -> _ -> mk_monitor_nodes_error(Flag, []) end. +-spec monitor_nodes(Flag, Options) -> ok | Error when + Flag :: boolean(), + Options :: [Option], + Option :: {node_type, NodeType} + | nodedown_reason, + NodeType :: visible | hidden | all, + Error :: error | {error, term()}. monitor_nodes(Flag, Opts) -> case catch process_flag({monitor_nodes, Opts}, Flag) of true -> ok; @@ -209,6 +244,8 @@ publish_on_node(Node) when is_atom(Node) -> update_publish_nodes(Ns) -> request({update_publish_nodes, Ns}). +-spec connect_node(Node) -> boolean() | ignored when + Node :: node(). %% explicit connects connect_node(Node) when is_atom(Node) -> request({connect, normal, Node}). diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl index d1feae771d..f6769df585 100644 --- a/lib/kernel/src/os.erl +++ b/lib/kernel/src/os.erl @@ -24,7 +24,10 @@ -include("file.hrl"). --spec type() -> 'vxworks' | {'unix',atom()} | {'win32',atom()} | {'ose',atom()}. +-spec type() -> vxworks | {Osfamily, Osname} when + Osfamily :: unix | win32, + Osname :: atom(). + type() -> case erlang:system_info(os_type) of {vxworks, _} -> @@ -32,18 +35,27 @@ type() -> Else -> Else end. --spec version() -> string() | {non_neg_integer(),non_neg_integer(),non_neg_integer()}. +-spec version() -> VersionString | {Major, Minor, Release} when + VersionString :: string(), + Major :: non_neg_integer(), + Minor :: non_neg_integer(), + Release :: non_neg_integer(). version() -> erlang:system_info(os_version). --spec find_executable(string()) -> string() | 'false'. +-spec find_executable(Name) -> Filename | 'false' when + Name :: string(), + Filename :: string(). find_executable(Name) -> case os:getenv("PATH") of false -> find_executable(Name, []); Path -> find_executable(Name, Path) end. --spec find_executable(string(), string()) -> string() | 'false'. +-spec find_executable(Name, Path) -> Filename | 'false' when + Name :: string(), + Path :: string(), + Filename :: string(). find_executable(Name, Path) -> Extensions = extensions(), case filename:pathtype(Name) of @@ -147,7 +159,8 @@ extensions() -> end. %% Executes the given command in the default shell for the operating system. --spec cmd(atom() | string() | [string()]) -> string(). +-spec cmd(Command) -> string() when + Command :: atom() | io_lib:chars(). cmd(Cmd) -> validate(Cmd), case type() of diff --git a/lib/kernel/src/pg2.erl b/lib/kernel/src/pg2.erl index 956a900adc..0d5838716e 100644 --- a/lib/kernel/src/pg2.erl +++ b/lib/kernel/src/pg2.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,17 +30,19 @@ %%% Exported functions %%% --spec start_link() -> {'ok', pid()} | {'error', term()}. +-spec start_link() -> {'ok', pid()} | {'error', any()}. start_link() -> gen_server:start_link({local, ?MODULE}, ?MODULE, [], []). --spec start() -> {'ok', pid()} | {'error', term()}. +-spec start() -> {'ok', pid()} | {'error', any()}. start() -> ensure_started(). --spec create(term()) -> 'ok'. +-type name() :: any(). + +-spec create(Name :: name()) -> 'ok'. create(Name) -> ensure_started(), @@ -55,9 +57,7 @@ create(Name) -> ok end. --type name() :: term(). - --spec delete(name()) -> 'ok'. +-spec delete(Name :: name()) -> 'ok'. delete(Name) -> ensure_started(), @@ -67,7 +67,8 @@ delete(Name) -> end), ok. --spec join(name(), pid()) -> 'ok' | {'error', {'no_such_group', term()}}. +-spec join(Name, Pid :: pid()) -> 'ok' | {'error', {'no_such_group', Name}} + when Name :: name(). join(Name, Pid) when is_pid(Pid) -> ensure_started(), @@ -83,7 +84,8 @@ join(Name, Pid) when is_pid(Pid) -> ok end. --spec leave(name(), pid()) -> 'ok' | {'error', {'no_such_group', name()}}. +-spec leave(Name, Pid :: pid()) -> 'ok' | {'error', {'no_such_group', Name}} + when Name :: name(). leave(Name, Pid) when is_pid(Pid) -> ensure_started(), @@ -99,10 +101,9 @@ leave(Name, Pid) when is_pid(Pid) -> ok end. --type get_members_ret() :: [pid()] | {'error', {'no_such_group', name()}}. +-spec get_members(Name) -> [pid()] | {'error', {'no_such_group', Name}} + when Name :: name(). --spec get_members(name()) -> get_members_ret(). - get_members(Name) -> ensure_started(), case ets:member(pg2_table, {group, Name}) of @@ -112,7 +113,8 @@ get_members(Name) -> {error, {no_such_group, Name}} end. --spec get_local_members(name()) -> get_members_ret(). +-spec get_local_members(Name) -> [pid()] | {'error', {'no_such_group', Name}} + when Name :: name(). get_local_members(Name) -> ensure_started(), @@ -123,15 +125,15 @@ get_local_members(Name) -> {error, {no_such_group, Name}} end. --spec which_groups() -> [name()]. +-spec which_groups() -> [Name :: name()]. which_groups() -> ensure_started(), all_groups(). --type gcp_error_reason() :: {'no_process', term()} | {'no_such_group', term()}. - --spec get_closest_pid(term()) -> pid() | {'error', gcp_error_reason()}. +-spec get_closest_pid(Name) -> pid() | {'error', Reason} when + Name :: name(), + Reason :: {'no_process', Name} | {'no_such_group', Name}. get_closest_pid(Name) -> case get_local_members(Name) of @@ -157,7 +159,9 @@ get_closest_pid(Name) -> -record(state, {}). --spec init([]) -> {'ok', #state{}}. +-opaque state() :: #state{}. + +-spec init(Arg :: []) -> {'ok', state()}. init([]) -> Ns = nodes(), @@ -169,13 +173,13 @@ init([]) -> pg2_table = ets:new(pg2_table, [ordered_set, protected, named_table]), {ok, #state{}}. --type call() :: {'create', name()} - | {'delete', name()} - | {'join', name(), pid()} - | {'leave', name(), pid()}. - --spec handle_call(call(), _, #state{}) -> - {'reply', 'ok', #state{}}. +-spec handle_call(Call :: {'create', Name} + | {'delete', Name} + | {'join', Name, Pid :: pid()} + | {'leave', Name, Pid :: pid()}, + From :: {pid(),Tag :: any()}, + State :: state()) -> {'reply', 'ok', state()} + when Name :: name(). handle_call({create, Name}, _From, S) -> assure_group(Name), @@ -195,11 +199,10 @@ handle_call(Request, From, S) -> [Request, From]), {noreply, S}. --type all_members() :: [[name(),...]]. --type cast() :: {'exchange', node(), all_members()} - | {'del_member', name(), pid()}. - --spec handle_cast(cast(), #state{}) -> {'noreply', #state{}}. +-spec handle_cast(Cast :: {'exchange', node(), Names :: [[Name,...]]} + | {'del_member', Name, Pid :: pid()}, + State :: state()) -> {'noreply', state()} + when Name :: name(). handle_cast({exchange, _Node, List}, S) -> store(List), @@ -208,7 +211,8 @@ handle_cast(_, S) -> %% Ignore {del_member, Name, Pid}. {noreply, S}. --spec handle_info(tuple(), #state{}) -> {'noreply', #state{}}. +-spec handle_info(Tuple :: tuple(), State :: state()) -> + {'noreply', state()}. handle_info({'DOWN', MonitorRef, process, _Pid, _Info}, S) -> member_died(MonitorRef), @@ -222,7 +226,7 @@ handle_info({new_pg2, Node}, S) -> handle_info(_, S) -> {noreply, S}. --spec terminate(term(), #state{}) -> 'ok'. +-spec terminate(Reason :: any(), State :: state()) -> 'ok'. terminate(_Reason, _S) -> true = ets:delete(pg2_table), diff --git a/lib/kernel/src/rpc.erl b/lib/kernel/src/rpc.erl index e09acb5024..e214ffa404 100644 --- a/lib/kernel/src/rpc.erl +++ b/lib/kernel/src/rpc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -263,14 +263,28 @@ proxy_user_flush() -> %% THE rpc client interface --spec call(node(), atom(), atom(), [term()]) -> term(). +-spec call(Node, Module, Function, Args) -> Res | {badrpc, Reason} when + Node :: node(), + Module :: module(), + Function :: atom(), + Args :: [term()], + Res :: term(), + Reason :: term(). call(N,M,F,A) when node() =:= N -> %% Optimize local call local_call(M, F, A); call(N,M,F,A) -> do_call(N, {call,M,F,A,group_leader()}, infinity). --spec call(node(), atom(), atom(), [term()], timeout()) -> term(). +-spec call(Node, Module, Function, Args, Timeout) -> + Res | {badrpc, Reason} when + Node :: node(), + Module :: module(), + Function :: atom(), + Args :: [term()], + Res :: term(), + Reason :: term(), + Timeout :: timeout(). call(N,M,F,A,_Timeout) when node() =:= N -> %% Optimize local call local_call(M,F,A); @@ -279,14 +293,28 @@ call(N,M,F,A,infinity) -> call(N,M,F,A,Timeout) when is_integer(Timeout), Timeout >= 0 -> do_call(N, {call,M,F,A,group_leader()}, Timeout). --spec block_call(node(), atom(), atom(), [term()]) -> term(). +-spec block_call(Node, Module, Function, Args) -> Res | {badrpc, Reason} when + Node :: node(), + Module :: module(), + Function :: atom(), + Args :: [term()], + Res :: term(), + Reason :: term(). block_call(N,M,F,A) when node() =:= N -> %% Optimize local call local_call(M,F,A); block_call(N,M,F,A) -> do_call(N, {block_call,M,F,A,group_leader()}, infinity). --spec block_call(node(), atom(), atom(), [term()], timeout()) -> term(). +-spec block_call(Node, Module, Function, Args, Timeout) -> + Res | {badrpc, Reason} when + Node :: node(), + Module :: module(), + Function :: atom(), + Args :: [term()], + Res :: term(), + Reason :: term(), + Timeout :: timeout(). block_call(N,M,F,A,_Timeout) when node() =:= N -> %% Optimize local call local_call(M, F, A); @@ -339,7 +367,13 @@ rpc_check(X) -> X. %% The entire call is packed into an atomic transaction which %% either succeeds or fails, i.e. never hangs (unless the server itself hangs). --spec server_call(node(), atom(), term(), term()) -> term() | {'error', 'nodedown'}. +-spec server_call(Node, Name, ReplyWrapper, Msg) -> Reply | {error, Reason} when + Node :: node(), + Name :: atom(), + ReplyWrapper :: term(), + Msg :: term(), + Reply :: term(), + Reason :: nodedown. server_call(Node, Name, ReplyWrapper, Msg) when is_atom(Node), is_atom(Name) -> @@ -362,7 +396,11 @@ server_call(Node, Name, ReplyWrapper, Msg) end end. --spec cast(node(), atom(), atom(), [term()]) -> 'true'. +-spec cast(Node, Module, Function, Args) -> true when + Node :: node(), + Module :: module(), + Function :: atom(), + Args :: [term()]. cast(Node, Mod, Fun, Args) when Node =:= node() -> catch spawn(Mod, Fun, Args), @@ -373,12 +411,17 @@ cast(Node, Mod, Fun, Args) -> %% Asynchronous broadcast, returns nothing, it's just send'n prey --spec abcast(atom(), term()) -> 'abcast'. +-spec abcast(Name, Msg) -> abcast when + Name :: atom(), + Msg :: term(). abcast(Name, Mess) -> abcast([node() | nodes()], Name, Mess). --spec abcast([node()], atom(), term()) -> 'abcast'. +-spec abcast(Nodes, Name, Msg) -> abcast when + Nodes :: [node()], + Name :: atom(), + Msg :: term(). abcast([Node|Tail], Name, Mess) -> Dest = {Name,Node}, @@ -396,23 +439,39 @@ abcast([], _,_) -> abcast. %% message when we return from the call, we can't know that they have %% processed the message though. --spec sbcast(atom(), term()) -> {[node()], [node()]}. +-spec sbcast(Name, Msg) -> {GoodNodes, BadNodes} when + Name :: atom(), + Msg :: term(), + GoodNodes :: [node()], + BadNodes :: [node()]. sbcast(Name, Mess) -> sbcast([node() | nodes()], Name, Mess). --spec sbcast([node()], atom(), term()) -> {[node()], [node()]}. +-spec sbcast(Nodes, Name, Msg) -> {GoodNodes, BadNodes} when + Name :: atom(), + Msg :: term(), + Nodes :: [node()], + GoodNodes :: [node()], + BadNodes :: [node()]. sbcast(Nodes, Name, Mess) -> Monitors = send_nodes(Nodes, ?NAME, {sbcast, Name, Mess}, []), rec_nodes(?NAME, Monitors). --spec eval_everywhere(atom(), atom(), [term()]) -> 'abcast'. +-spec eval_everywhere(Module, Function, Args) -> abcast when + Module :: module(), + Function :: atom(), + Args :: [term()]. eval_everywhere(Mod, Fun, Args) -> eval_everywhere([node() | nodes()] , Mod, Fun, Args). --spec eval_everywhere([node()], atom(), atom(), [term()]) -> 'abcast'. +-spec eval_everywhere(Nodes, Module, Function, Args) -> abcast when + Nodes :: [node()], + Module :: module(), + Function :: atom(), + Args :: [term()]. eval_everywhere(Nodes, Mod, Fun, Args) -> gen_server:abcast(Nodes, ?NAME, {cast,Mod,Fun,Args,group_leader()}). @@ -453,20 +512,45 @@ unmonitor(Ref) when is_reference(Ref) -> %% Call apply(M,F,A) on all nodes in parallel --spec multicall(atom(), atom(), [term()]) -> {[_], [node()]}. +-spec multicall(Module, Function, Args) -> {ResL, BadNodes} when + Module :: module(), + Function :: atom(), + Args :: [term()], + ResL :: [term()], + BadNodes :: [node()]. multicall(M, F, A) -> multicall(M, F, A, infinity). --spec multicall([node()], atom(), atom(), [term()]) -> {[_], [node()]} - ; (atom(), atom(), [term()], timeout()) -> {[_], [node()]}. +-spec multicall(Nodes, Module, Function, Args) -> {ResL, BadNodes} when + Nodes :: [node()], + Module :: module(), + Function :: atom(), + Args :: [term()], + ResL :: [term()], + BadNodes :: [node()]; + (Module, Function, Args, Timeout) -> {ResL, BadNodes} when + Module :: module(), + Function :: atom(), + Args :: [term()], + Timeout :: timeout(), + ResL :: [term()], + BadNodes :: [node()]. multicall(Nodes, M, F, A) when is_list(Nodes) -> multicall(Nodes, M, F, A, infinity); multicall(M, F, A, Timeout) -> multicall([node() | nodes()], M, F, A, Timeout). --spec multicall([node()], atom(), atom(), [term()], timeout()) -> {[_], [node()]}. +-spec multicall(Nodes, Module, Function, Args, Timeout) -> + {ResL, BadNodes} when + Nodes :: [node()], + Module :: module(), + Function :: atom(), + Args :: [term()], + Timeout :: timeout(), + ResL :: [term()], + BadNodes :: [node()]. multicall(Nodes, M, F, A, infinity) when is_list(Nodes), is_atom(M), is_atom(F), is_list(A) -> @@ -495,12 +579,21 @@ do_multicall(Nodes, M, F, A, Timeout) -> %% %% There is no apparent order among the replies. --spec multi_server_call(atom(), term()) -> {[_], [node()]}. +-spec multi_server_call(Name, Msg) -> {Replies, BadNodes} when + Name :: atom(), + Msg :: term(), + Replies :: [Reply :: term()], + BadNodes :: [node()]. multi_server_call(Name, Msg) -> multi_server_call([node() | nodes()], Name, Msg). --spec multi_server_call([node()], atom(), term()) -> {[_], [node()]}. +-spec multi_server_call(Nodes, Name, Msg) -> {Replies, BadNodes} when + Nodes :: [node()], + Name :: atom(), + Msg :: term(), + Replies :: [Reply :: term()], + BadNodes :: [node()]. multi_server_call(Nodes, Name, Msg) when is_list(Nodes), is_atom(Name) -> @@ -509,9 +602,22 @@ multi_server_call(Nodes, Name, Msg) %% Deprecated functions. Were only needed when communicating with R6 nodes. +-spec safe_multi_server_call(Name, Msg) -> {Replies, BadNodes} when + Name :: atom(), + Msg :: term(), + Replies :: [Reply :: term()], + BadNodes :: [node()]. + safe_multi_server_call(Name, Msg) -> multi_server_call(Name, Msg). +-spec safe_multi_server_call(Nodes, Name, Msg) -> {Replies, BadNodes} when + Nodes :: [node()], + Name :: atom(), + Msg :: term(), + Replies :: [Reply :: term()], + BadNodes :: [node()]. + safe_multi_server_call(Nodes, Name, Msg) -> multi_server_call(Nodes, Name, Msg). @@ -539,7 +645,14 @@ rec_nodes(Name, [{N,R} | Tail], Badnodes, Replies) -> %% rpc's towards the same node. I.e. it returns immediately and %% it returns a Key that can be used in a subsequent yield(Key). --spec async_call(node(), atom(), atom(), [term()]) -> pid(). +-opaque key() :: pid(). + +-spec async_call(Node, Module, Function, Args) -> Key when + Node :: node(), + Module :: module(), + Function :: atom(), + Args :: [term()], + Key :: key(). async_call(Node, Mod, Fun, Args) -> ReplyTo = self(), @@ -549,20 +662,28 @@ async_call(Node, Mod, Fun, Args) -> ReplyTo ! {self(), {promise_reply, R}} %% self() is key end). --spec yield(pid()) -> term(). +-spec yield(Key) -> Res | {badrpc, Reason} when + Key :: key(), + Res :: term(), + Reason :: term(). yield(Key) when is_pid(Key) -> {value,R} = do_yield(Key, infinity), R. --spec nb_yield(pid(), timeout()) -> {'value', _} | 'timeout'. +-spec nb_yield(Key, Timeout) -> {value, Val} | timeout when + Key :: key(), + Timeout :: timeout(), + Val :: (Res :: term()) | {badrpc, Reason :: term()}. nb_yield(Key, infinity=Inf) when is_pid(Key) -> do_yield(Key, Inf); nb_yield(Key, Timeout) when is_pid(Key), is_integer(Timeout), Timeout >= 0 -> do_yield(Key, Timeout). --spec nb_yield(pid()) -> {'value', _} | 'timeout'. +-spec nb_yield(Key) -> {value, Val} | timeout when + Key :: key(), + Val :: (Res :: term()) | {badrpc, Reason :: term()}. nb_yield(Key) when is_pid(Key) -> do_yield(Key, 0). @@ -582,7 +703,12 @@ do_yield(Key, Timeout) -> %% ArgL === [{M,F,Args},........] %% Returns a lists of the evaluations in the same order as %% given to ArgL --spec parallel_eval([{atom(), atom(), [_]}]) -> [_]. +-spec parallel_eval(FuncCalls) -> ResL when + FuncCalls :: [{Module, Function, Args}], + Module :: module(), + Function :: atom(), + Args :: [term()], + ResL :: [term()]. parallel_eval(ArgL) -> Nodes = [node() | nodes()], @@ -599,7 +725,13 @@ map_nodes([{M,F,A}|Tail],[Node|MoreNodes], Original) -> %% Parallel version of lists:map/3 with exactly the same %% arguments and return value as lists:map/3, %% except that it calls exit/1 if a network error occurs. --spec pmap({atom(),atom()}, [term()], [term()]) -> [term()]. +-spec pmap(FuncSpec, ExtraArgs, List1) -> List2 when + FuncSpec :: {Module,Function}, + Module :: module(), + Function :: atom(), + ExtraArgs :: [term()], + List1 :: [Elem :: term()], + List2 :: [term()]. pmap({M,F}, As, List) -> check(parallel_eval(build_args(M,F,As, List, [])), []). @@ -616,15 +748,20 @@ check([], Ack) -> Ack. %% location transparent version of process_info --spec pinfo(pid()) -> [{atom(), _}] | 'undefined'. +-spec pinfo(Pid) -> [{Item, Info}] | undefined when + Pid :: pid(), + Item :: atom(), + Info :: term(). pinfo(Pid) when node(Pid) =:= node() -> process_info(Pid); pinfo(Pid) -> call(node(Pid), erlang, process_info, [Pid]). --spec pinfo(pid(), Item) -> {Item, _} | 'undefined' | [] - when is_subtype(Item, atom()). +-spec pinfo(Pid, Item) -> {Item, Info} | undefined | [] when + Pid :: pid(), + Item :: atom(), + Info :: term(). pinfo(Pid, Item) when node(Pid) =:= node() -> process_info(Pid, Item); diff --git a/lib/kernel/src/seq_trace.erl b/lib/kernel/src/seq_trace.erl index 78c3040f21..a90b7b07c8 100644 --- a/lib/kernel/src/seq_trace.erl +++ b/lib/kernel/src/seq_trace.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2009. All Rights Reserved. +%% Copyright Ericsson AB 1998-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -38,15 +38,17 @@ -type flag() :: 'send' | 'receive' | 'print' | 'timestamp'. -type component() :: 'label' | 'serial' | flag(). --type value() :: non_neg_integer() - | {non_neg_integer(), non_neg_integer()} - | boolean(). --type token_pair() :: {component(), value()}. +-type value() :: (Integer :: non_neg_integer()) + | {Previous :: non_neg_integer(), + Current :: non_neg_integer()} + | (Bool :: boolean()). %%--------------------------------------------------------------------------- --type token() :: [] | {integer(), boolean(), _, _, _}. --spec set_token(token()) -> token() | 'ok'. +-type token() :: {integer(), boolean(), _, _, _}. +-spec set_token(Token) -> PreviousToken | 'ok' when + Token :: [] | token(), + PreviousToken :: [] | token(). set_token([]) -> erlang:seq_trace(sequential_trace_token,[]); @@ -58,28 +60,35 @@ set_token({Flags,Label,Serial,_From,Lastcnt}) -> %% expects that, the BIF can however "unofficially" handle atoms as well, and %% atoms can be used if only Erlang nodes are involved --spec set_token(component(), value()) -> token_pair(). +-spec set_token(Component, Val) -> {Component, OldVal} when + Component :: component(), + Val :: value(), + OldVal :: value(). set_token(Type, Val) -> erlang:seq_trace(Type, Val). --spec get_token() -> term(). +-spec get_token() -> [] | token(). get_token() -> element(2,process_info(self(),sequential_trace_token)). --spec get_token(component()) -> token_pair(). - +-spec get_token(Component) -> {Component, Val} when + Component :: component(), + Val :: value(). get_token(Type) -> erlang:seq_trace_info(Type). --spec print(term()) -> 'ok'. +-spec print(TraceInfo) -> 'ok' when + TraceInfo :: term(). print(Term) -> erlang:seq_trace_print(Term), ok. --spec print(integer(), term()) -> 'ok'. +-spec print(Label, TraceInfo) -> 'ok' when + Label :: integer(), + TraceInfo :: term(). print(Label, Term) when is_atom(Label) -> erlang:error(badarg, [Label, Term]); @@ -94,14 +103,17 @@ reset_trace() -> %% reset_trace(Pid) -> % this might be a useful function too --type tracer() :: pid() | port() | 'false'. +-type tracer() :: (Pid :: pid()) | port() | 'false'. --spec set_system_tracer(tracer()) -> tracer(). +-spec set_system_tracer(Tracer) -> OldTracer when + Tracer :: tracer(), + OldTracer :: tracer(). set_system_tracer(Pid) -> erlang:system_flag(sequential_tracer, Pid). --spec get_system_tracer() -> tracer(). +-spec get_system_tracer() -> Tracer when + Tracer :: tracer(). get_system_tracer() -> element(2, erlang:system_info(sequential_tracer)). diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl index c34f2ddeb0..e33b4830ab 100644 --- a/lib/kernel/src/user_drv.erl +++ b/lib/kernel/src/user_drv.erl @@ -117,8 +117,9 @@ server1(Iport, Oport, Shell) -> {Curr,Shell1} = case init:get_argument(remsh) of {ok,[[Node]]} -> - RShell = {list_to_atom(Node),shell,start,[]}, - RGr = group:start(self(), RShell), + ANode = list_to_atom(Node), + RShell = {ANode,shell,start,[]}, + RGr = group:start(self(), RShell, rem_sh_opts(ANode)), {RGr,RShell}; E when E =:= error ; E =:= {ok,[[]]} -> {group:start(self(), Shell),Shell} @@ -134,6 +135,9 @@ server1(Iport, Oport, Shell) -> %% Enter the server loop. server_loop(Iport, Oport, Curr, User, Gr). +rem_sh_opts(Node) -> + [{expand_fun,fun(B)-> rpc:call(Node,edlin_expand,expand,[B]) end}]. + %% start_user() %% Start a group leader process and register it as 'user', unless, %% of course, a 'user' already exists. diff --git a/lib/kernel/src/wrap_log_reader.erl b/lib/kernel/src/wrap_log_reader.erl index fabaa07752..c41e0091e4 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-2010. All Rights Reserved. +%% Copyright Ericsson AB 1998-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -41,6 +41,8 @@ first_no :: non_neg_integer() | 'one' % first read file number }). +-opaque continuation() :: #wrap_reader{}. + %% %% Exported functions %% @@ -50,9 +52,11 @@ %% is not yet reached, we are on the first 'round' of filling the wrap %% files. --type open_ret() :: {'ok', #wrap_reader{}} | {'error', tuple()}. +-type open_ret() :: {'ok', Continuation :: continuation()} + | {'error', Reason :: tuple()}. --spec open(atom() | string()) -> open_ret(). +-spec open(Filename) -> open_ret() when + Filename :: string() | atom(). open(File) when is_atom(File) -> open(atom_to_list(File)); @@ -77,7 +81,9 @@ open(File) when is_list(File) -> Error end. --spec open(atom() | string(), integer()) -> open_ret(). +-spec open(Filename, N) -> open_ret() when + Filename :: string() | atom(), + N :: integer(). open(File, FileNo) when is_atom(File), is_integer(FileNo) -> open(atom_to_list(File), FileNo); @@ -100,22 +106,29 @@ open(File, FileNo) when is_list(File), is_integer(FileNo) -> Error end. --spec close(#wrap_reader{}) -> 'ok' | {'error', atom()}. +-spec close(Continuation) -> 'ok' | {'error', Reason} when + Continuation :: continuation(), + Reason :: file:posix(). close(#wrap_reader{fd = FD}) -> file:close(FD). --type chunk_ret() :: {#wrap_reader{}, [term()]} - | {#wrap_reader{}, [term()], non_neg_integer()} - | {#wrap_reader{}, 'eof'} - | {'error', term()}. +-type chunk_ret() :: {Continuation2, Terms :: [term()]} + | {Continuation2, + Terms :: [term()], + Badbytes :: non_neg_integer()} + | {Continuation2, 'eof'} + | {'error', Reason :: term()}. --spec chunk(#wrap_reader{}) -> chunk_ret(). +-spec chunk(Continuation) -> chunk_ret() when + Continuation :: continuation(). chunk(WR = #wrap_reader{}) -> chunk(WR, ?MAX_CHUNK_SIZE, 0). --spec chunk(#wrap_reader{}, 'infinity' | pos_integer()) -> chunk_ret(). +-spec chunk(Continuation, N) -> chunk_ret() when + Continuation :: continuation(), + N :: infinity | pos_integer(). chunk(WR = #wrap_reader{}, infinity) -> chunk(WR, ?MAX_CHUNK_SIZE, 0); diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index 95517ffd6a..82bc3fc6d1 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2010. All Rights Reserved. +# Copyright Ericsson AB 1997-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl index 4ae4151004..f469a0af98 100644 --- a/lib/kernel/test/application_SUITE.erl +++ b/lib/kernel/test/application_SUITE.erl @@ -33,7 +33,7 @@ -export([config_change/1, distr_changed_tc1/1, distr_changed_tc2/1, - shutdown_func/1, do_shutdown/1]). + shutdown_func/1, do_shutdown/1, shutdown_timeout/1]). -define(TESTCASE, testcase_name). -define(testcase, ?config(?TESTCASE, Config)). @@ -50,7 +50,7 @@ all() -> load_use_cache, {group, reported_bugs}, start_phases, script_start, nodedown_start, permit_false_start_local, permit_false_start_dist, get_key, - {group, distr_changed}, config_change, shutdown_func]. + {group, distr_changed}, config_change, shutdown_func, shutdown_timeout]. groups() -> [{reported_bugs, [], @@ -967,7 +967,7 @@ otp_1586(doc) -> ["Test recursive load of applications."]; otp_1586(Conf) when is_list(Conf) -> Dir = ?config(priv_dir,Conf), - {ok, Fd} = file:open(filename:join(Dir, "app5.app"), write), + {ok, Fd} = file:open(filename:join(Dir, "app5.app"), [write]), w_app5(Fd), file:close(Fd), ?line code:add_patha(Dir), @@ -1021,10 +1021,10 @@ otp_2012(Conf) when is_list(Conf) -> ?line yes = global:register_name(conf_change, CcPid), % Write a .app file - {ok, Fd} = file:open("app1.app", write), + {ok, Fd} = file:open("app1.app", [write]), w_app1(Fd), file:close(Fd), - {ok, Fd2} = file:open("app2.app", write), + {ok, Fd2} = file:open("app2.app", [write]), w_app1(Fd2), file:close(Fd2), @@ -1096,7 +1096,7 @@ otp_2973(doc) -> ["Test of two processes simultanously starting the same application."]; otp_2973(Conf) when is_list(Conf) -> % Write a .app file - {ok, Fd} = file:open("app0.app", write), + {ok, Fd} = file:open("app0.app", [write]), w_app(Fd, app0()), file:close(Fd), @@ -1138,7 +1138,7 @@ otp_2973(Conf) when is_list(Conf) -> % Write a .app file - ?line {ok, Fda} = file:open("app_start_error.app", write), + ?line {ok, Fda} = file:open("app_start_error.app", [write]), ?line w_app_start_error(Fda), ?line file:close(Fda), @@ -1273,12 +1273,12 @@ otp_4066(Conf) when is_list(Conf) -> App1Nodes = {app1, AllNodes}, Dir = ?config(priv_dir,Conf), - ?line {ok, FdC} = file:open(filename:join(Dir, "otp_4066.config"), write), + ?line {ok, FdC} = file:open(filename:join(Dir, "otp_4066.config"), [write]), ?line write_config(FdC, config_4066(AllNodes, 5000, [App1Nodes])), ?line file:close(FdC), % Write the app1.app file - ?line {ok, FdA12} = file:open(filename:join(Dir, "app1.app"), write), + ?line {ok, FdA12} = file:open(filename:join(Dir, "app1.app"), [write]), ?line w_app1(FdA12), ?line file:close(FdA12), @@ -1441,7 +1441,7 @@ otp_5606(Conf) when is_list(Conf) -> %% Write a config file Dir = ?config(priv_dir, Conf), - {ok, Fd} = file:open(filename:join(Dir, "sys.config"), write), + {ok, Fd} = file:open(filename:join(Dir, "sys.config"), [write]), NodeNames = [Ncp1, Ncp2] = node_names([cp1, cp2], Conf), (config4(NodeNames))(Fd, 10000), file:close(Fd), @@ -1915,6 +1915,32 @@ do_shutdown(Reason) -> +%%%----------------------------------------------------------------- +%%% Tests the 'shutdown_timeout' kernel config parameter +%%%----------------------------------------------------------------- +shutdown_timeout(Config) when is_list(Config) -> + DataDir = ?config(data_dir,Config), + {ok,Cp1} = start_node(?MODULE_STRING++"_shutdown_timeout"), + wait_for_ready_net(), + ok = rpc:call(Cp1, application, set_env, [kernel, shutdown_timeout, 1000]), + rpc:call(Cp1, code, add_path, [filename:join([DataDir,deadlock])]), + ok = rpc:call(Cp1, application, start, [sasl]), + ok = rpc:call(Cp1, application, start, [deadlock]), + rpc:call(Cp1, deadlock, restart_and_fail, []), + + ok = net_kernel:monitor_nodes(true), + _ = rpc:call(Cp1, init, stop, []), + receive + {nodedown,Cp1} -> + ok + after 10000 -> + ct:fail("timeout 10 sec: node termination hangs") + end, + ok. + + + + %%----------------------------------------------------------------- %% Utility functions %%----------------------------------------------------------------- @@ -2436,7 +2462,7 @@ start_node_config_sf(Name, SysConfigFun, Conf) -> write_config_file(SysConfigFun, Conf) -> Dir = ?config(priv_dir, Conf), - {ok, Fd} = file:open(filename:join(Dir, "sys.config"), write), + {ok, Fd} = file:open(filename:join(Dir, "sys.config"), [write]), SysConfigFun(Fd), file:close(Fd), filename:join(Dir,"sys"). @@ -2571,15 +2597,15 @@ cc(List) -> create_app() -> ?line Dir = "./", ?line App1 = Dir ++ "app1", - ?line {ok, Fd1} = file:open(App1++".app",write), + ?line {ok, Fd1} = file:open(App1++".app",[write]), ?line io:format(Fd1, "~p. \n", [app1()]), ?line file:close(Fd1), ?line App2 = Dir ++ "app2", - ?line {ok, Fd2} = file:open(App2++".app",write), + ?line {ok, Fd2} = file:open(App2++".app",[write]), ?line io:format(Fd2, "~p. \n", [app2()]), ?line file:close(Fd2), ?line App3 = Dir ++ "app_sp", - ?line {ok, Fd3} = file:open(App3++".app",write), + ?line {ok, Fd3} = file:open(App3++".app",[write]), ?line io:format(Fd3, "~p. \n", [app_sp()]), ?line file:close(Fd3), ok. @@ -2591,7 +2617,7 @@ create_script(ScriptName) -> ?line Apps = which_applications(), ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), + ?line {ok,Fd} = file:open(Name++".rel",[write]), ?line io:format(Fd, "{release, {\"Test release 3\", \"LATEST\"}, \n" " {erts, \"4.4\"}, \n" @@ -2610,7 +2636,7 @@ create_script_dc(ScriptName) -> ?line Apps = which_applications(), ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), + ?line {ok,Fd} = file:open(Name++".rel",[write]), ?line io:format(Fd, "{release, {\"Test release 3\", \"LATEST\"}, \n" " {erts, \"4.4\"}, \n" @@ -2630,7 +2656,7 @@ create_script_3002(ScriptName) -> ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), ?line {value,{_,_,SaslVer}} = lists:keysearch(sasl,1,Apps), - ?line {ok,Fd} = file:open(Name++".rel",write), + ?line {ok,Fd} = file:open(Name++".rel",[write]), ?line io:format(Fd, "{release, {\"Test release 3\", \"LATEST\"}, \n" " {erts, \"4.4\"}, \n" @@ -2646,22 +2672,22 @@ create_script_3002(ScriptName) -> distr_changed_prep(Conf) when is_list(Conf) -> % Write .app files - ?line {ok, Fd1} = file:open("app1.app", write), + ?line {ok, Fd1} = file:open("app1.app", [write]), ?line w_app1(Fd1), ?line file:close(Fd1), - ?line {ok, Fd2} = file:open("app2.app", write), + ?line {ok, Fd2} = file:open("app2.app", [write]), ?line w_app2(Fd2), ?line file:close(Fd2), - ?line {ok, Fd3} = file:open("app3.app", write), + ?line {ok, Fd3} = file:open("app3.app", [write]), ?line w_app3(Fd3), ?line file:close(Fd3), - ?line {ok, Fd4} = file:open("app6.app", write), + ?line {ok, Fd4} = file:open("app6.app", [write]), ?line w_app6(Fd4), ?line file:close(Fd4), - ?line {ok, Fd5} = file:open("app7.app", write), + ?line {ok, Fd5} = file:open("app7.app", [write]), ?line w_app7(Fd5), ?line file:close(Fd5), - ?line {ok, Fd6} = file:open("app8.app", write), + ?line {ok, Fd6} = file:open("app8.app", [write]), ?line w_app8(Fd6), ?line file:close(Fd6), @@ -2683,7 +2709,7 @@ distr_changed_prep(Conf) when is_list(Conf) -> WithSyncTime = config_fun(config_dc(NodeNames)), ?line Dir = ?config(priv_dir,Conf), - ?line {ok, Fd_dc2} = file:open(filename:join(Dir, "sys2.config"), write), + ?line {ok, Fd_dc2} = file:open(filename:join(Dir, "sys2.config"), [write]), ?line (config_dc2(NodeNames))(Fd_dc2), ?line file:close(Fd_dc2), ?line Config2 = filename:join(Dir, "sys2"), diff --git a/lib/kernel/test/application_SUITE_data/Makefile.src b/lib/kernel/test/application_SUITE_data/Makefile.src index a237f6badb..abc3c82907 100644 --- a/lib/kernel/test/application_SUITE_data/Makefile.src +++ b/lib/kernel/test/application_SUITE_data/Makefile.src @@ -2,7 +2,8 @@ EFLAGS=+debug_info all: app_start_error.@EMULATOR@ trans_abnormal_sup.@EMULATOR@ \ trans_normal_sup.@EMULATOR@ transient.@EMULATOR@ \ - group_leader_sup.@EMULATOR@ group_leader.@EMULATOR@ + group_leader_sup.@EMULATOR@ group_leader.@EMULATOR@ \ + deadlock/deadlock.@EMULATOR@ app_start_error.@EMULATOR@: app_start_error.erl erlc $(EFLAGS) app_start_error.erl @@ -22,3 +23,5 @@ group_leader.@EMULATOR@: group_leader.erl group_leader_sup.@EMULATOR@: group_leader_sup.erl erlc $(EFLAGS) group_leader_sup.erl +deadlock/deadlock.@EMULATOR@: deadlock/deadlock.erl + erlc $(EFLAGS) -o deadlock deadlock/deadlock.erl
\ No newline at end of file diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app new file mode 100644 index 0000000000..0c1001bed6 --- /dev/null +++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app @@ -0,0 +1,8 @@ +{application, deadlock, [ + {vsn, "1"}, + {registered, []}, + {applications, [kernel, stdlib, sasl]}, + {modules, [deadlock]}, + {mod, {deadlock, []}}, + {env, [{fail_start, false}]} +]}. diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl new file mode 100644 index 0000000000..5f68bf9078 --- /dev/null +++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl @@ -0,0 +1,69 @@ +-module(deadlock). +-behaviour(application). +-compile(export_all). +-define(SUP,deadlock_sup). +-define(CHILD,deadlock_child). + + +%%%----------------------------------------------------------------- +%%% application callbacks +start(_StartType, _StartArgs) -> + supervisor:start_link({local, ?SUP}, ?MODULE, [sup]). + +stop(_State) -> + ok. + + + +%%%----------------------------------------------------------------- +%%% supervisor callbacks +init([sup]) -> + {ok, {{one_for_one, 5, 10}, [ + { + sasl_syslog_dm, {?MODULE, start_link, []}, + permanent, brutal_kill, worker, + [deadlock] + } + ]}}; + + +%%%----------------------------------------------------------------- +%%% gen_server callbacks +init([child]) -> + case application:get_env(deadlock, fail_start) of + {ok, false} -> + %% we must not fail on the first init, otherwise supervisor + %% terminates immediately + {ok, []}; + {ok, true} -> + timer:sleep(infinity), % init hangs!!!! + {ok, []} + end. + +handle_call(_Req, _From, State) -> + {reply, ok, State}. + +handle_cast(restart, State) -> + {stop, error, State}. + +handle_info(_Msg, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + + +%%%----------------------------------------------------------------- +%%% Start child +start_link() -> + gen_server:start_link({local, ?CHILD}, ?MODULE, [child], []). + + +%%%----------------------------------------------------------------- +%%% Provoke hanging +restart_and_fail() -> + application:set_env(deadlock, fail_start, true), % next init will hang + gen_server:cast(?CHILD, restart). diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl index 3ad49254f1..10ab3e4370 100644 --- a/lib/kernel/test/code_SUITE.erl +++ b/lib/kernel/test/code_SUITE.erl @@ -81,6 +81,13 @@ init_per_suite(Config) -> end_per_suite(Config) -> Config. +init_per_testcase(big_boot_embedded, Config) -> + case catch crypto:start() of + ok -> + init_per_testcase(do_big_boot_embedded, Config); + _Else -> + {skip, "Needs crypto!"} + end; init_per_testcase(_Func, Config) -> Dog=?t:timetrap(?t:minutes(5)), P=code:get_path(), @@ -258,8 +265,8 @@ replace_path(Config) when is_list(Config) -> %% Add a completly new application. - NewAppName = "blurf_blarfer", - ?line NewAppDir = filename:join(Cwd, NewAppName ++ "-6.33.1"), + NewAppName = 'blurf_blarfer', + ?line NewAppDir = filename:join(Cwd, atom_to_list(NewAppName) ++ "-6.33.1"), ?line ok = file:make_dir(NewAppDir), ?line true = code:replace_path(NewAppName, NewAppDir), ?line NewAppDir = code:lib_dir(NewAppName), @@ -410,8 +417,10 @@ all_loaded_1() -> ?line Loaded2 = match_and_remove(Preloaded, Loaded1), ObjExt = code:objfile_extension(), - ?line [] = lists:filter(fun({Mod,AbsName}) when is_atom(Mod), is_list(AbsName) -> - Mod =:= filename:basename(AbsName, ObjExt); + ?line [] = lists:filter(fun({Mod,AbsName}) when is_atom(Mod), + is_list(AbsName) -> + Mod =/= list_to_atom(filename:basename(AbsName, + ObjExt)); (_) -> true end, Loaded2), @@ -571,11 +580,13 @@ add_del_path(Config) when is_list(Config) -> clash(Config) when is_list(Config) -> DDir = ?config(data_dir,Config)++"clash/", P = code:get_path(), + [TestServerPath|_] = [Path || Path <- code:get_path(), + re:run(Path,"test_server/?$",[]) /= nomatch], %% test non-clashing entries - %% remove "." to prevent clash with test-server path - ?line true = code:del_path("."), + %% remove TestServerPath to prevent clash with test-server path + ?line true = code:del_path(TestServerPath), ?line true = code:add_path(DDir++"foobar-0.1/ebin"), ?line true = code:add_path(DDir++"zork-0.8/ebin"), test_server:capture_start(), @@ -587,8 +598,8 @@ clash(Config) when is_list(Config) -> %% test clashing entries - %% remove "." to prevent clash with test-server path - ?line true = code:del_path("."), + %% remove TestServerPath to prevent clash with test-server path + ?line true = code:del_path(TestServerPath), ?line true = code:add_path(DDir++"foobar-0.1/ebin"), ?line true = code:add_path(DDir++"foobar-0.1.ez/foobar-0.1/ebin"), test_server:capture_start(), @@ -601,9 +612,9 @@ clash(Config) when is_list(Config) -> %% test "Bad path can't read" - %% remove "." to prevent clash with test-server path + %% remove TestServerPath to prevent clash with test-server path Priv = ?config(priv_dir, Config), - ?line true = code:del_path("."), + ?line true = code:del_path(TestServerPath), TmpEzFile = Priv++"foobar-0.tmp.ez", ?line {ok, _} = file:copy(DDir++"foobar-0.1.ez", TmpEzFile), ?line true = code:add_path(TmpEzFile++"/foobar-0.1/ebin"), @@ -984,9 +995,9 @@ purge_stacktrace(Config) when is_list(Config) -> error:function_clause -> ?line code:load_file(code_b_test), ?line case erlang:get_stacktrace() of - [{?MODULE,_,[a]}, - {code_b_test,call,2}, - {?MODULE,purge_stacktrace,1}|_] -> + [{?MODULE,_,[a],_}, + {code_b_test,call,2,_}, + {?MODULE,purge_stacktrace,1,_}|_] -> ?line false = code:purge(code_b_test), ?line [] = erlang:get_stacktrace() end @@ -996,8 +1007,8 @@ purge_stacktrace(Config) when is_list(Config) -> error:function_clause -> ?line code:load_file(code_b_test), ?line case erlang:get_stacktrace() of - [{code_b_test,call,[nofun,2]}, - {?MODULE,purge_stacktrace,1}|_] -> + [{code_b_test,call,[nofun,2],_}, + {?MODULE,purge_stacktrace,1,_}|_] -> ?line false = code:purge(code_b_test), ?line [] = erlang:get_stacktrace() end @@ -1008,8 +1019,8 @@ purge_stacktrace(Config) when is_list(Config) -> error:badarg -> ?line code:load_file(code_b_test), ?line case erlang:get_stacktrace() of - [{code_b_test,call,Args}, - {?MODULE,purge_stacktrace,1}|_] -> + [{code_b_test,call,Args,_}, + {?MODULE,purge_stacktrace,1,_}|_] -> ?line false = code:purge(code_b_test), ?line [] = erlang:get_stacktrace() end @@ -1023,8 +1034,8 @@ mult_lib_roots(Config) when is_list(Config) -> "my_dummy_app-c/ebin/code_SUITE_mult_root_module"), %% Set up ERL_LIBS and start a slave node. - ErlLibs = filename:join(DataDir, first_root) ++ mult_lib_sep() ++ - filename:join(DataDir, second_root), + ErlLibs = filename:join(DataDir, "first_root") ++ mult_lib_sep() ++ + filename:join(DataDir, "second_root"), ?line {ok,Node} = ?t:start_node(mult_lib_roots, slave, @@ -1344,7 +1355,7 @@ create_script(Config) -> ?line Apps = application_controller:which_applications(), ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel, 1, Apps), ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib, 1, Apps), - ?line {ok,Fd} = file:open(Name ++ ".rel", write), + ?line {ok,Fd} = file:open(Name ++ ".rel", [write]), ?line io:format(Fd, "{release, {\"Test release 3\", \"P2A\"}, \n" " {erts, \"9.42\"}, \n" @@ -1409,7 +1420,7 @@ create_big_script(Config,Local) -> %% Now we should have only "real" applications... ?line [application:load(list_to_atom(Y)) || {match,[Y]} <- [ re:run(X,code:lib_dir()++"/"++"([^/-]*).*/ebin",[{capture,[1],list}]) || X <- code:get_path()],filter_app(Y,Local)], ?line Apps = [ {N,V} || {N,_,V} <- application:loaded_applications()], - ?line {ok,Fd} = file:open(Name ++ ".rel", write), + ?line {ok,Fd} = file:open(Name ++ ".rel", [write]), ?line io:format(Fd, "{release, {\"Test release 3\", \"P2A\"}, \n" " {erts, \"9.42\"}, \n" @@ -1470,7 +1481,7 @@ do_on_load_error(ReturnValue) -> ?line ErrorPid ! ReturnValue, receive {'DOWN',Ref,process,_,Exit} -> - ?line {undef,[{on_load_error,main,[]}|_]} = Exit + ?line {undef,[{on_load_error,main,[],_}|_]} = Exit end. native_early_modules(suite) -> []; diff --git a/lib/kernel/test/disk_log_SUITE.erl b/lib/kernel/test/disk_log_SUITE.erl index 4ae47b4762..ad987fe7a7 100644 --- a/lib/kernel/test/disk_log_SUITE.erl +++ b/lib/kernel/test/disk_log_SUITE.erl @@ -1831,11 +1831,16 @@ block_queue2(Conf) when is_list(Conf) -> %% Asynchronous stuff is ignored. ?line ok = disk_log:balog_terms(n, [<<"foo">>,<<"bar">>]), ?line ok = disk_log:balog_terms(n, [<<"more">>,<<"terms">>]), + Parent = self(), ?line Fun = - fun() -> {error,disk_log_stopped} = disk_log:sync(n) + fun() -> + {error,no_such_log} = disk_log:sync(n), + receive {disk_log, _, {error, disk_log_stopped}} -> ok end, + Parent ! disk_log_stopped_ok end, ?line spawn(Fun), ?line ok = sync_do(Pid, close), + ?line receive disk_log_stopped_ok -> ok end, ?line sync_do(Pid, terminate), ?line {ok,<<>>} = file:read_file(File ++ ".1"), ?line del(File, No), @@ -2708,7 +2713,7 @@ error_log(Conf) when is_list(Conf) -> % reopen (rename) fails, the log is terminated, ./File.2/ exists ?line {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt}, {format, external},{size, 100000}]), - ?line {error, eisdir} = disk_log:reopen(n, LDir), + ?line {error, {file_error, _, eisdir}} = disk_log:reopen(n, LDir), ?line true = (P0 == pps()), ?line file:delete(File), @@ -2719,7 +2724,7 @@ error_log(Conf) when is_list(Conf) -> ?line {ok, n} = disk_log:open([{name, n}, {file, File2}, {type, wrap}, {format, external},{size, {100, No}}]), ?line ok = disk_log:blog_terms(n, [B,B,B]), - ?line {error, eisdir} = disk_log:reopen(n, File), + ?line {error, {file_error, _, eisdir}} = disk_log:reopen(n, File), ?line {error, no_such_log} = disk_log:close(n), ?line del(File2, No), ?line del(File, No), @@ -4917,7 +4922,7 @@ mark(FileName, What) -> ok = file:close(Fd). crash(File, Where) -> - {ok, Fd} = file:open(File, read_write), + {ok, Fd} = file:open(File, [read,write]), file:position(Fd, Where), ok = file:write(Fd, [10]), ok = file:close(Fd). @@ -4933,7 +4938,7 @@ writable(Fname) -> file:write_file_info(Fname, Info#file_info{mode = Mode}). truncate(File, Where) -> - {ok, Fd} = file:open(File, read_write), + {ok, Fd} = file:open(File, [read,write]), file:position(Fd, Where), ok = file:truncate(Fd), ok = file:close(Fd). diff --git a/lib/kernel/test/erl_boot_server_SUITE.erl b/lib/kernel/test/erl_boot_server_SUITE.erl index cea3715ce4..bb64c01058 100644 --- a/lib/kernel/test/erl_boot_server_SUITE.erl +++ b/lib/kernel/test/erl_boot_server_SUITE.erl @@ -346,7 +346,7 @@ good_hosts(_Config) -> [GoodHost1, GoodHost2, GoodHost3]. open_udp() -> - ?line {ok, S} = prim_inet:open(udp, inet), + ?line {ok, S} = prim_inet:open(udp, inet, dgram), ?line ok = prim_inet:setopts(S, [{mode,list},{active,true}, {deliver,term},{broadcast,true}]), ?line {ok,_} = prim_inet:bind(S, {0,0,0,0}, 0), diff --git a/lib/kernel/test/erl_prim_loader_SUITE.erl b/lib/kernel/test/erl_prim_loader_SUITE.erl index f47c4603cf..7599a89779 100644 --- a/lib/kernel/test/erl_prim_loader_SUITE.erl +++ b/lib/kernel/test/erl_prim_loader_SUITE.erl @@ -547,8 +547,6 @@ host() -> stop_node(Node) -> test_server:stop_node(Node). -get_loader_flag({ose,_}) -> - " -loader ose_inet "; get_loader_flag(_) -> " -loader inet ". diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 8078c7d021..77fc7e73f9 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -360,41 +360,50 @@ make_del_dir(Config) when is_list(Config) -> ?line {error, eexist} = ?FILE_MODULE:make_dir(NewDir), ?line ok = ?FILE_MODULE:del_dir(NewDir), ?line {error, enoent} = ?FILE_MODULE:del_dir(NewDir), - - %% Check that we get an error when trying to create... - %% a deep directory - ?line NewDir2 = filename:join(RootDir, - atom_to_list(?MODULE) - ++"_mk-dir/foo"), - ?line {error, enoent} = ?FILE_MODULE:make_dir(NewDir2), - %% a nameless directory - ?line {error, enoent} = ?FILE_MODULE:make_dir(""), - %% a directory with illegal name - ?line {error, badarg} = ?FILE_MODULE:make_dir({1,2,3}), - - %% a directory with illegal name, even if it's a (bad) list - ?line {error, badarg} = ?FILE_MODULE:make_dir([1,2,3,{}]), - - %% Maybe this isn't an error, exactly, but worth mentioning anyway: - %% ok = ?FILE_MODULE:make_dir([$f,$o,$o,0,$b,$a,$r])), - %% The above line works, and created a directory "./foo" - %% More elegant would maybe have been to fail, or to really create - %% a directory, but with a name that incorporates the "bar" part of - %% the list, so that [$f,$o,$o,0,$f,$o,$o] wouldn't refer to the same - %% dir. But this would slow it down. - - %% Try deleting some bad directories - %% Deleting the parent directory to the current, sounds dangerous, huh? - %% Don't worry ;-) the parent directory should never be empty, right? - case ?FILE_MODULE:del_dir('..') of - {error, eexist} -> ok; - {error, einval} -> ok %FreeBSD + % Make sure we are not in a directory directly under test_server + % as that would result in eacess errors when trying to delere '..', + % because there are processes having that directory as current. + ?line ok = ?FILE_MODULE:make_dir(NewDir), + ?line {ok,CurrentDir} = file:get_cwd(), + ?line ok = ?FILE_MODULE:set_cwd(NewDir), + try + %% Check that we get an error when trying to create... + %% a deep directory + ?line NewDir2 = filename:join(RootDir, + atom_to_list(?MODULE) + ++"_mk-dir-noexist/foo"), + ?line {error, enoent} = ?FILE_MODULE:make_dir(NewDir2), + %% a nameless directory + ?line {error, enoent} = ?FILE_MODULE:make_dir(""), + %% a directory with illegal name + ?line {error, badarg} = ?FILE_MODULE:make_dir({1,2,3}), + + %% a directory with illegal name, even if it's a (bad) list + ?line {error, badarg} = ?FILE_MODULE:make_dir([1,2,3,{}]), + + %% Maybe this isn't an error, exactly, but worth mentioning anyway: + %% ok = ?FILE_MODULE:make_dir([$f,$o,$o,0,$b,$a,$r])), + %% The above line works, and created a directory "./foo" + %% More elegant would maybe have been to fail, or to really create + %% a directory, but with a name that incorporates the "bar" part of + %% the list, so that [$f,$o,$o,0,$f,$o,$o] wouldn't refer to the same + %% dir. But this would slow it down. + + %% Try deleting some bad directories + %% Deleting the parent directory to the current, sounds dangerous, huh? + %% Don't worry ;-) the parent directory should never be empty, right? + ?line case ?FILE_MODULE:del_dir('..') of + {error, eexist} -> ok; + {error, einval} -> ok %FreeBSD + end, + ?line {error, enoent} = ?FILE_MODULE:del_dir(""), + ?line {error, badarg} = ?FILE_MODULE:del_dir([3,2,1,{}]), + + ?line [] = flush(), + ?line test_server:timetrap_cancel(Dog) + after + ?FILE_MODULE:set_cwd(CurrentDir) end, - ?line {error, enoent} = ?FILE_MODULE:del_dir(""), - ?line {error, badarg} = ?FILE_MODULE:del_dir([3,2,1,{}]), - - ?line [] = flush(), - ?line test_server:timetrap_cancel(Dog), ok. cur_dir_0(suite) -> []; @@ -2055,6 +2064,10 @@ try_read_file_list(Fd) -> ?line Title = "Real Programmers Don't Use PASCAL</TITLE>\n", ?line Title = io:get_line(Fd, ''), + %% Seek past the end of the file. + + ?line {ok, _} = ?FILE_MODULE:position(Fd, 25000), + %% Done. ?line ?FILE_MODULE:close(Fd), @@ -2152,7 +2165,7 @@ write_compressed(Config) when is_list(Config) -> ?line Second = io:get_line(Fd1, ''), ?line ok = ?FILE_MODULE:close(Fd1), - %% Verify succesful compression by uncompressing the file + %% Verify successful compression by uncompressing the file %% using zlib:gunzip/1. ?line {ok,Contents} = file:read_file(MyFile), diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl index 03e734445c..300152ddce 100644 --- a/lib/kernel/test/gen_sctp_SUITE.erl +++ b/lib/kernel/test/gen_sctp_SUITE.erl @@ -30,33 +30,29 @@ -export( [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]). + xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1, + basic_stream/1, xfer_stream_min/1, peeloff/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]. + api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6, + basic_stream, xfer_stream_min, peeloff, buffers]. groups() -> []. -init_per_suite(Config) -> - try gen_sctp:open() of +init_per_suite(_Config) -> + case gen_sctp:open() of {ok,Socket} -> gen_sctp:close(Socket), []; - _ -> - [] - catch - error:badarg -> - {skip,"SCTP not supported on this machine"}; - _:_ -> - Config + {error,eprotonosupport} -> + {skip,"SCTP not supported on this machine"} end. -end_per_suite(_Conifig) -> +end_per_suite(_Config) -> ok. init_per_group(_GroupName, Config) -> @@ -96,7 +92,7 @@ xfer_min(Config) when is_list(Config) -> ?line Stream = 0, ?line Data = <<"The quick brown fox jumps over a lazy dog 0123456789">>, ?line Loopback = {127,0,0,1}, - ?line {ok,Sb} = gen_sctp:open(), + ?line {ok,Sb} = gen_sctp:open([{type,seqpacket}]), ?line {ok,Pb} = inet:port(Sb), ?line ok = gen_sctp:listen(Sb, true), @@ -108,29 +104,44 @@ xfer_min(Config) when is_list(Config) -> inbound_streams=SaInboundStreams, assoc_id=SaAssocId}=SaAssocChange} = gen_sctp:connect(Sa, Loopback, Pb, []), - ?line {ok,{Loopback, - Pa,[], + ?line {SbAssocId,SaOutboundStreams,SaInboundStreams} = + case recv_event(log_ok(gen_sctp:recv(Sb, infinity))) of + {Loopback,Pa, #sctp_assoc_change{state=comm_up, error=0, outbound_streams=SbOutboundStreams, inbound_streams=SbInboundStreams, - assoc_id=SbAssocId}}} = - gen_sctp:recv(Sb, infinity), - ?line SaOutboundStreams = SbInboundStreams, - ?line SbOutboundStreams = SaInboundStreams, + assoc_id=AssocId}} -> + {AssocId,SbInboundStreams,SbOutboundStreams}; + {Loopback,Pa, + #sctp_paddr_change{state=addr_confirmed, + addr={Loopback,Pa}, + error=0, + assoc_id=AssocId}} -> + {Loopback,Pa, + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SbOutboundStreams, + inbound_streams=SbInboundStreams, + assoc_id=AssocId}} = + ?line recv_event(log_ok(gen_sctp:recv(Sb, infinity))), + {AssocId,SbInboundStreams,SbOutboundStreams} + end, + ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), - ?line case gen_sctp:recv(Sb, infinity) of - {ok,{Loopback, - Pa, - [#sctp_sndrcvinfo{stream=Stream, - assoc_id=SbAssocId}], - Data}} -> ok; - {ok,{Loopback, - Pa,[], + ?line case log_ok(gen_sctp:recv(Sb, infinity)) of + {Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data} -> ok; + Event1 -> + {Loopback,Pa, #sctp_paddr_change{addr = {Loopback,_}, state = addr_available, error = 0, - assoc_id = SbAssocId}}} -> + assoc_id = SbAssocId}} = + recv_event(Event1), {ok,{Loopback, Pa, [#sctp_sndrcvinfo{stream=Stream, @@ -138,30 +149,40 @@ xfer_min(Config) when is_list(Config) -> Data}} = gen_sctp:recv(Sb, infinity) end, ?line ok = gen_sctp:send(Sb, SbAssocId, 0, Data), - ?line {ok,{Loopback, - Pb, + ?line case log_ok(gen_sctp:recv(Sa, infinity)) of + {Loopback,Pb, [#sctp_sndrcvinfo{stream=Stream, assoc_id=SaAssocId}], - Data}} = - gen_sctp:recv(Sa, infinity), + Data} -> + ok; + Event2 -> + {Loopback,Pb, + #sctp_paddr_change{addr={_,Pb}, + state=addr_confirmed, + error=0, + assoc_id=SaAssocId}} = + ?line recv_event(Event2), + ?line {Loopback, + Pb, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SaAssocId}], + Data} = + log_ok(gen_sctp:recv(Sa, infinity)) + end, %% ?line ok = gen_sctp:eof(Sa, SaAssocChange), - ?line {ok,{Loopback, - Pa,[], - #sctp_shutdown_event{assoc_id=SbAssocId}}} = - gen_sctp:recv(Sb, infinity), - ?line {ok,{Loopback, - Pb,[], - #sctp_assoc_change{state=shutdown_comp, - error=0, - assoc_id=SaAssocId}}} = - gen_sctp:recv(Sa, infinity), - ?line {ok,{Loopback, - Pa,[], - #sctp_assoc_change{state=shutdown_comp, - error=0, - assoc_id=SbAssocId}}} = - gen_sctp:recv(Sb, infinity), + ?line {Loopback,Pa,#sctp_shutdown_event{assoc_id=SbAssocId}} = + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), + ?line {Loopback,Pb, + #sctp_assoc_change{state=shutdown_comp, + error=0, + assoc_id=SaAssocId}} = + recv_event(log_ok(gen_sctp:recv(Sa, infinity))), + ?line {Loopback,Pa, + #sctp_assoc_change{state=shutdown_comp, + error=0, + assoc_id=SbAssocId}} = + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), ?line ok = gen_sctp:close(Sa), ?line ok = gen_sctp:close(Sb), @@ -186,52 +207,62 @@ xfer_active(Config) when is_list(Config) -> ?line {ok,Sa} = gen_sctp:open([{active,true}]), ?line {ok,Pa} = inet:port(Sa), - ?line {ok,#sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=SaOutboundStreams, - inbound_streams=SaInboundStreams, - assoc_id=SaAssocId}=SaAssocChange} = - gen_sctp:connect(Sa, Loopback, Pb, []), + ?line ok = gen_sctp:connect_init(Sa, Loopback, Pb, []), + ?line #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SaOutboundStreams, + inbound_streams=SaInboundStreams, + assoc_id=SaAssocId} = SaAssocChange = + recv_assoc_change(Sa, Loopback, Pb, Timeout), ?line io:format("Sa=~p, Pa=~p, Sb=~p, Pb=~p, SaAssocId=~p, " "SaOutboundStreams=~p, SaInboundStreams=~p~n", [Sa,Pa,Sb,Pb,SaAssocId, SaOutboundStreams,SaInboundStreams]), - ?line SbAssocId = - receive - {sctp,Sb,Loopback,Pa, - {[], - #sctp_assoc_change{state=comm_up, - error=0, - outbound_streams=SbOutboundStreams, - inbound_streams=SbInboundStreams, - assoc_id=SBAI}}} -> - ?line SaOutboundStreams = SbInboundStreams, - ?line SaInboundStreams = SbOutboundStreams, - SBAI - after Timeout -> - ?line test_server:fail({unexpected,flush()}) - end, + ?line #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SbOutboundStreams, + inbound_streams=SbInboundStreams, + assoc_id=SbAssocId} = + recv_assoc_change(Sb, Loopback, Pa, Timeout), + ?line SbOutboundStreams = SaInboundStreams, + ?line SbInboundStreams = SaOutboundStreams, ?line io:format("SbAssocId=~p~n", [SbAssocId]), - ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), + + ?line case recv_paddr_change(Sa, Loopback, Pb, 314) of + #sctp_paddr_change{state=addr_confirmed, + addr={_,Pb}, + error=0, + assoc_id=SaAssocId} -> ok; + #sctp_paddr_change{state=addr_available, + addr={_,Pb}, + error=0, + assoc_id=SaAssocId} -> ok; + timeout -> ok + end, + ?line case recv_paddr_change(Sb, Loopback, Pa, 314) of + #sctp_paddr_change{state=addr_confirmed, + addr={Loopback,Pa}, + error=0, + assoc_id=SbAssocId} -> ok; + #sctp_paddr_change{state=addr_available, + addr={Loopback,P}, + error=0, + assoc_id=SbAssocId} -> + ?line match_unless_solaris(Pa, P); + timeout -> ok + end, + ?line [] = flush(), + + ?line ok = + do_from_other_process( + fun () -> gen_sctp:send(Sa, SaAssocId, 0, Data) end), ?line receive {sctp,Sb,Loopback,Pa, {[#sctp_sndrcvinfo{stream=Stream, assoc_id=SbAssocId}], - Data}} -> ok; - {sctp,Sb,Loopback,Pa, - {[], - #sctp_paddr_change{addr = {Loopback,_}, - state = addr_available, - error = 0, - assoc_id = SbAssocId}}} -> - ?line receive - {sctp,Sb,Loopback,Pa, - {[#sctp_sndrcvinfo{stream=Stream, - assoc_id=SbAssocId}], - Data}} -> ok - end + Data}} -> ok after Timeout -> - ?line test_server:fail({unexpected,flush()}) + ?line test_server:fail({timeout,flush()}) end, ?line ok = gen_sctp:send(Sb, SbAssocId, 0, Data), ?line receive @@ -240,31 +271,28 @@ xfer_active(Config) when is_list(Config) -> assoc_id=SaAssocId}], Data}} -> ok after Timeout -> - ?line test_server:fail({unexpected,flush()}) + ?line test_server:fail({timeout,flush()}) end, %% ?line ok = gen_sctp:abort(Sa, SaAssocChange), - ?line receive - {sctp,Sb,Loopback,Pa, - {[], - #sctp_assoc_change{state=comm_lost, - assoc_id=SbAssocId}}} -> ok - after Timeout -> - ?line test_server:fail({unexpected,flush()}) + ?line case recv_assoc_change(Sb, Loopback, Pa, Timeout) of + #sctp_assoc_change{state=comm_lost, + assoc_id=SbAssocId} -> ok; + timeout -> + ?line test_server:fail({timeout,flush()}) end, ?line ok = gen_sctp:close(Sb), + ?line case recv_assoc_change(Sa, Loopback, Pb, Timeout) of + #sctp_assoc_change{state=comm_lost, + assoc_id=SaAssocId} -> ok; + timeout -> + ?line io:format("timeout waiting for comm_lost on Sa~n"), + ?line match_unless_solaris(ok, {timeout,flush()}) + end, ?line receive - {sctp,Sa,Loopback,Pb, - {[], - #sctp_assoc_change{state=comm_lost, - assoc_id=SaAssocId}}} -> ok - after Timeout -> - ?line test_server:fail({unexpected,flush()}) - end, - ?line receive - {sctp_error,Sa,enotconn} -> ok % Solaris - after 17 -> ok %% Only happens on Solaris - end, + {sctp_error,Sa,enotconn} -> ok % Solaris + after 17 -> ok + end, ?line ok = gen_sctp:close(Sa), %% ?line receive @@ -273,6 +301,30 @@ xfer_active(Config) when is_list(Config) -> end, ok. +recv_assoc_change(S, Addr, Port, Timeout) -> + receive + {sctp,S,Addr,Port,{[], #sctp_assoc_change{}=AssocChange}} -> + AssocChange; + {sctp,S,Addr,Port, + {[#sctp_sndrcvinfo{assoc_id=AssocId}], + #sctp_assoc_change{assoc_id=AssocId}=AssocChange}} -> + AssocChange + after Timeout -> + timeout + end. + +recv_paddr_change(S, Addr, Port, Timeout) -> + receive + {sctp,S,Addr,Port,{[], #sctp_paddr_change{}=PaddrChange}} -> + PaddrChange; + {sctp,S,Addr,Port, + {[#sctp_sndrcvinfo{assoc_id=AssocId}], + #sctp_paddr_change{assoc_id=AssocId}=PaddrChange}} -> + PaddrChange + after Timeout -> + timeout + end. + def_sndrcvinfo(doc) -> "Test that #sctp_sndrcvinfo{} parameters set on a socket " "are used by gen_sctp:send/4"; @@ -283,11 +335,11 @@ def_sndrcvinfo(Config) when is_list(Config) -> ?line Data = <<"What goes up, must come down.">>, %% ?line S1 = - ok(gen_sctp:open( + log_ok(gen_sctp:open( 0, [{sctp_default_send_param,#sctp_sndrcvinfo{ppid=17}}])), ?LOGVAR(S1), ?line P1 = - ok(inet:port(S1)), + log_ok(inet:port(S1)), ?LOGVAR(P1), ?line #sctp_sndrcvinfo{ppid=17, context=0, timetolive=0, assoc_id=0} = getopt(S1, sctp_default_send_param), @@ -295,10 +347,10 @@ def_sndrcvinfo(Config) when is_list(Config) -> gen_sctp:listen(S1, true), %% ?line S2 = - ok(gen_sctp:open()), + log_ok(gen_sctp:open()), ?LOGVAR(S2), ?line P2 = - ok(inet:port(S2)), + log_ok(inet:port(S2)), ?LOGVAR(P2), ?line #sctp_sndrcvinfo{ppid=0, context=0, timetolive=0, assoc_id=0} = getopt(S2, sctp_default_send_param), @@ -307,32 +359,57 @@ def_sndrcvinfo(Config) when is_list(Config) -> state=comm_up, error=0, assoc_id=S2AssocId} = S2AssocChange = - ok(gen_sctp:connect(S2, Loopback, P1, [])), + log_ok(gen_sctp:connect(S2, Loopback, P1, [])), ?LOGVAR(S2AssocChange), - ?line case ok(gen_sctp:recv(S1)) of - {Loopback, P2,[], + ?line case recv_event(log_ok(gen_sctp:recv(S1))) of + {Loopback,P2, #sctp_assoc_change{ + state=comm_up, + error=0, + assoc_id=S1AssocId}} -> + ?LOGVAR(S1AssocId); + {Loopback,P2, + #sctp_paddr_change{ + state=addr_confirmed, + error=0, + assoc_id=S1AssocId}} -> + ?LOGVAR(S1AssocId), + {Loopback,P2, + #sctp_assoc_change{ state=comm_up, error=0, - assoc_id=S1AssocId}} -> - ?LOGVAR(S1AssocId) + assoc_id=S1AssocId}} = + recv_event(log_ok(gen_sctp:recv(S1))) end, + ?line #sctp_sndrcvinfo{ - ppid=17, context=0, timetolive=0, assoc_id=S1AssocId} = + ppid=17, context=0, timetolive=0} = %, assoc_id=S1AssocId} = getopt( S1, sctp_default_send_param, #sctp_sndrcvinfo{assoc_id=S1AssocId}), ?line #sctp_sndrcvinfo{ - ppid=0, context=0, timetolive=0, assoc_id=S2AssocId} = + ppid=0, context=0, timetolive=0} = %, assoc_id=S2AssocId} = getopt( S2, sctp_default_send_param, #sctp_sndrcvinfo{assoc_id=S2AssocId}), %% ?line ok = gen_sctp:send(S1, S1AssocId, 1, <<"1: ",Data/binary>>), - ?line case ok(gen_sctp:recv(S2)) of + ?line case log_ok(gen_sctp:recv(S2)) of {Loopback,P1, [#sctp_sndrcvinfo{ stream=1, ppid=17, context=0, assoc_id=S2AssocId}], - <<"1: ",Data/binary>>} -> ok + <<"1: ",Data/binary>>} -> ok; + Event1 -> + ?line {Loopback,P1, + #sctp_paddr_change{state=addr_confirmed, + addr={_,P1}, + error=0, + assoc_id=S2AssocId}} = + recv_event(Event1), + ?line {Loopback,P1, + [#sctp_sndrcvinfo{ + stream=1, ppid=17, context=0, assoc_id=S2AssocId}], + <<"1: ",Data/binary>>} = + log_ok(gen_sctp:recv(S2)) end, %% ?line ok = @@ -352,7 +429,7 @@ def_sndrcvinfo(Config) when is_list(Config) -> %% ?line ok = gen_sctp:send(S1, S1AssocId, 0, <<"2: ",Data/binary>>), - ?line case ok(gen_sctp:recv(S2)) of + ?line case log_ok(gen_sctp:recv(S2)) of {Loopback,P1, [#sctp_sndrcvinfo{ stream=0, ppid=19, context=0, assoc_id=S2AssocId}], @@ -360,16 +437,18 @@ def_sndrcvinfo(Config) when is_list(Config) -> end, ?line ok = gen_sctp:send(S2, S2AssocChange, 1, <<"3: ",Data/binary>>), - ?line case ok(gen_sctp:recv(S1)) of + ?line case log_ok(gen_sctp:recv(S1)) of {Loopback,P2, [#sctp_sndrcvinfo{ stream=1, ppid=0, context=0, assoc_id=S1AssocId}], <<"3: ",Data/binary>>} -> ok; - {Loopback,P2,[], - #sctp_paddr_change{ - addr={Loopback,_}, state=addr_available, - error=0, assoc_id=S1AssocId}} -> - ?line case ok(gen_sctp:recv(S1)) of + Event2 -> + {Loopback,P2, + #sctp_paddr_change{ + addr={Loopback,_}, state=addr_available, + error=0, assoc_id=S1AssocId}} = + recv_event(Event2), + ?line case log_ok(gen_sctp:recv(S1)) of {Loopback,P2, [#sctp_sndrcvinfo{ stream=1, ppid=0, context=0, @@ -378,11 +457,14 @@ def_sndrcvinfo(Config) when is_list(Config) -> end end, ?line ok = - gen_sctp:send( - S2, - #sctp_sndrcvinfo{stream=0, ppid=20, assoc_id=S2AssocId}, - <<"4: ",Data/binary>>), - ?line case ok(gen_sctp:recv(S1)) of + do_from_other_process( + fun () -> + gen_sctp:send( + S2, + #sctp_sndrcvinfo{stream=0, ppid=20, assoc_id=S2AssocId}, + <<"4: ",Data/binary>>) + end), + ?line case log_ok(do_from_other_process(fun() -> gen_sctp:recv(S1) end)) of {Loopback,P2, [#sctp_sndrcvinfo{ stream=0, ppid=20, context=0, assoc_id=S1AssocId}], @@ -411,8 +493,12 @@ getopt(S, Opt, Param) -> setopt(S, Opt, Val) -> inet:setopts(S, [{Opt,Val}]). -ok({ok,X}) -> - io:format("OK: ~p~n", [X]), +log_ok(X) -> log(ok(X)). + +ok({ok,X}) -> X. + +log(X) -> + io:format("LOG[~w]: ~p~n", [self(),X]), X. flush() -> @@ -515,7 +601,10 @@ api_listen(Config) when is_list(Config) -> #sctp_assoc_change{ state=comm_lost}}} = gen_sctp:recv(Sa, infinity); - {error,#sctp_assoc_change{state=cant_assoc}} -> ok + {error,#sctp_assoc_change{state=cant_assoc}} -> + ok%; + %% {error,{Localhost,Pb,_,#sctp_assoc_change{state=cant_assoc}}} -> + %% ok end, ?line ok = gen_sctp:listen(Sb, true), ?line {ok,#sctp_assoc_change{state=comm_up, @@ -547,34 +636,48 @@ api_connect_init(Config) when is_list(Config) -> ?line {ok,Sa} = gen_sctp:open(), ?line case gen_sctp:connect_init(Sa, localhost, Pb, []) of {error,econnrefused} -> - ?line {ok,{Localhost, - Pb,[], - #sctp_assoc_change{state=comm_lost}}} = - gen_sctp:recv(Sa, infinity); + ?line {Localhost,Pb,#sctp_assoc_change{state=comm_lost}} = + recv_event(log_ok(gen_sctp:recv(Sa, infinity))); ok -> - ?line {ok,{Localhost, - Pb,[], - #sctp_assoc_change{state=cant_assoc}}} = - gen_sctp:recv(Sa, infinity) + ?line {Localhost,Pb,#sctp_assoc_change{state=cant_assoc}} = + recv_event(log_ok(gen_sctp:recv(Sa, infinity))) end, ?line ok = gen_sctp:listen(Sb, true), ?line case gen_sctp:connect_init(Sa, localhost, Pb, []) of ok -> - ?line {ok,{Localhost, - Pb,[], - #sctp_assoc_change{ - state = comm_up}}} = - gen_sctp:recv(Sa, infinity) + ?line {Localhost,Pb,#sctp_assoc_change{state=comm_up}} = + recv_event(log_ok(gen_sctp:recv(Sa, infinity))) end, ?line ok = gen_sctp:close(Sa), ?line ok = gen_sctp:close(Sb), ok. +recv_event({Addr,Port,[],#sctp_assoc_change{}=AssocChange}) -> + {Addr,Port,AssocChange}; +recv_event({Addr,Port, + [#sctp_sndrcvinfo{assoc_id=Assoc}], + #sctp_assoc_change{assoc_id=Assoc}=AssocChange}) -> + {Addr,Port,AssocChange}; +recv_event({Addr,Port,[],#sctp_paddr_change{}=PaddrChange}) -> + {Addr,Port,PaddrChange}; +recv_event({Addr,Port, + [#sctp_sndrcvinfo{assoc_id=Assoc}], + #sctp_paddr_change{assoc_id=Assoc}=PaddrChange}) -> + {Addr,Port,PaddrChange}; +recv_event({Addr,Port,[],#sctp_shutdown_event{}=ShutdownEvent}) -> + {Addr,Port,ShutdownEvent}; +recv_event({Addr,Port, + [#sctp_sndrcvinfo{assoc_id=Assoc}], + #sctp_shutdown_event{assoc_id=Assoc}=ShutdownEvent}) -> + {Addr,Port,ShutdownEvent}. + api_opts(doc) -> "Test socket options"; api_opts(suite) -> []; api_opts(Config) when is_list(Config) -> + ?line Sndbuf = 32768, + ?line Recbuf = 65536, ?line {ok,S} = gen_sctp:open(0), ?line OSType = os:type(), ?line case {inet:setopts(S, [{linger,{true,2}}]),OSType} of @@ -582,10 +685,18 @@ api_opts(Config) when is_list(Config) -> ok; {{error,einval},{unix,sunos}} -> ok - end. + end, + ?line ok = inet:setopts(S, [{sndbuf,Sndbuf}]), + ?line ok = inet:setopts(S, [{recbuf,Recbuf}]), + ?line case inet:getopts(S, [sndbuf]) of + {ok,[{sndbuf,SB}]} when SB >= Sndbuf -> ok + end, + ?line case inet:getopts(S, [recbuf]) of + {ok,[{recbuf,RB}]} when RB >= Recbuf -> ok + end. implicit_inet6(Config) when is_list(Config) -> - ?line Hostname = ok(inet:gethostname()), + ?line Hostname = log_ok(inet:gethostname()), ?line case gen_sctp:open(0, [inet6]) of {ok,S1} -> @@ -598,16 +709,16 @@ implicit_inet6(Config) when is_list(Config) -> ?line ok = gen_sctp:close(S1), %% ?line Localhost = - ok(inet:getaddr("localhost", inet6)), + log_ok(inet:getaddr("localhost", inet6)), ?line io:format("~s ~p~n", ["localhost",Localhost]), ?line S2 = - ok(gen_sctp:open(0, [{ip,Localhost}])), + log_ok(gen_sctp:open(0, [{ip,Localhost}])), ?line implicit_inet6(S2, Localhost), ?line ok = gen_sctp:close(S2), %% ?line io:format("~s ~p~n", [Hostname,Host]), ?line S3 = - ok(gen_sctp:open(0, [{ifaddr,Host}])), + log_ok(gen_sctp:open(0, [{ifaddr,Host}])), ?line implicit_inet6(S3, Host), ?line ok = gen_sctp:close(S1); {error,eafnosupport} -> @@ -620,21 +731,599 @@ implicit_inet6(Config) when is_list(Config) -> implicit_inet6(S1, Addr) -> ?line ok = gen_sctp:listen(S1, true), - ?line P1 = ok(inet:port(S1)), - ?line S2 = ok(gen_sctp:open(0, [inet6])), - ?line P2 = ok(inet:port(S2)), + ?line P1 = log_ok(inet:port(S1)), + ?line S2 = log_ok(gen_sctp:open(0, [inet6])), + ?line P2 = log_ok(inet:port(S2)), ?line #sctp_assoc_change{state=comm_up} = - ok(gen_sctp:connect(S2, Addr, P1, [])), - ?line case ok(gen_sctp:recv(S1)) of - {Addr,P2,[],#sctp_assoc_change{state=comm_up}} -> - ok + log_ok(gen_sctp:connect(S2, Addr, P1, [])), + ?line case recv_event(log_ok(gen_sctp:recv(S1))) of + {Addr,P2,#sctp_assoc_change{state=comm_up}} -> + ok; + {Addr,P2,#sctp_paddr_change{state=addr_confirmed, + addr={Addr,P2}, + error=0}} -> + {Addr,P2,#sctp_assoc_change{state=comm_up}} = + recv_event(log_ok(gen_sctp:recv(S1))) end, - ?line case ok(inet:sockname(S1)) of + ?line case log_ok(inet:sockname(S1)) of {Addr,P1} -> ok; {{0,0,0,0,0,0,0,0},P1} -> ok end, - ?line case ok(inet:sockname(S2)) of + ?line case log_ok(inet:sockname(S2)) of {Addr,P2} -> ok; {{0,0,0,0,0,0,0,0},P2} -> ok end, ?line ok = gen_sctp:close(S2). + +basic_stream(doc) -> + "Hello world stream socket"; +basic_stream(suite) -> + []; +basic_stream(Config) when is_list(Config) -> + ?line {ok,S} = gen_sctp:open([{type,stream}]), + ?line ok = gen_sctp:listen(S, true), + ?line ok = + do_from_other_process( + fun () -> gen_sctp:listen(S, 10) end), + ?line ok = gen_sctp:close(S), + ok. + +xfer_stream_min(doc) -> + "Minimal data transfer"; +xfer_stream_min(suite) -> + []; +xfer_stream_min(Config) when is_list(Config) -> + ?line Stream = 0, + ?line Data = <<"The quick brown fox jumps over a lazy dog 0123456789">>, + ?line Loopback = {127,0,0,1}, + ?line {ok,Sb} = gen_sctp:open([{type,seqpacket}]), + ?line ?LOGVAR(Sb), + ?line {ok,Pb} = inet:port(Sb), + ?line ?LOGVAR(Pb), + ?line ok = gen_sctp:listen(Sb, true), + + ?line {ok,Sa} = gen_sctp:open([{type,stream}]), + ?line ?LOGVAR(Sa), + ?line {ok,Pa} = inet:port(Sa), + ?line ?LOGVAR(Pa), + ?line #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=SaOutboundStreams, + inbound_streams=SaInboundStreams, + assoc_id=SaAssocId_X} = + log_ok(gen_sctp:connect(Sa, Loopback, Pb, [])), + ?line ?LOGVAR(SaAssocId_X), + ?line [{_,#sctp_paddrinfo{assoc_id=SaAssocId,state=active}}] = + log_ok(inet:getopts(Sa, [{sctp_get_peer_addr_info, + #sctp_paddrinfo{address={Loopback,Pb}}}])), + ?line ?LOGVAR(SaAssocId), + ?line match_unless_solaris(SaAssocId_X, SaAssocId), + + ?line {SbOutboundStreams,SbInboundStreams,SbAssocId} = + case recv_event(log_ok(gen_sctp:recv(Sb, infinity))) of + {Loopback,Pa, + #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=OS, + inbound_streams=IS, + assoc_id=AI}} -> + {OS,IS,AI}; + {Loopback,Pa, + #sctp_paddr_change{state=addr_confirmed, + addr={Loopback,Pa}, + error=0, + assoc_id=AI}} -> + {Loopback,Pa, + ?line #sctp_assoc_change{state=comm_up, + error=0, + outbound_streams=OS, + inbound_streams=IS, + assoc_id=AI}} = + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), + {OS,IS,AI} + end, + ?line ?LOGVAR(SbAssocId), + ?line SaOutboundStreams = SbInboundStreams, + ?line ?LOGVAR(SaOutboundStreams), + ?line SbOutboundStreams = SaInboundStreams, + ?line ?LOGVAR(SbOutboundStreams), + ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data), + ?line case gen_sctp:recv(Sb, infinity) of + {ok,{Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data}} -> ok; + {ok,{Loopback, + Pa,[], + #sctp_paddr_change{addr = {Loopback,_}, + state = addr_available, + error = 0, + assoc_id = SbAssocId}}} -> + {ok,{Loopback, + Pa, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SbAssocId}], + Data}} = gen_sctp:recv(Sb, infinity) + end, + ?line ok = + do_from_other_process( + fun () -> gen_sctp:send(Sb, SbAssocId, 0, Data) end), + ?line case log_ok(gen_sctp:recv(Sa, infinity)) of + {Loopback,Pb, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SaAssocId}], + Data} -> ok; + Event1 -> + ?line {Loopback,Pb, + #sctp_paddr_change{state=addr_confirmed, + addr={_,Pb}, + error=0, + assoc_id=SaAssocId}} = + recv_event(Event1), + ?line {Loopback,Pb, + [#sctp_sndrcvinfo{stream=Stream, + assoc_id=SaAssocId}], + Data} = + log_ok(gen_sctp:recv(Sa, infinity)) + end, + ?line ok = gen_sctp:close(Sa), + ?line {Loopback,Pa, + #sctp_shutdown_event{assoc_id=SbAssocId}} = + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), + ?line {Loopback,Pa, + #sctp_assoc_change{state=shutdown_comp, + error=0, + assoc_id=SbAssocId}} = + recv_event(log_ok(gen_sctp:recv(Sb, infinity))), + ?line ok = gen_sctp:close(Sb), + + ?line receive + Msg -> test_server:fail({received,Msg}) + after 17 -> ok + end, + ok. + + + +do_from_other_process(Fun) -> + Parent = self(), + Ref = make_ref(), + Child = + spawn(fun () -> + try Fun() of + Result -> + Parent ! {Ref,Result} + catch + Class:Reason -> + Stacktrace = erlang:get_stacktrace(), + Parent ! {Ref,Class,Reason,Stacktrace} + end + end), + Mref = erlang:monitor(process, Child), + receive + {Ref,Result} -> + receive {'DOWN',Mref,_,_,_} -> Result end; + {Ref,Class,Reason,Stacktrace} -> + receive {'DOWN',Mref,_,_,_} -> + erlang:raise(Class, Reason, Stacktrace) + end; + {'DOWN',Mref,_,_,Reason} -> + erlang:exit(Reason) + end. + + + +peeloff(doc) -> + "Peel off an SCTP stream socket"; +peeloff(suite) -> + []; +peeloff(Config) when is_list(Config) -> + ?line Addr = {127,0,0,1}, + ?line Stream = 0, + ?line Timeout = 333, + ?line S1 = socket_open([{ifaddr,Addr}], 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 ?LOGVAR(S2), + ?line P2 = socket_call(S2, get_port), + ?line ?LOGVAR(P2), + ?line Socket2 = socket_call(S2, get_socket), + ?line ?LOGVAR(Socket2), + %% + ?line socket_call(S2, {connect_init,Addr,P1,[]}), + ?line S2Ai = + receive + {S2,{Addr,P1, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId2}}} -> AssocId2 + after Timeout -> + socket_bailout([S1,S2]) + end, + ?line ?LOGVAR(S2Ai), + ?line S1Ai = + receive + {S1,{Addr,P2, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId1}}} -> AssocId1 + after Timeout -> + socket_bailout([S1,S2]) + end, + ?line ?LOGVAR(S1Ai), + %% + ?line socket_call(S2, {send,S2Ai,Stream,<<"Number one">>}), + ?line + receive + {S1,{Addr,P2,S1Ai,Stream,<<"Number one">>}} -> ok + after Timeout -> + socket_bailout([S1,S2]) + end, + ?line socket_call(S2, {send,Socket1,S1Ai,Stream,<<"Number two">>}), + ?line + receive + {S2,{Addr,P1,S2Ai,Stream,<<"Number two">>}} -> ok + after Timeout -> + socket_bailout([S1,S2]) + end, + %% + ?line S3 = socket_peeloff(Socket1, S1Ai, Timeout), + ?line ?LOGVAR(S3), + ?line P3_X = socket_call(S3, get_port), + ?line ?LOGVAR(P3_X), + ?line P3 = case P3_X of 0 -> P1; _ -> P3_X end, + ?line [{_,#sctp_paddrinfo{assoc_id=S3Ai,state=active}}] = + socket_call(S3, + {getopts,[{sctp_get_peer_addr_info, + #sctp_paddrinfo{address={Addr,P2}}}]}), + %%?line S3Ai = S1Ai, + ?line ?LOGVAR(S3Ai), + %% + ?line socket_call(S3, {send,S3Ai,Stream,<<"Number three">>}), + ?line + receive + {S2,{Addr,P3,S2Ai,Stream,<<"Number three">>}} -> ok + after Timeout -> + socket_bailout([S1,S2,S3]) + end, + ?line socket_call(S3, {send,Socket2,S2Ai,Stream,<<"Number four">>}), + ?line + receive + {S3,{Addr,P2,S3Ai,Stream,<<"Number four">>}} -> ok + after Timeout -> + socket_bailout([S1,S2,S3]) + end, + %% + ?line inet:i(sctp), + ?line socket_close_verbose(S1), + ?line socket_close_verbose(S2), + ?line + receive + {S3,{Addr,P2,#sctp_shutdown_event{assoc_id=S3Ai_X}}} -> + ?line match_unless_solaris(S3Ai, S3Ai_X) + after Timeout -> + socket_bailout([S3]) + end, + ?line + receive + {S3,{Addr,P2,#sctp_assoc_change{state=shutdown_comp, + assoc_id=S3Ai}}} -> ok + after Timeout -> + socket_bailout([S3]) + end, + ?line socket_close_verbose(S3), + ?line [] = flush(), + ok. + + + +buffers(doc) -> + ["Check sndbuf and recbuf behaviour"]; +buffers(suite) -> + []; +buffers(Config) when is_list(Config) -> + ?line Limit = 4096, + ?line Addr = {127,0,0,1}, + ?line Stream = 1, + ?line Timeout = 3333, + ?line S1 = socket_open([{ip,Addr}], Timeout), + ?line ?LOGVAR(S1), + ?line P1 = socket_call(S1, get_port), + ?line ?LOGVAR(P1), + ?line ok = socket_call(S1, {listen,true}), + ?line S2 = socket_open([{ip,Addr}], Timeout), + ?line ?LOGVAR(S2), + ?line P2 = socket_call(S2, get_port), + ?line ?LOGVAR(P2), + %% + ?line socket_call(S2, {connect_init,Addr,P1,[]}), + ?line S2Ai = + receive + {S2,{Addr,P1, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId2}}} -> AssocId2 + after Timeout -> + socket_bailout([S1,S2]) + end, + ?line S1Ai = + receive + {S1,{Addr,P2, + #sctp_assoc_change{ + state=comm_up, + assoc_id=AssocId1}}} -> AssocId1 + after Timeout -> + socket_bailout([S1,S2]) + end, + %% + ?line socket_call(S1, {setopts,[{recbuf,Limit}]}), + ?line Recbuf = + case socket_call(S1, {getopts,[recbuf]}) of + [{recbuf,RB1}] when RB1 >= Limit -> RB1 + end, + ?line Data = mk_data(Recbuf+Limit), + ?line socket_call(S2, {setopts,[{sndbuf,Recbuf+Limit}]}), + ?line socket_call(S2, {send,S2Ai,Stream,Data}), + ?line + receive + {S1,{Addr,P2,S1Ai,Stream,Data}} -> ok + after Timeout -> + socket_bailout([S1,S2]) + end, + %% + ?line socket_close_verbose(S1), + ?line + receive + {S2,{Addr,P1,#sctp_shutdown_event{assoc_id=S2Ai}}} -> ok + after Timeout -> + socket_bailout([S2]) + end, + ?line + receive + {S2,{Addr,P1,#sctp_assoc_change{state=shutdown_comp, + assoc_id=S2Ai}}} -> ok + after Timeout -> + socket_bailout([S2]) + end, + ?line socket_close_verbose(S2), + ?line [] = flush(), + ok. + +mk_data(Bytes) -> + mk_data(0, Bytes, <<>>). +%% +mk_data(N, Bytes, Bin) when N < Bytes -> + mk_data(N+4, Bytes, <<Bin/binary,N:32>>); +mk_data(_, _, Bin) -> + Bin. + +%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%% socket gen_server ultra light + +socket_open(SocketOpts, Timeout) -> + Opts = [{type,seqpacket},{active,once},binary|SocketOpts], + Starter = + fun () -> + {ok,Socket} = + gen_sctp:open(Opts), + Socket + end, + s_start(Starter, Timeout). + +socket_peeloff(Socket, AssocId, Timeout) -> + Opts = [{active,once},binary], + Starter = + fun () -> + {ok,NewSocket} = + gen_sctp:peeloff(Socket, AssocId), + ok = inet:setopts(NewSocket, Opts), + NewSocket + end, + s_start(Starter, Timeout). + +socket_close_verbose(S) -> + History = socket_history(socket_close(S)), + io:format("socket_close ~p:~n ~p.~n", [S,History]), + History. + +socket_close(S) -> + s_req(S, close). + +socket_call(S, Request) -> + s_req(S, {Request}). + +%% socket_get(S, Key) -> +%% s_req(S, {get,Key}). + +socket_bailout([S|Ss]) -> + History = socket_history(socket_close(S)), + io:format("bailout ~p:~n ~p.~n", [S,History]), + socket_bailout(Ss); +socket_bailout([]) -> + io:format("flush: ~p.~n", [flush()]), + test_server:fail(socket_bailout). + +socket_history({State,Flush}) -> + {lists:keysort( + 2, + lists:flatten( + [[{Key,Val} || Val <- Vals] + || {Key,Vals} <- gb_trees:to_list(State)])), + Flush}. + +s_handler(Socket) -> + fun ({listen,Listen}) -> + ok = gen_sctp:listen(Socket, Listen); + (get_port) -> + ok(inet:port(Socket)); + (get_socket) -> + Socket; + ({connect_init,ConAddr,ConPort,ConOpts}) -> + ok = gen_sctp:connect_init(Socket, ConAddr, ConPort, ConOpts); + ({send,AssocId,Stream,Data}) -> + ok = gen_sctp:send(Socket, AssocId, Stream, Data); + ({send,OtherSocket,AssocId,Stream,Data}) -> + ok = gen_sctp:send(OtherSocket, AssocId, Stream, Data); + ({setopts,Opts}) -> + ok = inet:setopts(Socket, Opts); + ({getopts,Optnames}) -> + ok(inet:getopts(Socket, Optnames)) + end. + +s_req(S, Req) -> + Mref = erlang:monitor(process, S), + S ! {self(),Mref,Req}, + receive + {'DOWN',Mref,_,_,Error} -> + exit(Error); + {S,Mref,Reply} -> + erlang:demonitor(Mref), + receive {'DOWN',Mref,_,_,_} -> ok after 0 -> ok end, + Reply + end. + +s_start(Starter, Timeout) -> + Parent = self(), + Owner = + spawn_link( + fun () -> + s_start(Starter(), Timeout, Parent) + end), + Owner. + +s_start(Socket, Timeout, Parent) -> + Handler = s_handler(Socket), + try + s_loop(Socket, Timeout, Parent, Handler, gb_trees:empty()) + catch + Class:Reason -> + Stacktrace = erlang:get_stacktrace(), + io:format(?MODULE_STRING":socket exception ~w:~w at~n" + "~p.~n", [Class,Reason,Stacktrace]), + erlang:raise(Class, Reason, Stacktrace) + end. + +s_loop(Socket, Timeout, Parent, Handler, State) -> + receive + {Parent,Ref,close} -> % socket_close() + erlang:send_after(Timeout, self(), {Parent,Ref,exit}), + s_loop(Socket, Timeout, Parent, Handler, State); + {Parent,Ref,exit} -> + ok = gen_sctp:close(Socket), + Key = exit, + Val = {now(),Socket}, + NewState = gb_push(Key, Val, State), + Parent ! {self(),Ref,{NewState,flush()}}; + {Parent,Ref,{Msg}} -> + Result = Handler(Msg), + Key = req, + Val = {now(),{Msg,Result}}, + NewState = gb_push(Key, Val, State), + Parent ! {self(),Ref,Result}, + s_loop(Socket, Timeout, Parent, Handler, NewState); + %% {Parent,Ref,{get,Key}} -> + %% Parent ! {self(),Ref,gb_get(Key, State)}, + %% s_loop(Socket, Timeout, Parent, Handler, State); + {sctp,Socket,Addr,Port, + {[#sctp_sndrcvinfo{stream=Stream,assoc_id=AssocId}=SRI],Data}} + when not is_tuple(Data) -> + case gb_get({assoc_change,AssocId}, State) of + [{_,{Addr,Port, + #sctp_assoc_change{ + state=comm_up, + inbound_streams=Is}}}|_] + when 0 =< Stream, Stream < Is-> ok; + [] -> ok + end, + Key = {msg,AssocId,Stream}, + Val = {now(),{Addr,Port,SRI,Data}}, + NewState = gb_push(Key, Val, State), + Parent ! {self(),{Addr,Port,AssocId,Stream,Data}}, + again(Socket), + s_loop(Socket, Timeout, Parent, Handler, NewState); + {sctp,Socket,Addr,Port, + {SRI,#sctp_assoc_change{assoc_id=AssocId,state=St}=SAC}} -> + case SRI of + [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok; + [] -> ok + end, + Key = {assoc_change,AssocId}, + Val = {now(),{Addr,Port,SAC}}, + case {gb_get(Key, State),St} of + {[],_} -> ok; + {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_} + when St =:= comm_lost; St =:= shutdown_comp -> ok + end, + NewState = gb_push(Key, Val, State), + Parent ! {self(),{Addr,Port,SAC}}, + again(Socket), + s_loop(Socket, Timeout, Parent, Handler, NewState); + {sctp,Socket,Addr,Port, + {SRI,#sctp_paddr_change{assoc_id=AssocId, + addr={_,P}, + state=St}=SPC}} -> + match_unless_solaris(Port, P), + case SRI of + [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok; + [] -> ok + end, + case {gb_get({assoc_change,AssocId}, State),St} of + {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_], + addr_available} -> ok; + {[],addr_confirmed} -> ok + end, + Key = {paddr_change,AssocId}, + Val = {now(),{Addr,Port,SPC}}, + NewState = gb_push(Key, Val, State), + again(Socket), + s_loop(Socket, Timeout, Parent, Handler, NewState); + {sctp,Socket,Addr,Port, + {SRI,#sctp_shutdown_event{assoc_id=AssocId}=SSE}} -> + case SRI of + [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok; + [] -> ok + end, + case gb_get({assoc_change,AssocId}, State) of + [{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_] -> ok; + [] -> ok + end, + Key = {shutdown_event,AssocId}, + Val = {now(),{Addr,Port}}, + NewState = gb_push(Key, Val, State), + Parent ! {self(), {Addr,Port,SSE}}, + again(Socket), + s_loop(Socket, Timeout, Parent, Handler, NewState); + Unexpected -> + erlang:error({unexpected,Unexpected}) + end. + +again(Socket) -> + inet:setopts(Socket, [{active,once}]). + +gb_push(Key, Val, GBT) -> + case gb_trees:lookup(Key, GBT) of + none -> + gb_trees:insert(Key, [Val], GBT); + {value,V} -> + gb_trees:update(Key, [Val|V], GBT) + end. + +gb_get(Key, GBT) -> + case gb_trees:lookup(Key, GBT) of + none -> + []; + {value,V} -> + V + end. + +match_unless_solaris(A, B) -> + case os:type() of + {unix,sunos} -> B; + _ -> A = B + end. diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index fd4685cdad..cbaec2d6dd 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -158,6 +158,10 @@ t_shutdown_error(Config) when is_list(Config) -> t_fdopen(Config) when is_list(Config) -> ?line Question = "Aaaa... Long time ago in a small town in Germany,", + ?line Question1 = list_to_binary(Question), + ?line Question2 = [<<"Aaaa">>, "... ", $L, <<>>, $o, "ng time ago ", + ["in ", [], <<"a small town">>, [" in Germany,", <<>>]]], + ?line Question1 = iolist_to_binary(Question2), ?line Answer = "there was a shoemaker, Schumacher was his name.", ?line {ok, L} = gen_tcp:listen(0, [{active, false}]), ?line {ok, Port} = inet:port(L), @@ -167,6 +171,10 @@ t_fdopen(Config) when is_list(Config) -> ?line {ok, Server} = gen_tcp:fdopen(FD, []), ?line ok = gen_tcp:send(Client, Question), ?line {ok, Question} = gen_tcp:recv(Server, length(Question), 2000), + ?line ok = gen_tcp:send(Client, Question1), + ?line {ok, Question} = gen_tcp:recv(Server, length(Question), 2000), + ?line ok = gen_tcp:send(Client, Question2), + ?line {ok, Question} = gen_tcp:recv(Server, length(Question), 2000), ?line ok = gen_tcp:send(Server, Answer), ?line {ok, Answer} = gen_tcp:recv(Client, length(Answer), 2000), ?line ok = gen_tcp:close(Client), diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl index d8a5519195..514deaf065 100644 --- a/lib/kernel/test/gen_udp_SUITE.erl +++ b/lib/kernel/test/gen_udp_SUITE.erl @@ -201,13 +201,21 @@ binary_passive_recv(suite) -> binary_passive_recv(doc) -> ["OTP-3823 gen_udp:recv does not return address in binary mode"]; binary_passive_recv(Config) when is_list(Config) -> - ?line D = "The quick brown fox jumps over a lazy dog", - ?line B = list_to_binary(D), + ?line D1 = "The quick brown fox jumps over a lazy dog", + ?line D2 = list_to_binary(D1), + ?line D3 = ["The quick", <<" brown ">>, "fox jumps ", <<"over ">>, + <<>>, $a, [[], " lazy ", <<"dog">>]], + ?line D2 = iolist_to_binary(D3), + ?line B = D2, ?line {ok, R} = gen_udp:open(0, [binary, {active, false}]), ?line {ok, RP} = inet:port(R), ?line {ok, S} = gen_udp:open(0), ?line {ok, SP} = inet:port(S), - ?line ok = gen_udp:send(S, localhost, RP, D), + ?line ok = gen_udp:send(S, localhost, RP, D1), + ?line {ok, {{127, 0, 0, 1}, SP, B}} = gen_udp:recv(R, byte_size(B)+1), + ?line ok = gen_udp:send(S, localhost, RP, D2), + ?line {ok, {{127, 0, 0, 1}, SP, B}} = gen_udp:recv(R, byte_size(B)+1), + ?line ok = gen_udp:send(S, localhost, RP, D3), ?line {ok, {{127, 0, 0, 1}, SP, B}} = gen_udp:recv(R, byte_size(B)+1), ?line ok = gen_udp:close(S), ?line ok = gen_udp:close(R), @@ -400,6 +408,7 @@ open_fd(Config) when is_list(Config) -> {ok,S1} = gen_udp:open(0), {ok,P2} = inet:port(S1), {ok,FD} = prim_inet:getfd(S1), + {error,einval} = gen_udp:open(P2, [inet6, {fd,FD}]), {ok,S2} = gen_udp:open(P2, [{fd,FD}]), {ok,S3} = gen_udp:open(0), {ok,P3} = inet:port(S3), diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl index 1e7bcf1766..60035b50a0 100644 --- a/lib/kernel/test/global_SUITE.erl +++ b/lib/kernel/test/global_SUITE.erl @@ -436,7 +436,7 @@ lock_global2(Id, Parent) -> %cp1 - cp3 are started, and the name 'test' registered for a process on %test_server. Then it is checked that the name is registered on all -%nodes, using whereis_name and safe_whereis_name. Check that the same +%nodes, using whereis_name. Check that the same %name can't be registered with another value. Exit the registered %process and check that the name disappears. Register a new process %(Pid2) under the name 'test'. Let another new process (Pid3) @@ -465,10 +465,6 @@ names(Config) when is_list(Config) -> % test that it is registered at all nodes ?line ?UNTIL(begin - (Pid =:= global:safe_whereis_name(test)) and - (Pid =:= rpc:call(Cp1, global, safe_whereis_name, [test])) and - (Pid =:= rpc:call(Cp2, global, safe_whereis_name, [test])) and - (Pid =:= rpc:call(Cp3, global, safe_whereis_name, [test])) and (Pid =:= global:whereis_name(test)) and (Pid =:= rpc:call(Cp1, global, whereis_name, [test])) and (Pid =:= rpc:call(Cp2, global, whereis_name, [test])) and @@ -566,10 +562,7 @@ names_hidden(Config) when is_list(Config) -> % Check that it didn't get registered on visible nodes ?line - ?UNTIL((undefined =:= global:safe_whereis_name(test)) and - (undefined =:= rpc:call(Cp1, global, safe_whereis_name, [test])) and - (undefined =:= rpc:call(Cp2, global, safe_whereis_name, [test])) and - (undefined =:= global:whereis_name(test)) and + ?UNTIL((undefined =:= global:whereis_name(test)) and (undefined =:= rpc:call(Cp1, global, whereis_name, [test])) and (undefined =:= rpc:call(Cp2, global, whereis_name, [test]))), @@ -579,11 +572,7 @@ names_hidden(Config) when is_list(Config) -> % test that it is registered at all nodes ?line - ?UNTIL((Pid =:= global:safe_whereis_name(test)) and - (Pid =:= rpc:call(Cp1, global, safe_whereis_name, [test])) and - (Pid =:= rpc:call(Cp2, global, safe_whereis_name, [test])) and - (HPid =:= rpc:call(Cp3, global, safe_whereis_name, [test])) and - (Pid =:= global:whereis_name(test)) and + ?UNTIL((Pid =:= global:whereis_name(test)) and (Pid =:= rpc:call(Cp1, global, whereis_name, [test])) and (Pid =:= rpc:call(Cp2, global, whereis_name, [test])) and (HPid =:= rpc:call(Cp3, global, whereis_name, [test])) and diff --git a/lib/kernel/test/global_group_SUITE.erl b/lib/kernel/test/global_group_SUITE.erl index 13b2fd07b5..799b0d9d05 100644 --- a/lib/kernel/test/global_group_SUITE.erl +++ b/lib/kernel/test/global_group_SUITE.erl @@ -100,7 +100,7 @@ start_gg_proc(Config) when is_list(Config) -> ?line Dir = ?config(priv_dir, Config), ?line File = filename:join(Dir, "global_group.config"), - ?line {ok, Fd}=file:open(File, write), + ?line {ok, Fd}=file:open(File, [write]), [Ncp1,Ncp2,Ncp3] = node_names([cp1, cp2, cp3], Config), ?line config(Fd, Ncp1, Ncp2, Ncp3, "cpx", "cpy", "cpz", "cpq"), @@ -135,7 +135,7 @@ no_gg_proc(Config) when is_list(Config) -> ?line Dir = ?config(priv_dir, Config), ?line File = filename:join(Dir, "no_global_group.config"), - ?line {ok, Fd} = file:open(File, write), + ?line {ok, Fd} = file:open(File, [write]), ?line config_no(Fd), ?line NN = node_name(atom_to_list(node())), @@ -308,7 +308,7 @@ no_gg_proc_sync(Config) when is_list(Config) -> ?line Dir = ?config(priv_dir, Config), ?line File = filename:join(Dir, "no_global_group_sync.config"), - ?line {ok, Fd} = file:open(File, write), + ?line {ok, Fd} = file:open(File, [write]), [Ncp1,Ncp2,Ncp3,Ncpx,Ncpy,Ncpz] = node_names([cp1,cp2,cp3,cpx,cpy,cpz], Config), @@ -482,7 +482,7 @@ compatible(Config) when is_list(Config) -> ?line Dir = ?config(priv_dir, Config), ?line File = filename:join(Dir, "global_group_comp.config"), - ?line {ok, Fd} = file:open(File, write), + ?line {ok, Fd} = file:open(File, [write]), [Ncp1,Ncp2,Ncp3,Ncpx,Ncpy,Ncpz] = node_names([cp1,cp2,cp3,cpx,cpy,cpz], Config), @@ -655,7 +655,7 @@ one_grp(Config) when is_list(Config) -> ?line Dir = ?config(priv_dir, Config), ?line File = filename:join(Dir, "global_group.config"), - ?line {ok, Fd} = file:open(File, write), + ?line {ok, Fd} = file:open(File, [write]), [Ncp1,Ncp2,Ncp3] = node_names([cp1, cp2, cp3], Config), ?line config(Fd, Ncp1, Ncp2, Ncp3, "cpx", "cpy", "cpz", "cpq"), @@ -742,7 +742,7 @@ one_grp_x(Config) when is_list(Config) -> ?line Dir = ?config(priv_dir, Config), ?line File = filename:join(Dir, "global_group.config"), - ?line {ok, Fd} = file:open(File, write), + ?line {ok, Fd} = file:open(File, [write]), [Ncp1,Ncp2,Ncp3] = node_names([cp1, cp2, cp3], Config), ?line config(Fd, Ncp1, Ncp2, Ncp3, "cpx", "cpy", "cpz", "cpq"), @@ -804,7 +804,7 @@ two_grp(Config) when is_list(Config) -> ?line Dir = ?config(priv_dir, Config), ?line File = filename:join(Dir, "global_group.config"), - ?line {ok, Fd} = file:open(File, write), + ?line {ok, Fd} = file:open(File, [write]), [Ncp1,Ncp2,Ncp3,Ncpx,Ncpy,Ncpz,Ncpq] = node_names([cp1,cp2,cp3,cpx,cpy,cpz,cpq], Config), @@ -1104,7 +1104,7 @@ hidden_groups(Config) when is_list(Config) -> ?line Dir = ?config(priv_dir, Config), ?line File = filename:join(Dir, "global_group.config"), - ?line {ok, Fd} = file:open(File, write), + ?line {ok, Fd} = file:open(File, [write]), [Ncp1,Ncp2,Ncp3,Ncpx,Ncpy,Ncpz,Ncpq] = node_names([cp1,cp2,cp3,cpx,cpy,cpz,cpq], Config), diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl index 1bb173a3ac..aaa20b7398 100644 --- a/lib/kernel/test/inet_SUITE.erl +++ b/lib/kernel/test/inet_SUITE.erl @@ -294,7 +294,7 @@ t_getaddr_v6(Config) when is_list(Config) -> ?line {Name,FullName,IPStr,_IP,_,IP_46_Str,IP46} = ct:get_config(test_host_ipv4_only), case {inet:getaddr(IP_46_Str, inet6),inet:getaddr(Name, inet6)} of - {{ok,IP46},{ok,_}} -> + {{ok,IP46},{ok,V4Addr}} when V4Addr /= {0,0,0,0,0,0,0,1} -> %% Since we suceeded in parsing an IPv6 address string and %% look up the name, this computer fully supports IPv6. ?line {ok,IP46} = inet:getaddr(IP46, inet6), diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl index 5fc8df475d..15b0ed5718 100644 --- a/lib/kernel/test/inet_res_SUITE.erl +++ b/lib/kernel/test/inet_res_SUITE.erl @@ -27,7 +27,8 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, init_per_testcase/2, end_per_testcase/2]). --export([basic/1, resolve/1, edns0/1, txt_record/1, files_monitor/1]). +-export([basic/1, resolve/1, edns0/1, txt_record/1, files_monitor/1, + last_ms_answer/1]). -export([ gethostbyaddr/0, gethostbyaddr/1, gethostbyaddr_v6/0, gethostbyaddr_v6/1, @@ -45,6 +46,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [basic, resolve, edns0, txt_record, files_monitor, + last_ms_answer, gethostbyaddr, gethostbyaddr_v6, gethostbyname, gethostbyname_v6, getaddr, getaddr_v6, ipv4_to_ipv6, host_and_addr]. @@ -64,16 +66,15 @@ init_per_group(_GroupName, Config) -> end_per_group(_GroupName, Config) -> Config. -zone_dir(basic) -> - otptest; -zone_dir(resolve) -> - otptest; -zone_dir(edns0) -> - otptest; -zone_dir(files_monitor) -> - otptest; -zone_dir(_) -> - undefined. +zone_dir(TC) -> + case TC of + basic -> otptest; + resolve -> otptest; + edns0 -> otptest; + files_monitor -> otptest; + last_ms_answer -> otptest; + _ -> undefined + end. init_per_testcase(Func, Config) -> PrivDir = ?config(priv_dir, Config), @@ -116,9 +117,15 @@ ns_init(ZoneDir, PrivDir, DataDir) -> case os:type() of {unix,_} when ZoneDir =:= undefined -> undefined; {unix,_} -> - {ok,S} = gen_udp:open(0, [{reuseaddr,true}]), - {ok,PortNum} = inet:port(S), - gen_udp:close(S), + PortNum = case {os:type(),os:version()} of + {{unix,solaris},{M,V,_}} when M =< 5, V < 10 -> + 11895 + random:uniform(100); + _ -> + {ok,S} = gen_udp:open(0, [{reuseaddr,true}]), + {ok,PNum} = inet:port(S), + gen_udp:close(S), + PNum + end, RunNamed = filename:join(DataDir, ?RUN_NAMED), NS = {{127,0,0,1},PortNum}, P = erlang:open_port({spawn_executable,RunNamed}, @@ -129,21 +136,22 @@ ns_init(ZoneDir, PrivDir, DataDir) -> atom_to_list(ZoneDir)]}, stderr_to_stdout, eof]), - ns_start(ZoneDir, NS, P); + ns_start(ZoneDir, PrivDir, NS, P); _ -> throw("Only run on Unix") end. -ns_start(ZoneDir, NS, P) -> +ns_start(ZoneDir, PrivDir, NS, P) -> case ns_collect(P) of eof -> erlang:error(eof); "Running: "++_ -> {ZoneDir,NS,P}; "Error: "++Error -> + ns_printlog(filename:join([PrivDir,ZoneDir,"named.log"])), throw(Error); _ -> - ns_start(ZoneDir, NS, P) + ns_start(ZoneDir, PrivDir, NS, P) end. ns_end(undefined, _PrivDir) -> undefined; @@ -184,6 +192,88 @@ ns_printlog(Fname) -> ok end. +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Behaviour modifying nameserver proxy + +proxy_start(TC, {NS,P}) -> + Tag = make_ref(), + Parent = self(), + Pid = + spawn_link( + fun () -> + try proxy_start(TC, NS, P, Parent, Tag) + catch C:X -> + io:format( + "~w: ~w:~p ~p~n", + [self(),C,X,erlang:get_stacktrace()]) + end + end), + receive {started,Tag,Port} -> + ProxyNS = {{127,0,0,1},Port}, + {proxy,Pid,Tag,ProxyNS} + end. + +proxy_start(TC, NS, P, Parent, Tag) -> + {ok,Outbound} = gen_udp:open(0, [binary]), + ok = gen_udp:connect(Outbound, NS, P), + {ok,Inbound} = gen_udp:open(0, [binary]), + {ok,Port} = inet:port(Inbound), + Parent ! {started,Tag,Port}, + proxy(TC, Outbound, NS, P, Inbound). + + +%% To provoke the last_ms_answer bug (OTP-9221) the proxy +%% * Relays the query to the right nameserver +%% * Intercepts the reply but holds it until the timer that +%% was started when receiving the query fires. +%% * Repeats the reply with incorrect query ID a number of +%% times with a short interval. +%% * Sends the correct reply, to give a correct test result +%% after bug correction. +%% +%% The repetition of an incorrect answer with tight interval will keep +%% inet_res in an inner loop in the code that decrements the remaining +%% time until it hits 0 which triggers a crash, if the outer timeout +%% parameter to inet_res:resolve is so short that it runs out during +%% these repetitions. +proxy(last_ms_answer, Outbound, NS, P, Inbound) -> + receive + {udp,Inbound,SrcIP,SrcPort,Data} -> + Time = + inet_db:res_option(timeout) div inet_db:res_option(retry), + Tag = erlang:make_ref(), + erlang:send_after(Time - 10, self(), {time,Tag}), + ok = gen_udp:send(Outbound, NS, P, Data), + receive + {udp,Outbound,NS,P,Reply} -> + {ok,Msg} = inet_dns:decode(Reply), + Hdr = inet_dns:msg(Msg, header), + Id = inet_dns:header(Hdr, id), + BadHdr = + inet_dns:make_header(Hdr, id, (Id+1) band 16#ffff), + BadMsg = inet_dns:make_msg(Msg, header, BadHdr), + BadReply = inet_dns:encode(BadMsg), + receive + {time,Tag} -> + proxy__last_ms_answer( + Inbound, SrcIP, SrcPort, BadReply, Reply, 30) + end + end + end. + +proxy__last_ms_answer(Socket, IP, Port, _, Reply, 0) -> + ok = gen_udp:send(Socket, IP, Port, Reply); +proxy__last_ms_answer(Socket, IP, Port, BadReply, Reply, N) -> + ok = gen_udp:send(Socket, IP, Port, BadReply), + receive after 1 -> ok end, + proxy__last_ms_answer(Socket, IP, Port, BadReply, Reply, N-1). + +proxy_wait({proxy,Pid,_,_}) -> + Mref = erlang:monitor(process, Pid), + receive {'DOWN',Mref,_,_,_} -> ok end. + +proxy_ns({proxy,_,_,ProxyNS}) -> ProxyNS. + %% %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -204,7 +294,7 @@ basic(Config) when is_list(Config) -> {ok,Msg1} = inet_dns:decode(Bin1), %% %% resolve - {ok,Msg2} = inet_res:resolve(Name, in, a, [{nameservers,[NS]}]), + {ok,Msg2} = inet_res:resolve(Name, in, a, [{nameservers,[NS]},verbose]), io:format("~p~n", [Msg2]), [RR2] = inet_dns:msg(Msg2, anlist), IP = inet_dns:rr(RR2, data), @@ -474,6 +564,26 @@ do_files_monitor(Config) -> ok. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +last_ms_answer(doc) -> + ["Answer just when timeout is triggered (OTP-9221)"]; +last_ms_answer(Config) when is_list(Config) -> + NS = ns(Config), + Name = "ns.otptest", + %%IP = {127,0,0,254}, + Time = inet_db:res_option(timeout) div inet_db:res_option(retry), + PSpec = proxy_start(last_ms_answer, NS), + ProxyNS = proxy_ns(PSpec), + %% + %% resolve; whith short timeout to trigger Timeout =:= 0 in inet_res + {error,timeout} = + inet_res:resolve( + Name, in, a, [{nameservers,[ProxyNS]},verbose], Time + 10), + %% + proxy_wait(PSpec), + ok. + +%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Compatibility tests. Call the inet_SUITE tests, but with %% lookup = [file,dns] instead of [native] diff --git a/lib/kernel/test/inet_res_SUITE_data/run-named b/lib/kernel/test/inet_res_SUITE_data/run-named index b418607d48..39e7b1d5aa 100755 --- a/lib/kernel/test/inet_res_SUITE_data/run-named +++ b/lib/kernel/test/inet_res_SUITE_data/run-named @@ -2,7 +2,7 @@ ## ## %CopyrightBegin% ## -## Copyright Ericsson AB 2009. All Rights Reserved. +## Copyright Ericsson AB 2009-2011. All Rights Reserved. ## ## The contents of this file are subject to the Erlang Public License, ## Version 1.1, (the "License"); you may not use this file except in @@ -47,6 +47,7 @@ CONF_FILE=named.conf INC_FILE=named_inc.conf PID_FILE=named.pid LOG_FILE=named.log +EXIT_FILE=named.exit error () { r=$? @@ -71,10 +72,14 @@ test -d "$SRCDIR" || \ test -f "$SRCDIR/$INC_FILE" || \ error "Missing file: $SRCDIR/$INC_FILE !" -# Locate named and check version +# Locate named and check version. +# The bind-named name is used for tricking Apparmor and such +# by copying/hardlinking the real named to that name. NAMED=named -for n in /usr/sbin/named /usr/sbin/in.named; do - test -x "$n" && NAMED="$n" +for n in /usr/local/bin/bind-named /usr/local/bin/named \ + /usr/sbin/bind-named /usr/sbin/named /usr/sbin/in.named +do + test -x "$n" && NAMED="$n" && break done NAMED_VER="`"$NAMED" -v 2>&1`" || \ error "Name server not found!" @@ -145,19 +150,27 @@ cat >>"$CONF_FILE" <<-CONF_FILE ( cd "$SRCDIR" && ls -1 ) | while read f; do cp -fp "$SRCDIR/$f" . done +rm -f "$EXIT_FILE" # Start nameserver echo "Cwd: `pwd`" echo "Nameserver: $NAMED_VER" echo "Port: $2" echo "ZoneDir: $3" -$NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null & -NAMED=$! -trap "kill -TERM $NAMED >/dev/null 2>&1; wait $NAMED >/dev/null 2>&1" \ +echo "Command: $NAMED $NAMED_FG -c $CONF_FILE" +($NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null; \ + echo "$?" >"$EXIT_FILE")& +NAMED_PID=$! +trap "kill -TERM $NAMED_PID >/dev/null 2>&1; wait $NAMED_PID >/dev/null 2>&1" \ 0 1 2 3 15 -sleep 1 # Give name server time to load its zone files -echo "Running: Enter \`\`quit'' to terminate nameserver[$NAMED]..." -while read LINE; do - test :"$LINE" = :'quit' && break -done +sleep 2 # Give name server time to load its zone files +if [ -f "$EXIT_FILE" ]; then + ERROR="`cat "$EXIT_FILE"`" + (exit "$ERROR")& error "$NAMED returned $ERROR on start" +else + echo "Running: Enter \`\`quit'' to terminate nameserver[$NAMED_PID]..." + while read LINE; do + test :"$LINE" = :'quit' && break + done +fi echo "Closing: Terminating nameserver..." diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl index 2db0f7dcb8..b39fadd65f 100644 --- a/lib/kernel/test/init_SUITE.erl +++ b/lib/kernel/test/init_SUITE.erl @@ -656,7 +656,7 @@ create_script(Config) -> ?line Apps = application_controller:which_applications(), ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps), ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps), - ?line {ok,Fd} = file:open(Name ++ ".rel", write), + ?line {ok,Fd} = file:open(Name ++ ".rel", [write]), ?line io:format(Fd, "{release, {\"Test release 3\", \"P2A\"}, \n" " {erts, \"4.4\"}, \n" diff --git a/lib/kernel/test/pg2_SUITE.erl b/lib/kernel/test/pg2_SUITE.erl index 0ac34e735c..520b53b4e4 100644 --- a/lib/kernel/test/pg2_SUITE.erl +++ b/lib/kernel/test/pg2_SUITE.erl @@ -47,6 +47,7 @@ init_per_testcase(Case, Config) -> [{?TESTCASE, Case}, {watchdog, Dog} | Config]. end_per_testcase(_Case, _Config) -> + test_server_ctrl:kill_slavenodes(), Dog = ?config(watchdog, _Config), test_server:timetrap_cancel(Dog), ok. diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index a04ea3cdcd..00eda6292f 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -250,39 +250,49 @@ make_del_dir(Config, Handle, Suffix) -> ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), - %% Check that we get an error when trying to create... - %% a deep directory - ?line NewDir2 = filename:join(RootDir, - atom_to_list(?MODULE) - ++"_mk-dir/foo"), - ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2]), - %% a nameless directory - ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [""]), - %% a directory with illegal name - ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir']), - - %% a directory with illegal name, even if it's a (bad) list - ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}]]), - - %% Maybe this isn't an error, exactly, but worth mentioning anyway: - %% ok = ?PRIM_FILE:make_dir([$f,$o,$o,0,$b,$a,$r])), - %% The above line works, and created a directory "./foo" - %% More elegant would maybe have been to fail, or to really create - %% a directory, but with a name that incorporates the "bar" part of - %% the list, so that [$f,$o,$o,0,$f,$o,$o] wouldn't refer to the same - %% dir. But this would slow it down. - - %% Try deleting some bad directories - %% Deleting the parent directory to the current, sounds dangerous, huh? - %% Don't worry ;-) the parent directory should never be empty, right? - case ?PRIM_FILE_call(del_dir, Handle, [".."]) of - {error, eexist} -> ok; - {error, einval} -> ok %FreeBSD + % Make sure we are not in a directory directly under test_server + % as that would result in eacess errors when trying to delere '..', + % because there are processes having that directory as current. + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), + ?line {ok, CurrentDir} = ?PRIM_FILE_call(get_cwd, Handle, []), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), + try + %% Check that we get an error when trying to create... + %% a deep directory + ?line NewDir2 = filename:join(RootDir, + atom_to_list(?MODULE) + ++"_mk-dir-noexist/foo"), + ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2]), + %% a nameless directory + ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [""]), + %% a directory with illegal name + ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir']), + + %% a directory with illegal name, even if it's a (bad) list + ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}]]), + + %% Maybe this isn't an error, exactly, but worth mentioning anyway: + %% ok = ?PRIM_FILE:make_dir([$f,$o,$o,0,$b,$a,$r])), + %% The above line works, and created a directory "./foo" + %% More elegant would maybe have been to fail, or to really create + %% a directory, but with a name that incorporates the "bar" part of + %% the list, so that [$f,$o,$o,0,$f,$o,$o] wouldn't refer to the same + %% dir. But this would slow it down. + + %% Try deleting some bad directories + %% Deleting the parent directory to the current, sounds dangerous, huh? + %% Don't worry ;-) the parent directory should never be empty, right? + ?line case ?PRIM_FILE_call(del_dir, Handle, [".."]) of + {error, eexist} -> ok; + {error, einval} -> ok %FreeBSD + end, + ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]), + ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]), + + ?line test_server:timetrap_cancel(Dog) + after + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir]) end, - ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]), - ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]), - - ?line test_server:timetrap_cancel(Dog), ok. cur_dir_0a(suite) -> []; diff --git a/lib/kernel/test/ram_file_SUITE.erl b/lib/kernel/test/ram_file_SUITE.erl index 9b3fbb91fc..ab95a3ff5f 100644 --- a/lib/kernel/test/ram_file_SUITE.erl +++ b/lib/kernel/test/ram_file_SUITE.erl @@ -552,7 +552,7 @@ large_file_light(Config) when is_list(Config) -> ?line PrivDir = ?config(priv_dir, Config), %% Marker for next test case that is to heavy to run in a suite. ?line ok = ?FILE_MODULE:write_file( - filename:join(PrivDir, large_file_light), + filename:join(PrivDir, "large_file_light"), <<"TAG">>), %% ?line Data = "abcdefghijklmnopqrstuvwzyz", @@ -582,7 +582,7 @@ large_file_heavy(Config) when is_list(Config) -> ?line PrivDir = ?config(priv_dir, Config), %% Check previous test case marker. case ?FILE_MODULE:read_file_info( - filename:join(PrivDir, large_file_light)) of + filename:join(PrivDir, "large_file_light")) of {ok,_} -> {skipped,"Too heavy for casual testing!"}; _ -> diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl index 9eb84c9167..74bafe8935 100644 --- a/lib/kernel/test/zlib_SUITE.erl +++ b/lib/kernel/test/zlib_SUITE.erl @@ -42,8 +42,8 @@ end end()). --define(BARG, {'EXIT',{badarg,[{zlib,_,_}|_]}}). --define(DATA_ERROR, {'EXIT',{data_error,[{zlib,_,_}|_]}}). +-define(BARG, {'EXIT',{badarg,[{zlib,_,_,_}|_]}}). +-define(DATA_ERROR, {'EXIT',{data_error,[{zlib,_,_,_}|_]}}). init_per_testcase(_Func, Config) -> Dog = test_server:timetrap(test_server:seconds(60)), @@ -412,6 +412,7 @@ api_crc32(Config) when is_list(Config) -> Compressed = list_to_binary(Compressed1 ++ Compressed2), CRC1 = ?m( CRC1 when is_integer(CRC1), zlib:crc32(Z1)), ?m(CRC1 when is_integer(CRC1), zlib:crc32(Z1,Bin)), + ?m(CRC1 when is_integer(CRC1), zlib:crc32(Z1,binary_to_list(Bin))), ?m(CRC2 when is_integer(CRC2), zlib:crc32(Z1,Compressed)), CRC2 = ?m(CRC2 when is_integer(CRC2), zlib:crc32(Z1,0,Compressed)), ?m(CRC3 when CRC2 /= CRC3, zlib:crc32(Z1,234,Compressed)), @@ -437,6 +438,7 @@ api_adler32(Config) when is_list(Config) -> Compressed2 = ?m(_, zlib:deflate(Z1, <<>>, finish)), Compressed = list_to_binary(Compressed1 ++ Compressed2), ?m(ADLER1 when is_integer(ADLER1), zlib:adler32(Z1,Bin)), + ?m(ADLER1 when is_integer(ADLER1), zlib:adler32(Z1,binary_to_list(Bin))), ADLER2 = ?m(ADLER2 when is_integer(ADLER2), zlib:adler32(Z1,Compressed)), ?m(ADLER2 when is_integer(ADLER2), zlib:adler32(Z1,1,Compressed)), ?m(ADLER3 when ADLER2 /= ADLER3, zlib:adler32(Z1,234,Compressed)), @@ -464,6 +466,7 @@ api_un_compress(Config) when is_list(Config) -> ?m({'EXIT',{data_error,_}}, zlib:uncompress(<<120,156,3>>)), ?m({'EXIT',{data_error,_}}, zlib:uncompress(<<120,156,3,0>>)), ?m({'EXIT',{data_error,_}}, zlib:uncompress(<<0,156,3,0,0,0,0,1>>)), + ?m(Bin, zlib:uncompress(binary_to_list(Comp))), ?m(Bin, zlib:uncompress(Comp)). api_un_zip(doc) -> "Test zip"; @@ -472,10 +475,12 @@ api_un_zip(Config) when is_list(Config) -> ?m(?BARG,zlib:zip(not_a_binary)), Bin = <<1,11,1,23,45>>, ?line Comp = zlib:zip(Bin), + ?m(Comp, zlib:zip(binary_to_list(Bin))), ?m(?BARG,zlib:unzip(not_a_binary)), ?m({'EXIT',{data_error,_}}, zlib:unzip(<<171,171,171,171,171>>)), ?m({'EXIT',{data_error,_}}, zlib:unzip(<<>>)), ?m(Bin, zlib:unzip(Comp)), + ?m(Bin, zlib:unzip(binary_to_list(Comp))), %% OTP-6396 B = <<131,104,19,100,0,13,99,95,99,105,100,95,99,115,103,115,110,95,50,97,1,107,0,4,208,161,246,29,107,0,3,237,166,224,107,0,6,66,240,153,0,2,10,1,0,8,97,116,116,97,99,104,101,100,104,2,100,0,22,117,112,100,97,116,101,95,112,100,112,95,99,111,110,116,101,120,116,95,114,101,113,107,0,114,69,3,12,1,11,97,31,113,150,64,104,132,61,64,104,12,3,197,31,113,150,64,104,132,61,64,104,12,1,11,97,31,115,150,64,104,116,73,64,104,0,0,0,0,0,0,65,149,16,61,65,149,16,61,1,241,33,4,5,0,33,4,4,10,6,10,181,4,10,6,10,181,38,15,99,111,109,109,97,110,100,1,114,45,97,112,110,45,49,3,99,111,109,5,109,110,99,57,57,6,109,99,99,50,52,48,4,103,112,114,115,8,0,104,2,104,2,100,0,8,97,99,116,105,118,97,116,101,104,23,100,0,11,112,100,112,95,99,111,110,116,1,120,116,100,0,7,112,114,105,109,97,114,121,97,1,100,0,9,117,110,100,101,102,105,110,101,100,97,1,97,4,97,4,97,7,100,0,9,117,110,100,101,102,105,110,101,100,100,0,9,117,110,100,101,102,105,110,10100,100,0,9,117,110,100,101,102,105,110,101,100,100,0,5,102,97,108,115,101,100,0,9,117,110,100,101,102,105,110,101,100,100,0,9,117,110,100,101,102,105,110,101,100,100,0,9,117,110,100,101,102,105,1,101,100,97,0,100,0,9,117,110,100,101,102,105,110,101,100,107,0,4,16,0,1,144,107,0,4,61,139,186,181,107,0,4,10,8,201,49,100,0,9,117,110,100,101,102,105,110,101,100,100,0,9,117,110,100,101,102,105,0,101,100,100,0,9,117,110,100,101,102,105,110,101,100,104,2,104,3,98,0,0,7,214,97,11,97,20,104,3,97,17,97,16,97,21,106,108,0,0,0,3,104,2,97,1,104,2,104,3,98,0,0,7,214,97,11,97,20,104,3,97,17,97,167,20,104,2,97,4,104,2,104,3,98,0,0,7,214,97,11,97,20,104,3,97,17,97,16,97,21,104,2,97,10,104,2,104,3,98,0,0,7,214,97,11,97,20,104,3,97,17,97,16,97,26,106,100,0,5,118,101,114,57,57,100,0,9,117,110,0,101,102,105,110,101,100,107,0,2,0,244,107,0,4,10,6,102,195,107,0,4,10,6,102,195,100,0,9,117,110,100,101,102,105,110,101,100,100,0,9,117,110,100,101,102,105,110,101,100,107,0,125,248,143,0,203,25115,157,116,65,185,65,172,55,87,164,88,225,50,203,251,115,157,116,65,185,65,172,55,87,164,88,225,50,0,0,82,153,50,0,200,98,87,148,237,193,185,65,149,167,69,144,14,16,153,50,3,81,70,94,13,109,193,1,120,5,181,113,198,118,50,3,81,70,94,13,109,193,185,120,5,181,113,198,118,153,3,81,70,94,13,109,193,185,120,5,181,113,198,118,153,50,16,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,113,92,2,119,128,0,0,108,0,0,1,107,0,114,69,3,12,1,11,97,31,113,150,64,104,132,61,64,104,12,3,11,97,31,113,150,64,104,132,61,64,104,12,1,11,97,31,115,150,64,104,116,73,64,104,0,0,0,0,0,0,65,149,16,61,65,149,16,61,1,241,33,4,0,33,4,4,10,6,10,181,4,10,6,10,181,38,15,99,111,109,109,97,110,100,101,114,45,97,112,110,45,49,3,99,111,109,5,109,110,99,57,57,6,109,99,99,50,52,48,4,103,112,114,115,8,0,106>>, @@ -504,10 +509,12 @@ api_g_un_zip(Config) when is_list(Config) -> ?m(?BARG,zlib:gzip(not_a_binary)), Bin = <<1,11,1,23,45>>, ?line Comp = zlib:gzip(Bin), + ?m(Comp, zlib:gzip(binary_to_list(Bin))), ?m(?BARG, zlib:gunzip(not_a_binary)), ?m(?DATA_ERROR, zlib:gunzip(<<171,171,171,171,171>>)), ?m(?DATA_ERROR, zlib:gunzip(<<>>)), ?m(Bin, zlib:gunzip(Comp)), + ?m(Bin, zlib:gunzip(binary_to_list(Comp))), %% Bad CRC; bad length. BadCrc = bad_crc_data(), @@ -844,6 +851,7 @@ dictionary_usage({run}) -> ?m(ok, zlib:inflateInit(Z2)), ?line {'EXIT',{{need_dictionary,DictID},_}} = (catch zlib:inflate(Z2, Compressed)), ?m(ok, zlib:inflateSetDictionary(Z2, Dict)), + ?m(ok, zlib:inflateSetDictionary(Z2, binary_to_list(Dict))), ?line Uncompressed = ?m(B when is_list(B), zlib:inflate(Z2, [])), ?m(ok, zlib:inflateEnd(Z2)), ?m(ok, zlib:close(Z2)), diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index e7b71cc168..76c62ece67 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 2.14.4 +KERNEL_VSN = 2.15 |