diff options
Diffstat (limited to 'lib/kernel')
46 files changed, 1831 insertions, 2018 deletions
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml index 38c7b5acf1..4e32c1a3a5 100644 --- a/lib/kernel/doc/src/application.xml +++ b/lib/kernel/doc/src/application.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>application</module> + <module since="">application</module> <modulesummary>Generic OTP application functions</modulesummary> <description> <p>In OTP, <em>application</em> denotes a component implementing @@ -67,8 +67,8 @@ </datatypes> <funcs> <func> - <name name="ensure_all_started" arity="1"/> - <name name="ensure_all_started" arity="2"/> + <name name="ensure_all_started" arity="1" since="OTP R16B02"/> + <name name="ensure_all_started" arity="2" since="OTP R16B02"/> <fsummary>Load and start an application and its dependencies, recursively.</fsummary> <desc> <p>Equivalent to calling @@ -85,8 +85,8 @@ </desc> </func> <func> - <name name="ensure_started" arity="1"/> - <name name="ensure_started" arity="2"/> + <name name="ensure_started" arity="1" since="OTP R16B01"/> + <name name="ensure_started" arity="2" since="OTP R16B01"/> <fsummary>Load and start an application.</fsummary> <desc> <p>Equivalent to @@ -95,8 +95,8 @@ </desc> </func> <func> - <name name="get_all_env" arity="0"/> - <name name="get_all_env" arity="1"/> + <name name="get_all_env" arity="0" since=""/> + <name name="get_all_env" arity="1" since=""/> <fsummary>Get the configuration parameters for an application.</fsummary> <desc> <p>Returns the configuration parameters and their values for @@ -108,8 +108,8 @@ </desc> </func> <func> - <name name="get_all_key" arity="0"/> - <name name="get_all_key" arity="1"/> + <name name="get_all_key" arity="0" since=""/> + <name name="get_all_key" arity="1" since=""/> <fsummary>Get the application specification keys.</fsummary> <desc> <p>Returns the application specification keys and their values @@ -122,8 +122,8 @@ </desc> </func> <func> - <name name="get_application" arity="0"/> - <name name="get_application" arity="1"/> + <name name="get_application" arity="0" since=""/> + <name name="get_application" arity="1" since=""/> <fsummary>Get the name of an application containing a certain process or module.</fsummary> <desc> <p>Returns the name of the application to which the process @@ -136,8 +136,8 @@ </desc> </func> <func> - <name name="get_env" arity="1"/> - <name name="get_env" arity="2"/> + <name name="get_env" arity="1" since=""/> + <name name="get_env" arity="2" since=""/> <fsummary>Get the value of a configuration parameter.</fsummary> <desc> <p>Returns the value of configuration parameter <c><anno>Par</anno></c> @@ -153,7 +153,7 @@ </desc> </func> <func> - <name name="get_env" arity="3"/> + <name name="get_env" arity="3" since="OTP R16B"/> <fsummary>Get the value of a configuration parameter using a default.</fsummary> <desc> <p>Works like <seealso marker="#get_env/2"><c>get_env/2</c></seealso> but returns @@ -162,8 +162,8 @@ </desc> </func> <func> - <name name="get_key" arity="1"/> - <name name="get_key" arity="2"/> + <name name="get_key" arity="1" since=""/> + <name name="get_key" arity="2" since=""/> <fsummary>Get the value of an application specification key.</fsummary> <desc> <p>Returns the value of the application specification key @@ -180,8 +180,8 @@ </desc> </func> <func> - <name name="load" arity="1"/> - <name name="load" arity="2"/> + <name name="load" arity="1" since=""/> + <name name="load" arity="2" since=""/> <fsummary>Load an application.</fsummary> <type name="application_spec"/> <type name="application_opt"/> @@ -226,7 +226,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="loaded_applications" arity="0"/> + <name name="loaded_applications" arity="0" since=""/> <fsummary>Get the currently loaded applications.</fsummary> <desc> <p>Returns a list with information about the applications, and included @@ -238,7 +238,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="permit" arity="2"/> + <name name="permit" arity="2" since=""/> <fsummary>Change the permission for an application to run at a node.</fsummary> <desc> <p>Changes the permission for <c><anno>Application</anno></c> to run at @@ -271,8 +271,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="set_env" arity="3"/> - <name name="set_env" arity="4"/> + <name name="set_env" arity="3" since=""/> + <name name="set_env" arity="4" since=""/> <fsummary>Set the value of a configuration parameter.</fsummary> <desc> <p>Sets the value of configuration parameter <c><anno>Par</anno></c> for @@ -302,8 +302,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="start" arity="1"/> - <name name="start" arity="2"/> + <name name="start" arity="1" since=""/> + <name name="start" arity="2" since=""/> <fsummary>Load and start an application.</fsummary> <desc> <p>Starts <c><anno>Application</anno></c>. If it is not loaded, @@ -353,7 +353,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="start_type" arity="0"/> + <name name="start_type" arity="0" since=""/> <fsummary>Get the start type of an ongoing application startup.</fsummary> <desc> <p>This function is intended to be called by a process belonging @@ -370,7 +370,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="stop" arity="1"/> + <name name="stop" arity="1" since=""/> <fsummary>Stop an application.</fsummary> <desc> <p>Stops <c><anno>Application</anno></c>. The application master calls @@ -399,7 +399,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="takeover" arity="2"/> + <name name="takeover" arity="2" since=""/> <fsummary>Take over a distributed application.</fsummary> <desc> <p>Takes over the distributed application @@ -424,7 +424,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="unload" arity="1"/> + <name name="unload" arity="1" since=""/> <fsummary>Unload an application.</fsummary> <desc> <p>Unloads the application specification for <c><anno>Application</anno></c> @@ -435,8 +435,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="unset_env" arity="2"/> - <name name="unset_env" arity="3"/> + <name name="unset_env" arity="2" since=""/> + <name name="unset_env" arity="3" since=""/> <fsummary>Unset the value of a configuration parameter.</fsummary> <desc> <p>Removes the configuration parameter <c><anno>Par</anno></c> and its value @@ -459,8 +459,8 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name name="which_applications" arity="0"/> - <name name="which_applications" arity="1"/> + <name name="which_applications" arity="0" since=""/> + <name name="which_applications" arity="1" since=""/> <fsummary>Get the currently running applications.</fsummary> <desc> <p>Returns a list with information about the applications that @@ -484,7 +484,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </section> <funcs> <func> - <name>Module:start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}</name> + <name since="">Module:start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}</name> <fsummary>Start an application.</fsummary> <type> <v>StartType = <seealso marker="#type-start_type"><c>start_type()</c></seealso></v> @@ -526,7 +526,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>Module:start_phase(Phase, StartType, PhaseArgs) -> ok | {error, Reason}</name> + <name since="">Module:start_phase(Phase, StartType, PhaseArgs) -> ok | {error, Reason}</name> <fsummary>Extended start of an application.</fsummary> <type> <v>Phase = atom()</v> @@ -551,7 +551,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>Module:prep_stop(State) -> NewState</name> + <name since="">Module:prep_stop(State) -> NewState</name> <fsummary>Prepare an application for termination.</fsummary> <type> <v>State = NewState = term()</v> @@ -569,7 +569,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>Module:stop(State)</name> + <name since="">Module:stop(State)</name> <fsummary>Clean up after termination of an application.</fsummary> <type> <v>State = term()</v> @@ -585,7 +585,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code> </desc> </func> <func> - <name>Module:config_change(Changed, New, Removed) -> ok</name> + <name since="">Module:config_change(Changed, New, Removed) -> ok</name> <fsummary>Update the configuration parameters for an application.</fsummary> <type> <v>Changed = [{Par,Val}]</v> diff --git a/lib/kernel/doc/src/auth.xml b/lib/kernel/doc/src/auth.xml index 5901446960..a57da18de9 100644 --- a/lib/kernel/doc/src/auth.xml +++ b/lib/kernel/doc/src/auth.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>auth</module> + <module since="">auth</module> <modulesummary>Erlang network authentication server.</modulesummary> <description> <p>This module is deprecated. For a description of the Magic @@ -42,7 +42,7 @@ </datatypes> <funcs> <func> - <name name="cookie" arity="0"/> + <name name="cookie" arity="0" since=""/> <fsummary>Magic cookie for local node (deprecated).</fsummary> <desc> <p>Use @@ -51,7 +51,7 @@ </desc> </func> <func> - <name name="cookie" arity="1"/> + <name name="cookie" arity="1" since=""/> <fsummary>Set the magic for the local node (deprecated).</fsummary> <type_desc variable="TheCookie"> The cookie can also be specified as a list with a single atom element. @@ -63,7 +63,7 @@ </desc> </func> <func> - <name name="is_auth" arity="1"/> + <name name="is_auth" arity="1" since=""/> <fsummary>Status of communication authorization (deprecated).</fsummary> <desc> <p>Returns <c>yes</c> if communication with <c><anno>Node</anno></c> is @@ -76,7 +76,7 @@ </desc> </func> <func> - <name>node_cookie([Node, Cookie]) -> yes | no</name> + <name since="">node_cookie([Node, Cookie]) -> yes | no</name> <fsummary>Set the magic cookie for a node and verify authorization (deprecated).</fsummary> <type> <v>Node = node()</v> @@ -88,7 +88,7 @@ </desc> </func> <func> - <name name="node_cookie" arity="2"/> + <name name="node_cookie" arity="2" since=""/> <fsummary>Set the magic cookie for a node and verify authorization (deprecated).</fsummary> <desc> <p>Sets the magic cookie of <c><anno>Node</anno></c> to diff --git a/lib/kernel/doc/src/code.xml b/lib/kernel/doc/src/code.xml index 69ce4da61c..4aa9e8b9d2 100644 --- a/lib/kernel/doc/src/code.xml +++ b/lib/kernel/doc/src/code.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>code</module> + <module since="">code</module> <modulesummary>Erlang code server.</modulesummary> <description> <p>This module contains the interface to the Erlang @@ -322,7 +322,7 @@ zip:create("mnesia-4.4.7.ez", <funcs> <func> - <name name="set_path" arity="1"/> + <name name="set_path" arity="1" since=""/> <fsummary>Set the code server search path.</fsummary> <desc> <p>Sets the code path to the list of directories <c><anno>Path</anno></c>.</p> @@ -336,15 +336,15 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="get_path" arity="0"/> + <name name="get_path" arity="0" since=""/> <fsummary>Return the code server search path.</fsummary> <desc> <p>Returns the code path.</p> </desc> </func> <func> - <name name="add_path" arity="1"/> - <name name="add_pathz" arity="1"/> + <name name="add_path" arity="1" since=""/> + <name name="add_pathz" arity="1" since=""/> <fsummary>Add a directory to the end of the code path.</fsummary> <type name="add_path_ret"/> <desc> @@ -357,7 +357,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="add_patha" arity="1"/> + <name name="add_patha" arity="1" since=""/> <fsummary>Add a directory to the beginning of the code path.</fsummary> <type name="add_path_ret"/> <desc> @@ -370,8 +370,8 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="add_paths" arity="1"/> - <name name="add_pathsz" arity="1"/> + <name name="add_paths" arity="1" since=""/> + <name name="add_pathsz" arity="1" since=""/> <fsummary>Add directories to the end of the code path.</fsummary> <desc> <p>Adds the directories in <c><anno>Dirs</anno></c> to the end of the code @@ -381,7 +381,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="add_pathsa" arity="1"/> + <name name="add_pathsa" arity="1" since=""/> <fsummary>Add directories to the beginning of the code path.</fsummary> <desc> <p>Traverses <c><anno>Dirs</anno></c> and adds @@ -397,7 +397,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="del_path" arity="1"/> + <name name="del_path" arity="1" since=""/> <fsummary>Delete a directory from the code path.</fsummary> <desc> <p>Deletes a directory from the code path. The argument can be @@ -417,7 +417,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="replace_path" arity="2"/> + <name name="replace_path" arity="2" since=""/> <fsummary>Replace a directory with another in the code path.</fsummary> <desc> <p>Replaces an old occurrence of a directory @@ -441,7 +441,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="load_file" arity="1"/> + <name name="load_file" arity="1" since=""/> <fsummary>Load a module.</fsummary> <type name="load_ret"/> <desc> @@ -460,7 +460,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="load_abs" arity="1"/> + <name name="load_abs" arity="1" since=""/> <fsummary>Load a module, residing in a specified file.</fsummary> <type name="load_ret"/> <type name="loaded_filename"/> @@ -477,7 +477,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="ensure_loaded" arity="1"/> + <name name="ensure_loaded" arity="1" since=""/> <fsummary>Ensure that a module is loaded.</fsummary> <desc> <p>Tries to load a module in the same way as @@ -489,7 +489,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="load_binary" arity="3"/> + <name name="load_binary" arity="3" since=""/> <fsummary>Load object code for a module.</fsummary> <type name="loaded_filename"/> <type name="loaded_ret_atoms"/> @@ -507,7 +507,7 @@ zip:create("mnesia-4.4.7.ez", </desc> </func> <func> - <name name="atomic_load" arity="1"/> + <name name="atomic_load" arity="1" since="OTP 19.0"/> <fsummary>Load a list of modules atomically</fsummary> <desc> <p>Tries to load all of the modules in the list @@ -566,7 +566,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="prepare_loading" arity="1"/> + <name name="prepare_loading" arity="1" since="OTP 19.0"/> <fsummary>Prepare a list of modules atomically</fsummary> <desc> <p>Prepares to load the modules in the list @@ -598,7 +598,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="finish_loading" arity="1"/> + <name name="finish_loading" arity="1" since="OTP 19.0"/> <fsummary>Finish loading a list of prepared modules atomically</fsummary> <desc> <p>Tries to load code for all modules that have been previously @@ -627,7 +627,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="ensure_modules_loaded" arity="1"/> + <name name="ensure_modules_loaded" arity="1" since="OTP 19.0"/> <fsummary>Ensure that a list of modules is loaded</fsummary> <desc> <p>Tries to load any modules not already loaded in the list @@ -639,7 +639,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="delete" arity="1"/> + <name name="delete" arity="1" since=""/> <fsummary>Remove current code for a module.</fsummary> <desc> <p>Removes the current code for <c><anno>Module</anno></c>, that is, @@ -652,7 +652,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="purge" arity="1"/> + <name name="purge" arity="1" since=""/> <fsummary>Remove old code for a module.</fsummary> <desc> <p>Purges the code for <c><anno>Module</anno></c>, that is, removes code @@ -668,7 +668,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="soft_purge" arity="1"/> + <name name="soft_purge" arity="1" since=""/> <fsummary>Remove old code for a module, unless no process uses it.</fsummary> <desc> <p>Purges the code for <c><anno>Module</anno></c>, that is, removes code @@ -683,7 +683,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="is_loaded" arity="1"/> + <name name="is_loaded" arity="1" since=""/> <fsummary>Check if a module is loaded.</fsummary> <type name="loaded_filename"/> <type name="loaded_ret_atoms"/> @@ -702,7 +702,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="all_loaded" arity="0"/> + <name name="all_loaded" arity="0" since=""/> <fsummary>Get all loaded modules.</fsummary> <type name="loaded_filename"/> <type name="loaded_ret_atoms"/> @@ -716,7 +716,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="which" arity="1"/> + <name name="which" arity="1" since=""/> <fsummary>The object code file of a module.</fsummary> <type name="loaded_ret_atoms"/> <desc> @@ -731,7 +731,7 @@ ok = code:finish_loading(Prepared), </desc> </func> <func> - <name name="get_object_code" arity="1"/> + <name name="get_object_code" arity="1" since=""/> <fsummary>Gets the object code for a module.</fsummary> <desc> <p>Searches the code path for the object code of module @@ -750,7 +750,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="root_dir" arity="0"/> + <name name="root_dir" arity="0" since=""/> <fsummary>Root directory of Erlang/OTP.</fsummary> <desc> <p>Returns the root directory of Erlang/OTP, which is @@ -762,7 +762,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="lib_dir" arity="0"/> + <name name="lib_dir" arity="0" since=""/> <fsummary>Library directory of Erlang/OTP.</fsummary> <desc> <p>Returns the library directory, <c>$OTPROOT/lib</c>, where @@ -774,7 +774,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="lib_dir" arity="1"/> + <name name="lib_dir" arity="1" since=""/> <fsummary>Library directory for an application.</fsummary> <desc> <p>Returns the path @@ -807,7 +807,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="lib_dir" arity="2"/> + <name name="lib_dir" arity="2" since=""/> <fsummary>Subdirectory for an application.</fsummary> <desc> <p>Returns the path to a subdirectory directly under the top @@ -827,7 +827,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="compiler_dir" arity="0"/> + <name name="compiler_dir" arity="0" since=""/> <fsummary>Library directory for the compiler.</fsummary> <desc> <p>Returns the compiler library directory. Equivalent to @@ -835,7 +835,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="priv_dir" arity="1"/> + <name name="priv_dir" arity="1" since=""/> <fsummary>Priv directory for an application.</fsummary> <desc> <p>Returns the path to the <c>priv</c> directory in an @@ -846,7 +846,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="objfile_extension" arity="0"/> + <name name="objfile_extension" arity="0" since=""/> <fsummary>Object code file extension.</fsummary> <desc> <p>Returns the object code file extension corresponding to @@ -854,7 +854,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="stick_dir" arity="1"/> + <name name="stick_dir" arity="1" since=""/> <fsummary>Mark a directory as sticky.</fsummary> <desc> <p>Marks <c><anno>Dir</anno></c> as sticky.</p> @@ -862,7 +862,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="unstick_dir" arity="1"/> + <name name="unstick_dir" arity="1" since=""/> <fsummary>Remove a sticky directory mark.</fsummary> <desc> <p>Unsticks a directory that is marked as @@ -871,7 +871,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="is_sticky" arity="1"/> + <name name="is_sticky" arity="1" since=""/> <fsummary>Test if a module is sticky.</fsummary> <desc> <p>Returns <c>true</c> if <c><anno>Module</anno></c> is the @@ -882,7 +882,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="where_is_file" arity="1"/> + <name name="where_is_file" arity="1" since=""/> <fsummary>Full name of a file located in the code path.</fsummary> <desc> <p>Searches the code path for <c><anno>Filename</anno></c>, a file of @@ -893,7 +893,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="clash" arity="0"/> + <name name="clash" arity="0" since=""/> <fsummary>Search for modules with identical names.</fsummary> <desc> <p>Searches all directories in the code path for module names with @@ -901,7 +901,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="module_status" arity="1"/> + <name name="module_status" arity="1" since="OTP 20.0"/> <fsummary>Return the status of the module in relation to object file on disk.</fsummary> <desc> <p>Returns:</p> @@ -934,7 +934,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="modified_modules" arity="0"/> + <name name="modified_modules" arity="0" since="OTP 20.0"/> <fsummary>Return a list of all modules modified on disk.</fsummary> <desc> <p>Returns the list of all currently loaded modules for which @@ -943,7 +943,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </desc> </func> <func> - <name name="is_module_native" arity="1"/> + <name name="is_module_native" arity="1" since=""/> <fsummary>Test if a module has native code.</fsummary> <desc> <p>Returns:</p> @@ -961,7 +961,7 @@ rpc:call(Node, code, load_binary, [Module, Filename, Binary]), </func> <func> - <name name="get_mode" arity="0"/> + <name name="get_mode" arity="0" since="OTP R16B"/> <fsummary>The mode of the code server.</fsummary> <desc> <p>Returns an atom describing the mode of the code server: diff --git a/lib/kernel/doc/src/disk_log.xml b/lib/kernel/doc/src/disk_log.xml index 884cb32c0c..e308b06f3c 100644 --- a/lib/kernel/doc/src/disk_log.xml +++ b/lib/kernel/doc/src/disk_log.xml @@ -34,7 +34,7 @@ <rev>D</rev> <file>disk_log.sgml</file> </header> - <module>disk_log</module> + <module since="">disk_log</module> <modulesummary>A disk-based term logging facility.</modulesummary> <description> <p><c>disk_log</c> is a disk-based term logger that enables @@ -238,7 +238,7 @@ </datatypes> <funcs> <func> - <name name="accessible_logs" arity="0"/> + <name name="accessible_logs" arity="0" since=""/> <fsummary>Return the accessible disk logs on the current node.</fsummary> <desc> <p>Returns the names of the disk logs accessible on the current node. @@ -248,8 +248,8 @@ </desc> </func> <func> - <name name="alog" arity="2"/> - <name name="balog" arity="2"/> + <name name="alog" arity="2" since=""/> + <name name="balog" arity="2" since=""/> <fsummary>Asynchronously log an item on to a disk log.</fsummary> <type variable="Log"/> <type variable="Term" name_i="1"/> @@ -275,8 +275,8 @@ </desc> </func> <func> - <name name="alog_terms" arity="2"/> - <name name="balog_terms" arity="2"/> + <name name="alog_terms" arity="2" since=""/> + <name name="balog_terms" arity="2" since=""/> <fsummary>Asynchronously log many items on to a disk log.</fsummary> <type variable="Log"/> <type variable="TermList" name_i="1"/> @@ -303,8 +303,8 @@ </desc> </func> <func> - <name name="block" arity="1"/> - <name name="block" arity="2"/> + <name name="block" arity="1" since=""/> + <name name="block" arity="2" since=""/> <fsummary>Block a disk log.</fsummary> <type name="block_error_rsn"/> <desc> @@ -330,21 +330,21 @@ </desc> </func> <func> - <name name="change_header" arity="2"/> + <name name="change_header" arity="2" since=""/> <fsummary>Change option head or head_func for an owner of a disk log.</fsummary> <desc> <p>Changes the value of option <c>head</c> or <c>head_func</c> for an owner of a disk log.</p> </desc> </func> <func> - <name name="change_notify" arity="3"/> + <name name="change_notify" arity="3" since=""/> <fsummary>Change option notify for an owner of a disk log.</fsummary> <desc> <p>Changes the value of option <c>notify</c> for an owner of a disk log. </p> </desc> </func> <func> - <name name="change_size" arity="2"/> + <name name="change_size" arity="2" since=""/> <fsummary>Change the size of an open disk log.</fsummary> <desc> <p>Changes the size of an open log. @@ -384,10 +384,10 @@ </desc> </func> <func> - <name name="chunk" arity="2"/> - <name name="chunk" arity="3"/> - <name name="bchunk" arity="2"/> - <name name="bchunk" arity="3"/> + <name name="chunk" arity="2" since=""/> + <name name="chunk" arity="3" since=""/> + <name name="bchunk" arity="2" since=""/> + <name name="bchunk" arity="3" since=""/> <fsummary>Read a chunk of items written to a disk log.</fsummary> <type variable="Log"/> <type variable="Continuation"/> @@ -447,7 +447,7 @@ </desc> </func> <func> - <name name="chunk_info" arity="1"/> + <name name="chunk_info" arity="1" since=""/> <fsummary>Return information about a chunk continuation of a disk log.</fsummary> <desc> <p>Returns the pair <c>{node, <anno>Node</anno>}</c>, @@ -457,7 +457,7 @@ </desc> </func> <func> - <name name="chunk_step" arity="3"/> + <name name="chunk_step" arity="3" since=""/> <fsummary>Step forward or backward among the wrap log files of a disk log.</fsummary> <desc> <p>Can be used with <c>chunk/2,3</c> and <c>bchunk/2,3</c> @@ -480,7 +480,7 @@ </desc> </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a disk log.</fsummary> <type name="close_error_rsn"/> <desc> @@ -505,7 +505,7 @@ </desc> </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Return an English description of a disk log error reply.</fsummary> <desc> <p>Given the error returned by any function in this module, @@ -517,7 +517,7 @@ </desc> </func> <func> - <name name="inc_wrap_file" arity="1"/> + <name name="inc_wrap_file" arity="1" since=""/> <fsummary>Change to the next wrap log file of a disk log.</fsummary> <type name="inc_wrap_error_rsn"/> <type name="invalid_header"/> @@ -534,7 +534,7 @@ </desc> </func> <func> - <name name="info" arity="1"/> + <name name="info" arity="1" since=""/> <fsummary>Return information about a disk log.</fsummary> <type name="dlog_info"/> <desc> @@ -685,8 +685,8 @@ </desc> </func> <func> - <name name="lclose" arity="1"/> - <name name="lclose" arity="2"/> + <name name="lclose" arity="1" since=""/> + <name name="lclose" arity="2" since=""/> <fsummary>Close a disk log on one node.</fsummary> <type name="lclose_error_rsn"/> <desc> @@ -704,8 +704,8 @@ </desc> </func> <func> - <name name="log" arity="2"/> - <name name="blog" arity="2"/> + <name name="log" arity="2" since=""/> + <name name="blog" arity="2" since=""/> <fsummary>Log an item onto a disk log.</fsummary> <type variable="Log"/> <type variable="Term" name_i="1"/> @@ -739,8 +739,8 @@ </desc> </func> <func> - <name name="log_terms" arity="2"/> - <name name="blog_terms" arity="2"/> + <name name="log_terms" arity="2" since=""/> + <name name="blog_terms" arity="2" since=""/> <fsummary>Log many items onto a disk log.</fsummary> <type variable="Log"/> <type variable="TermList" name_i="1"/> @@ -768,7 +768,7 @@ </desc> </func> <func> - <name name="open" arity="1"/> + <name name="open" arity="1" since=""/> <fsummary>Open a disk log file.</fsummary> <type name="dlog_options"/> <type name="dlog_option"/> @@ -1041,7 +1041,7 @@ </desc> </func> <func> - <name name="pid2name" arity="1"/> + <name name="pid2name" arity="1" since=""/> <fsummary>Return the name of the disk log handled by a pid.</fsummary> <desc> <p>Returns the log name @@ -1053,9 +1053,9 @@ </desc> </func> <func> - <name name="reopen" arity="2"/> - <name name="reopen" arity="3"/> - <name name="breopen" arity="3"/> + <name name="reopen" arity="2" since=""/> + <name name="reopen" arity="3" since=""/> + <name name="breopen" arity="3" since=""/> <fsummary>Reopen a disk log and save the old log.</fsummary> <type variable="Log"/> <type variable="File" name_i="1"/> @@ -1087,7 +1087,7 @@ </desc> </func> <func> - <name name="sync" arity="1"/> + <name name="sync" arity="1" since=""/> <fsummary>Flush the contents of a disk log to the disk.</fsummary> <type name="sync_error_rsn"/> <desc> @@ -1097,9 +1097,9 @@ </desc> </func> <func> - <name name="truncate" arity="1"/> - <name name="truncate" arity="2"/> - <name name="btruncate" arity="2"/> + <name name="truncate" arity="1" since=""/> + <name name="truncate" arity="2" since=""/> + <name name="btruncate" arity="2" since=""/> <fsummary>Truncate a disk log.</fsummary> <type variable="Log"/> <type variable="Head" name_i="2"/> @@ -1129,7 +1129,7 @@ </desc> </func> <func> - <name name="unblock" arity="1"/> + <name name="unblock" arity="1" since=""/> <fsummary>Unblock a disk log.</fsummary> <type name="unblock_error_rsn"/> <desc> diff --git a/lib/kernel/doc/src/erl_boot_server.xml b/lib/kernel/doc/src/erl_boot_server.xml index 4109251387..89f9855c49 100644 --- a/lib/kernel/doc/src/erl_boot_server.xml +++ b/lib/kernel/doc/src/erl_boot_server.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>erl_boot_server</module> + <module since="">erl_boot_server</module> <modulesummary>Boot server for other Erlang machines.</modulesummary> <description> <p>This server is used to assist diskless Erlang nodes that fetch @@ -52,14 +52,14 @@ </description> <funcs> <func> - <name name="add_slave" arity="1"/> + <name name="add_slave" arity="1" since=""/> <fsummary>Add a slave to the list of allowed slaves.</fsummary> <desc> <p>Adds a <c><anno>Slave</anno></c> node to the list of allowed slave hosts.</p> </desc> </func> <func> - <name name="delete_slave" arity="1"/> + <name name="delete_slave" arity="1" since=""/> <fsummary>Delete a slave from the list of allowed slaves.</fsummary> <desc> <p>Deletes a <c><anno>Slave</anno></c> node from the list of allowed slave @@ -67,7 +67,7 @@ </desc> </func> <func> - <name name="start" arity="1"/> + <name name="start" arity="1" since=""/> <fsummary>Start the boot server.</fsummary> <desc> <p>Starts the boot server. <c><anno>Slaves</anno></c> is a list of @@ -76,7 +76,7 @@ </desc> </func> <func> - <name name="start_link" arity="1"/> + <name name="start_link" arity="1" since=""/> <fsummary>Start the boot server and link to the the caller.</fsummary> <desc> <p>Starts the boot server and links to the caller. This function @@ -85,7 +85,7 @@ </desc> </func> <func> - <name name="which_slaves" arity="0"/> + <name name="which_slaves" arity="0" since=""/> <fsummary>Return the current list of allowed slave hosts.</fsummary> <desc> <p>Returns the current list of allowed slave hosts.</p> diff --git a/lib/kernel/doc/src/erl_ddll.xml b/lib/kernel/doc/src/erl_ddll.xml index 75114e015c..f2d5e1b397 100644 --- a/lib/kernel/doc/src/erl_ddll.xml +++ b/lib/kernel/doc/src/erl_ddll.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>erl_ddll</module> + <module since="">erl_ddll</module> <modulesummary>Dynamic driver loader and linker.</modulesummary> <description> <p>This module provides an interface for loading @@ -196,7 +196,7 @@ </datatypes> <funcs> <func> - <name name="demonitor" arity="1"/> + <name name="demonitor" arity="1" since=""/> <fsummary>Remove a monitor for a driver.</fsummary> <desc> <p>Removes a driver monitor in much the same way as @@ -212,7 +212,7 @@ </desc> </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Format an error descriptor.</fsummary> <desc> <p>Takes an <c><anno>ErrorDesc</anno></c> returned by load, unload, or @@ -229,7 +229,7 @@ </desc> </func> <func> - <name name="info" arity="0"/> + <name name="info" arity="0" since=""/> <fsummary>Retrieve information about all drivers.</fsummary> <desc> <p>Returns a list of tuples <c>{<anno>DriverName</anno>, <anno>InfoList</anno>}</c>, @@ -240,7 +240,7 @@ </desc> </func> <func> - <name name="info" arity="1"/> + <name name="info" arity="1" since=""/> <fsummary>Retrieve information about one driver.</fsummary> <desc> <p>Returns a list of tuples <c>{<anno>Tag</anno>, <anno>Value</anno>}</c>, @@ -266,7 +266,7 @@ </desc> </func> <func> - <name name="info" arity="2"/> + <name name="info" arity="2" since=""/> <fsummary>Retrieve specific information about one driver.</fsummary> <desc> <p>Returns specific information about one aspect of a driver. @@ -328,7 +328,7 @@ </desc> </func> <func> - <name name="load" arity="2"/> + <name name="load" arity="2" since=""/> <fsummary>Load a driver.</fsummary> <desc> <p>Loads and links the dynamic driver <c><anno>Name</anno></c>. @@ -390,7 +390,7 @@ </desc> </func> <func> - <name name="load_driver" arity="2"/> + <name name="load_driver" arity="2" since=""/> <fsummary>Load a driver.</fsummary> <desc> <p>Works essentially as <c>load/2</c>, but loads the driver @@ -413,7 +413,7 @@ </desc> </func> <func> - <name name="loaded_drivers" arity="0"/> + <name name="loaded_drivers" arity="0" since=""/> <fsummary>List loaded drivers.</fsummary> <desc> <p>Returns a list of all the available drivers, both @@ -425,7 +425,7 @@ </desc> </func> <func> - <name name="monitor" arity="2"/> + <name name="monitor" arity="2" since=""/> <fsummary>Create a monitor for a driver.</fsummary> <desc> <p>Creates a driver monitor and works in many @@ -588,7 +588,7 @@ </desc> </func> <func> - <name name="reload" arity="2"/> + <name name="reload" arity="2" since=""/> <fsummary>Replace a driver.</fsummary> <desc> <p>Reloads the driver named <c><anno>Name</anno></c> from a possibly @@ -626,7 +626,7 @@ </desc> </func> <func> - <name name="reload_driver" arity="2"/> + <name name="reload_driver" arity="2" since=""/> <fsummary>Replace a driver.</fsummary> <desc> <p>Works exactly as <seealso marker="#reload/2"><c>reload/2</c></seealso>, @@ -644,7 +644,7 @@ </desc> </func> <func> - <name name="try_load" arity="3"/> + <name name="try_load" arity="3" since=""/> <fsummary>Load a driver.</fsummary> <desc> <p>Provides more control than the @@ -931,7 +931,7 @@ </desc> </func> <func> - <name name="try_unload" arity="2"/> + <name name="try_unload" arity="2" since=""/> <fsummary>Unload a driver.</fsummary> <desc> <p>This is the low-level function to unload (or decrement @@ -1116,7 +1116,7 @@ </desc> </func> <func> - <name name="unload" arity="1"/> + <name name="unload" arity="1" since=""/> <fsummary>Unload a driver.</fsummary> <desc> <p>Unloads, or at least dereferences the driver named @@ -1143,7 +1143,7 @@ </desc> </func> <func> - <name name="unload_driver" arity="1"/> + <name name="unload_driver" arity="1" since=""/> <fsummary>Unload a driver.</fsummary> <desc> <p>Unloads, or at least dereferences the driver named diff --git a/lib/kernel/doc/src/erl_epmd.xml b/lib/kernel/doc/src/erl_epmd.xml index 8b076cd2d7..2adbf11a28 100644 --- a/lib/kernel/doc/src/erl_epmd.xml +++ b/lib/kernel/doc/src/erl_epmd.xml @@ -28,7 +28,7 @@ <date>2018-02-19</date> <rev>A</rev> </header> - <module>erl_epmd</module> + <module since="OTP R14B">erl_epmd</module> <modulesummary> Erlang interface towards epmd </modulesummary> @@ -41,7 +41,7 @@ <funcs> <func> - <name name="start_link" arity="0"/> + <name name="start_link" arity="0" since="OTP 21.0"/> <fsummary>Callback for erl_distribution supervisor.</fsummary> <desc> <p>This function is invoked as this module is added as a child of the @@ -50,8 +50,8 @@ </func> <func> - <name name="register_node" arity="2"/> - <name name="register_node" arity="3"/> + <name name="register_node" arity="2" since="OTP 21.0"/> + <name name="register_node" arity="3" since="OTP 21.0"/> <fsummary>Registers the node with <c>epmd</c>.</fsummary> <desc> <p>Registers the node with <c>epmd</c> and tells epmd what port will be @@ -62,8 +62,8 @@ </func> <func> - <name name="port_please" arity="2"/> - <name name="port_please" arity="3"/> + <name name="port_please" arity="2" since="OTP 21.0"/> + <name name="port_please" arity="3" since="OTP 21.0"/> <fsummary>Returns the port number for a given node.</fsummary> <desc> <p>Requests the distribution port for the given node of an EPMD @@ -73,7 +73,7 @@ </func> <func> - <name name="address_please" arity="3"/> + <name name="address_please" arity="3" since="OTP 21.0"/> <fsummary>Returns address and port.</fsummary> <desc> <p>Called by the distribution module. Resolves the <c>Host</c> to an IP @@ -84,7 +84,7 @@ </func> <func> - <name name="names" arity="1"/> + <name name="names" arity="1" since="OTP 21.0"/> <fsummary>Names of Erlang nodes at a host.</fsummary> <desc> <p>Called by <seealso marker="net_adm"><c>net_adm:names/0</c></seealso>. diff --git a/lib/kernel/doc/src/error_handler.xml b/lib/kernel/doc/src/error_handler.xml index e5639487dc..eb01e87aee 100644 --- a/lib/kernel/doc/src/error_handler.xml +++ b/lib/kernel/doc/src/error_handler.xml @@ -30,7 +30,7 @@ <date></date> <rev></rev> </header> - <module>error_handler</module> + <module since="">error_handler</module> <modulesummary>Default system error handler.</modulesummary> <description> <p>This module defines what happens when certain types @@ -38,7 +38,7 @@ </description> <funcs> <func> - <name name="raise_undef_exception" arity="3"/> + <name name="raise_undef_exception" arity="3" since="OTP R16B"/> <fsummary>Raise an undef exception.</fsummary> <type_desc variable="Args"> A (possibly empty) list of arguments <c>Arg1,..,ArgN</c> @@ -51,7 +51,7 @@ </desc> </func> <func> - <name name="undefined_function" arity="3"/> + <name name="undefined_function" arity="3" since=""/> <fsummary>Called when an undefined function is encountered.</fsummary> <type_desc variable="Args"> A (possibly empty) list of arguments <c>Arg1,..,ArgN</c> @@ -93,7 +93,7 @@ </desc> </func> <func> - <name name="undefined_lambda" arity="3"/> + <name name="undefined_lambda" arity="3" since=""/> <fsummary>Called when an undefined lambda (fun) is encountered.</fsummary> <type_desc variable="Args"> A (possibly empty) list of arguments <c>Arg1,..,ArgN</c> diff --git a/lib/kernel/doc/src/error_logger.xml b/lib/kernel/doc/src/error_logger.xml index c3d68fd79f..c170b4fa34 100644 --- a/lib/kernel/doc/src/error_logger.xml +++ b/lib/kernel/doc/src/error_logger.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>error_logger</module> + <module since="">error_logger</module> <modulesummary>Erlang error logger.</modulesummary> <description> @@ -76,8 +76,8 @@ </datatypes> <funcs> <func> - <name name="add_report_handler" arity="1"/> - <name name="add_report_handler" arity="2"/> + <name name="add_report_handler" arity="1" since=""/> + <name name="add_report_handler" arity="2" since=""/> <fsummary>Add an event handler to the error logger.</fsummary> <desc> <p>Adds a new event handler to the error logger. The event @@ -96,7 +96,7 @@ </desc> </func> <func> - <name name="delete_report_handler" arity="1"/> + <name name="delete_report_handler" arity="1" since=""/> <fsummary>Delete an event handler from the error logger.</fsummary> <desc> <p>Deletes an event handler from the error logger by calling @@ -108,9 +108,9 @@ </desc> </func> <func> - <name name="error_msg" arity="1"/> - <name name="error_msg" arity="2"/> - <name name="format" arity="2"/> + <name name="error_msg" arity="1" since=""/> + <name name="error_msg" arity="2" since=""/> + <name name="format" arity="2" since=""/> <fsummary>Log a standard error event.</fsummary> <desc> <p>Log a standard error event. The <c><anno>Format</anno></c> @@ -142,7 +142,7 @@ ok</pre> </desc> </func> <func> - <name name="error_report" arity="1"/> + <name name="error_report" arity="1" since=""/> <fsummary>Log a standard error event.</fsummary> <desc> <p>Log a standard error event. Error logger forwards the event @@ -169,7 +169,7 @@ ok</pre> </desc> </func> <func> - <name name="error_report" arity="2"/> + <name name="error_report" arity="2" since=""/> <fsummary>Log a user-defined error event.</fsummary> <desc> <p>Log a user-defined error event. Error logger forwards the @@ -191,7 +191,7 @@ ok</pre> </desc> </func> <func> - <name name="get_format_depth" arity="0"/> + <name name="get_format_depth" arity="0" since="OTP 20.0"/> <fsummary>Get the value of the Kernel application variable <c>error_logger_format_depth</c>.</fsummary> <desc> @@ -211,8 +211,8 @@ ok</pre> </desc> </func> <func> - <name name="info_msg" arity="1"/> - <name name="info_msg" arity="2"/> + <name name="info_msg" arity="1" since=""/> + <name name="info_msg" arity="2" since=""/> <fsummary>Log a standard information event.</fsummary> <desc> <p>Log a standard information event. The <c><anno>Format</anno></c> @@ -244,7 +244,7 @@ ok</pre> </desc> </func> <func> - <name name="info_report" arity="1"/> + <name name="info_report" arity="1" since=""/> <fsummary>Log a standard information event.</fsummary> <desc> <p>Log a standard information event. Error logger forwards the @@ -271,7 +271,7 @@ ok</pre> </desc> </func> <func> - <name name="info_report" arity="2"/> + <name name="info_report" arity="2" since=""/> <fsummary>Log a user-defined information event.</fsummary> <desc> <p>Log a user-defined information event. Error logger forwards @@ -294,9 +294,9 @@ ok</pre> </desc> </func> <func> - <name name="logfile" arity="1" clause_i="1"/> - <name name="logfile" arity="1" clause_i="2"/> - <name name="logfile" arity="1" clause_i="3"/> + <name name="logfile" arity="1" clause_i="1" since=""/> + <name name="logfile" arity="1" clause_i="2" since=""/> + <name name="logfile" arity="1" clause_i="3" since=""/> <fsummary>Enable or disable error printouts to a file.</fsummary> <type variable="Filename"/> <type variable="OpenReason" name_i="1"/> @@ -346,7 +346,7 @@ ok</pre> </desc> </func> <func> - <name name="tty" arity="1"/> + <name name="tty" arity="1" since=""/> <fsummary>Enable or disable printouts to the terminal.</fsummary> <desc> <p>Enables (<c><anno>Flag</anno> == true</c>) or disables @@ -363,7 +363,7 @@ ok</pre> </desc> </func> <func> - <name name="warning_map" arity="0"/> + <name name="warning_map" arity="0" since=""/> <fsummary>Return the current mapping for warning events.</fsummary> <desc> <p>Returns the current mapping for warning events. Events sent @@ -400,8 +400,8 @@ ok</pre> </desc> </func> <func> - <name name="warning_msg" arity="1"/> - <name name="warning_msg" arity="2"/> + <name name="warning_msg" arity="1" since=""/> + <name name="warning_msg" arity="2" since=""/> <fsummary>Log a standard warning event.</fsummary> <desc> <p>Log a standard warning event. The <c><anno>Format</anno></c> @@ -429,7 +429,7 @@ ok</pre> </desc> </func> <func> - <name name="warning_report" arity="1"/> + <name name="warning_report" arity="1" since=""/> <fsummary>Log a standard warning event.</fsummary> <desc> <p>Log a standard warning event. Error logger forwards the event @@ -446,7 +446,7 @@ ok</pre> </desc> </func> <func> - <name name="warning_report" arity="2"/> + <name name="warning_report" arity="2" since=""/> <fsummary>Log a user-defined warning event.</fsummary> <desc> <p>Log a user-defined warning event. Error logger forwards the diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml index 9acaf6b41e..fc25e83d40 100644 --- a/lib/kernel/doc/src/file.xml +++ b/lib/kernel/doc/src/file.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>file</module> + <module since="">file</module> <modulesummary>File interface module.</modulesummary> <description> <p>This module provides an interface to the file system.</p> @@ -186,7 +186,7 @@ <funcs> <func> - <name name="advise" arity="4"/> + <name name="advise" arity="4" since="OTP R14B"/> <fsummary>Predeclare an access pattern for file data.</fsummary> <type name="posix_file_advise"/> <desc> @@ -197,7 +197,7 @@ </desc> </func> <func> - <name name="allocate" arity="3"/> + <name name="allocate" arity="3" since="OTP R16B"/> <fsummary>Allocate file space.</fsummary> <desc> <p><c>allocate/3</c> can be used to preallocate space for a file.</p> @@ -209,7 +209,7 @@ </desc> </func> <func> - <name name="change_group" arity="2"/> + <name name="change_group" arity="2" since=""/> <fsummary>Change group of a file.</fsummary> <desc> <p>Changes group of a file. See @@ -217,7 +217,7 @@ </desc> </func> <func> - <name name="change_mode" arity="2"/> + <name name="change_mode" arity="2" since="OTP R14B"/> <fsummary>Change permissions of a file.</fsummary> <desc> <p>Changes permissions of a file. See @@ -225,7 +225,7 @@ </desc> </func> <func> - <name name="change_owner" arity="2"/> + <name name="change_owner" arity="2" since=""/> <fsummary>Change owner of a file.</fsummary> <desc> <p>Changes owner of a file. See @@ -233,7 +233,7 @@ </desc> </func> <func> - <name name="change_owner" arity="3"/> + <name name="change_owner" arity="3" since=""/> <fsummary>Change owner and group of a file.</fsummary> <desc> <p>Changes owner and group of a file. See @@ -241,7 +241,7 @@ </desc> </func> <func> - <name name="change_time" arity="2"/> + <name name="change_time" arity="2" since=""/> <fsummary>Change the modification time of a file.</fsummary> <desc> <p>Changes the modification and access times of a file. See @@ -249,7 +249,7 @@ </desc> </func> <func> - <name name="change_time" arity="3"/> + <name name="change_time" arity="3" since=""/> <fsummary>Change the modification and last access time of a file.</fsummary> <desc> <p>Changes the modification and last access times of a file. See @@ -257,7 +257,7 @@ </desc> </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a file.</fsummary> <desc> <p>Closes the file referenced by <c><anno>IoDevice</anno></c>. It mostly @@ -270,7 +270,7 @@ </desc> </func> <func> - <name name="consult" arity="1"/> + <name name="consult" arity="1" since=""/> <fsummary>Read Erlang terms from a file.</fsummary> <desc> <p>Reads Erlang terms, separated by '.', from @@ -308,8 +308,8 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="copy" arity="2"/> - <name name="copy" arity="3"/> + <name name="copy" arity="2" since=""/> + <name name="copy" arity="3" since=""/> <fsummary>Copy file contents.</fsummary> <desc> <p>Copies <c><anno>ByteCount</anno></c> bytes from @@ -346,7 +346,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="datasync" arity="1"/> + <name name="datasync" arity="1" since="OTP R14B"/> <fsummary>Synchronize the in-memory data of a file, ignoring most of its metadata, with that on the physical medium.</fsummary> <desc> <p>Ensures that any buffers kept by the operating system @@ -369,7 +369,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="del_dir" arity="1"/> + <name name="del_dir" arity="1" since=""/> <fsummary>Delete a directory.</fsummary> <desc> <p>Tries to delete directory <c><anno>Dir</anno></c>. @@ -405,7 +405,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="delete" arity="1"/> + <name name="delete" arity="1" since=""/> <fsummary>Delete a file.</fsummary> <desc> <p>Tries to delete file <c><anno>Filename</anno></c>. @@ -442,7 +442,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="eval" arity="1"/> + <name name="eval" arity="1" since=""/> <fsummary>Evaluate Erlang expressions in a file.</fsummary> <desc> <p>Reads and evaluates Erlang expressions, separated by '.' (or @@ -476,7 +476,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="eval" arity="2"/> + <name name="eval" arity="2" since=""/> <fsummary>Evaluate Erlang expressions in a file.</fsummary> <desc> <p>The same as <c>eval/1</c>, but the variable bindings @@ -486,7 +486,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Return a descriptive string for an error reason.</fsummary> <desc> <p>Given the error reason returned by any function in this @@ -494,7 +494,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="get_cwd" arity="0"/> + <name name="get_cwd" arity="0" since=""/> <fsummary>Get the current working directory.</fsummary> <desc> <p>Returns <c>{ok, <anno>Dir</anno>}</c>, where <c><anno>Dir</anno></c> @@ -516,7 +516,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="get_cwd" arity="1"/> + <name name="get_cwd" arity="1" since=""/> <fsummary>Get the current working directory for the specified drive.</fsummary> <desc> <p>Returns <c>{ok, <anno>Dir</anno>}</c> or @@ -547,7 +547,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="list_dir" arity="1"/> + <name name="list_dir" arity="1" since=""/> <fsummary>List files in a directory.</fsummary> <desc> <p>Lists all files in a directory, <em>except</em> files @@ -578,7 +578,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="list_dir_all" arity="1"/> + <name name="list_dir_all" arity="1" since="OTP R16B"/> <fsummary>List all files in a directory.</fsummary> <desc> <p><marker id="list_dir_all"/>Lists all the files in a directory, @@ -603,7 +603,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="make_dir" arity="1"/> + <name name="make_dir" arity="1" since=""/> <fsummary>Make a directory.</fsummary> <desc> <p>Tries to create directory <c><anno>Dir</anno></c>. Missing parent @@ -637,7 +637,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="make_link" arity="2"/> + <name name="make_link" arity="2" since=""/> <fsummary>Make a hard link to a file.</fsummary> <desc> <p>Makes a hard link from <c><anno>Existing</anno></c> to @@ -666,7 +666,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="make_symlink" arity="2"/> + <name name="make_symlink" arity="2" since=""/> <fsummary>Make a symbolic link to a file or directory.</fsummary> <desc> <p>Creates a symbolic link <c><anno>New</anno></c> to @@ -702,7 +702,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="native_name_encoding" arity="0"/> + <name name="native_name_encoding" arity="0" since="OTP R14B01"/> <fsummary>Return the configured filename encoding of the VM.</fsummary> <desc> <p><marker id="native_name_encoding"/>Returns @@ -714,7 +714,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="open" arity="2"/> + <name name="open" arity="2" since=""/> <fsummary>Open a file.</fsummary> <desc> <p>Opens file <c><anno>File</anno></c> in the mode determined @@ -997,7 +997,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="path_consult" arity="2"/> + <name name="path_consult" arity="2" since=""/> <fsummary>Read Erlang terms from a file.</fsummary> <desc> <p>Searches the path <c><anno>Path</anno></c> (a list of directory @@ -1039,7 +1039,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="path_eval" arity="2"/> + <name name="path_eval" arity="2" since=""/> <fsummary>Evaluate Erlang expressions in a file.</fsummary> <desc> <p>Searches the path <c><anno>Path</anno></c> (a list of directory @@ -1085,7 +1085,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="path_open" arity="3"/> + <name name="path_open" arity="3" since=""/> <fsummary>Open a file.</fsummary> <desc> <p>Searches the path <c><anno>Path</anno></c> (a list of directory @@ -1114,7 +1114,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="path_script" arity="2"/> + <name name="path_script" arity="2" since=""/> <fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary> <desc> <p>Searches the path <c><anno>Path</anno></c> (a list of directory @@ -1158,7 +1158,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="path_script" arity="3"/> + <name name="path_script" arity="3" since=""/> <fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary> <desc> <p>The same as <c>path_script/2</c> but the variable bindings @@ -1168,7 +1168,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="pid2name" arity="1"/> + <name name="pid2name" arity="1" since=""/> <fsummary>Return the name of the file handled by a pid.</fsummary> <desc> <p>If <c><anno>Pid</anno></c> is an I/O device, that is, a pid returned from @@ -1193,7 +1193,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="position" arity="2"/> + <name name="position" arity="2" since=""/> <fsummary>Set position in a file.</fsummary> <desc> <p>Sets the position of the file referenced by <c><anno>IoDevice</anno></c> @@ -1245,7 +1245,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="pread" arity="2"/> + <name name="pread" arity="2" since=""/> <fsummary>Read from a file at certain positions.</fsummary> <desc> <p>Performs a sequence of <c>pread/3</c> in one operation, @@ -1263,7 +1263,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="pread" arity="3"/> + <name name="pread" arity="3" since=""/> <fsummary>Read from a file at a certain position.</fsummary> <desc> <p>Combines <c>position/2</c> and <c>read/2</c> in one @@ -1283,7 +1283,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="pwrite" arity="2"/> + <name name="pwrite" arity="2" since=""/> <fsummary>Write to a file at certain positions.</fsummary> <desc> <p>Performs a sequence of <c>pwrite/3</c> in one operation, @@ -1298,7 +1298,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="pwrite" arity="3"/> + <name name="pwrite" arity="3" since=""/> <fsummary>Write to a file at a certain position.</fsummary> <desc> <p>Combines <c>position/2</c> and <c>write/2</c> in one @@ -1317,7 +1317,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read" arity="2"/> + <name name="read" arity="2" since=""/> <fsummary>Read from a file.</fsummary> <desc> <p>Reads <c><anno>Number</anno></c> bytes/characters from the file @@ -1371,7 +1371,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read_file" arity="1"/> + <name name="read_file" arity="1" since=""/> <fsummary>Read a file.</fsummary> <desc> <p>Returns <c>{ok, <anno>Binary</anno>}</c>, where @@ -1407,8 +1407,8 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read_file_info" arity="1"/> - <name name="read_file_info" arity="2"/> + <name name="read_file_info" arity="1" since=""/> + <name name="read_file_info" arity="2" since="OTP R15B"/> <fsummary>Retrieve information about a file.</fsummary> <desc> <p>Retrieves information about a file. Returns @@ -1562,7 +1562,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read_line" arity="1"/> + <name name="read_line" arity="1" since=""/> <fsummary>Read a line from a file.</fsummary> <desc> <p>Reads a line of bytes/characters from the file referenced by @@ -1619,7 +1619,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read_link" arity="1"/> + <name name="read_link" arity="1" since=""/> <fsummary>See what a link is pointing to.</fsummary> <desc> <p><marker id="read_link_all"/>Returns @@ -1649,7 +1649,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read_link_all" arity="1"/> + <name name="read_link_all" arity="1" since="OTP R16B"/> <fsummary>See what a link is pointing to.</fsummary> <desc> <p>Returns <c>{ok, <anno>Filename</anno>}</c> if @@ -1677,8 +1677,8 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="read_link_info" arity="1"/> - <name name="read_link_info" arity="2"/> + <name name="read_link_info" arity="1" since=""/> + <name name="read_link_info" arity="2" since="OTP R15B"/> <fsummary>Retrieve information about a link or file.</fsummary> <desc> <p>Works like @@ -1699,7 +1699,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="rename" arity="2"/> + <name name="rename" arity="2" since=""/> <fsummary>Rename a file.</fsummary> <desc> <p>Tries to rename the file <c><anno>Source</anno></c> to @@ -1762,7 +1762,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="script" arity="1"/> + <name name="script" arity="1" since=""/> <fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary> <desc> <p>Reads and evaluates Erlang expressions, separated by '.' (or @@ -1797,7 +1797,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="script" arity="2"/> + <name name="script" arity="2" since=""/> <fsummary>Evaluate and return the value of Erlang expressions in a file.</fsummary> <desc> <p>The same as <c>script/1</c> but the variable bindings @@ -1807,7 +1807,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="sendfile" arity="2"/> + <name name="sendfile" arity="2" since="OTP R15B"/> <fsummary>Send a file to a socket.</fsummary> <desc> <p>Sends the file <c>Filename</c> to <c>Socket</c>. @@ -1816,7 +1816,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="sendfile" arity="5"/> + <name name="sendfile" arity="5" since="OTP R15B"/> <fsummary>Send a file to a socket.</fsummary> <type name="sendfile_option"/> <desc> @@ -1843,7 +1843,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="set_cwd" arity="1"/> + <name name="set_cwd" arity="1" since=""/> <fsummary>Set the current working directory.</fsummary> <desc> <p>Sets the current working directory of the file server to @@ -1890,7 +1890,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="sync" arity="1"/> + <name name="sync" arity="1" since=""/> <fsummary>Synchronize the in-memory state of a file with that on the physical medium.</fsummary> <desc> <p>Ensures that any buffers kept by the operating system @@ -1906,7 +1906,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="truncate" arity="1"/> + <name name="truncate" arity="1" since=""/> <fsummary>Truncate a file.</fsummary> <desc> <p>Truncates the file referenced by <c><anno>IoDevice</anno></c> at @@ -1915,7 +1915,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="write" arity="2"/> + <name name="write" arity="2" since=""/> <fsummary>Write to a file.</fsummary> <desc> <p>Writes <c><anno>Bytes</anno></c> to the file referenced by @@ -1941,7 +1941,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="write_file" arity="2"/> + <name name="write_file" arity="2" since=""/> <fsummary>Write a file.</fsummary> <desc> <p>Writes the contents of the <c>iodata</c> term <c><anno>Bytes</anno></c> @@ -1978,7 +1978,7 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="write_file" arity="3"/> + <name name="write_file" arity="3" since=""/> <fsummary>Write a file.</fsummary> <desc> <p>Same as <c>write_file/2</c>, but takes a third argument @@ -1989,8 +1989,8 @@ f.txt: {person, "kalle", 25}. </desc> </func> <func> - <name name="write_file_info" arity="2"/> - <name name="write_file_info" arity="3"/> + <name name="write_file_info" arity="2" since=""/> + <name name="write_file_info" arity="3" since="OTP R15B"/> <fsummary>Change file information.</fsummary> <desc> <p>Changes file information. Returns <c>ok</c> if successful, diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml index 1e08b25f66..1e7009b3a8 100644 --- a/lib/kernel/doc/src/gen_sctp.xml +++ b/lib/kernel/doc/src/gen_sctp.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>gen_sctp.xml</file> </header> - <module>gen_sctp</module> + <module since="">gen_sctp</module> <modulesummary>Functions for communicating with sockets using the SCTP protocol.</modulesummary> <description> @@ -100,7 +100,7 @@ <funcs> <func> - <name name="abort" arity="2"/> + <name name="abort" arity="2" since=""/> <fsummary>Abnormally terminate the association specified by <c>Assoc</c>, without flushing of unsent data.</fsummary> <desc> @@ -113,7 +113,7 @@ </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close the socket and all associations on it.</fsummary> <desc> <p>Closes the socket and all associations on it. The unsent @@ -128,7 +128,7 @@ </func> <func> - <name name="connect" arity="4"/> + <name name="connect" arity="4" since=""/> <fsummary>Same as <c>connect(Socket, Addr, Port, Opts, infinity)</c>.</fsummary> <desc> <p>Same as <c>connect(<anno>Socket</anno>, <anno>Addr</anno>, @@ -137,7 +137,7 @@ </func> <func> - <name name="connect" arity="5"/> + <name name="connect" arity="5" since=""/> <fsummary>Establish a new association for socket <c>Socket</c>, with a peer (SCTP server socket).</fsummary> <desc> @@ -213,7 +213,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="connect_init" arity="4"/> + <name name="connect_init" arity="4" since="OTP R13B04"/> <fsummary>Same as <c>connect_init(Socket, Addr, Port, Opts, infinity)</c>..</fsummary> <desc> <p>Same as <c>connect_init(<anno>Socket</anno>, <anno>Addr</anno>, @@ -222,7 +222,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="connect_init" arity="5"/> + <name name="connect_init" arity="5" since="OTP R13B04"/> <fsummary>Initiate a new association for socket <c>Socket</c>, with a peer (SCTP server socket).</fsummary> <desc> @@ -248,7 +248,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="controlling_process" arity="2"/> + <name name="controlling_process" arity="2" since=""/> <fsummary>Assign a new controlling process pid to the socket.</fsummary> <desc> <p>Assigns a new controlling process <c><anno>Pid</anno></c> to @@ -259,7 +259,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="eof" arity="2"/> + <name name="eof" arity="2" since=""/> <fsummary>Gracefully terminate the association specified by <c>Assoc</c>, with flushing of all unsent data.</fsummary> <desc> @@ -272,7 +272,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="error_string" arity="1"/> + <name name="error_string" arity="1" since=""/> <fsummary>Translate an SCTP error number into a string.</fsummary> <desc> <p>Translates an SCTP error number from, for example, @@ -283,8 +283,8 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="listen" arity="2" clause_i="1"/> - <name name="listen" arity="2" clause_i="2"/> + <name name="listen" arity="2" clause_i="1" since=""/> + <name name="listen" arity="2" clause_i="2" since=""/> <fsummary>Set up a socket to listen.</fsummary> <desc> <p>Sets up a socket to listen on the IP address and port number @@ -300,10 +300,10 @@ connect(Socket, Ip, Port>, </func> <func> - <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"/> + <name name="open" arity="0" since=""/> + <name name="open" arity="1" clause_i="1" since=""/> + <name name="open" arity="1" clause_i="2" since=""/> + <name name="open" arity="2" since=""/> <fsummary>Create an SCTP socket and binds it to local addresses.</fsummary> <desc> <p>Creates an SCTP socket and binds it to the local addresses @@ -366,7 +366,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="peeloff" arity="2"/> + <name name="peeloff" arity="2" since="OTP R15B"/> <fsummary>Peel off a type <c>stream</c> socket from a type <c>seqpacket</c> one.</fsummary> <desc> @@ -387,8 +387,8 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="recv" arity="1"/> - <name name="recv" arity="2"/> + <name name="recv" arity="1" since=""/> + <name name="recv" arity="2" since=""/> <fsummary>Receive a message from a socket.</fsummary> <desc> <p>Receives the <c><anno>Data</anno></c> message from any association @@ -532,7 +532,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="send" arity="3"/> + <name name="send" arity="3" since=""/> <fsummary>Send a message using an <c>#sctp_sndrcvinfo{}</c>record.</fsummary> <desc> <p>Sends the <c><anno>Data</anno></c> message with all sending @@ -547,7 +547,7 @@ connect(Socket, Ip, Port>, </func> <func> - <name name="send" arity="4"/> + <name name="send" arity="4" since=""/> <fsummary>Send a message over an existing association and specified stream.</fsummary> <desc> diff --git a/lib/kernel/doc/src/gen_tcp.xml b/lib/kernel/doc/src/gen_tcp.xml index 24d63693fd..fc16473393 100644 --- a/lib/kernel/doc/src/gen_tcp.xml +++ b/lib/kernel/doc/src/gen_tcp.xml @@ -27,7 +27,7 @@ <date>1997-10-24</date> <rev>A</rev> </header> - <module>gen_tcp</module> + <module since="">gen_tcp</module> <modulesummary>Interface to TCP/IP sockets.</modulesummary> <description> <p>This module provides functions for communicating @@ -116,8 +116,8 @@ do_recv(Sock, Bs) -> <funcs> <func> - <name name="accept" arity="1"/> - <name name="accept" arity="2"/> + <name name="accept" arity="1" since=""/> + <name name="accept" arity="2" since=""/> <fsummary>Accept an incoming connection request on a listening socket.</fsummary> <type_desc variable="ListenSocket">Returned by <seealso marker="#listen/2"><c>listen/2</c></seealso>. @@ -163,7 +163,7 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a TCP socket.</fsummary> <desc> <p>Closes a TCP socket.</p> @@ -188,8 +188,8 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="connect" arity="3"/> - <name name="connect" arity="4"/> + <name name="connect" arity="3" since=""/> + <name name="connect" arity="4" since=""/> <fsummary>Connect to a TCP port.</fsummary> <desc> <p>Connects to a server on TCP port <c><anno>Port</anno></c> on the host @@ -268,7 +268,7 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="controlling_process" arity="2"/> + <name name="controlling_process" arity="2" since=""/> <fsummary>Change controlling process of a socket.</fsummary> <desc> <p>Assigns a new controlling process <c><anno>Pid</anno></c> to @@ -292,7 +292,7 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="listen" arity="2"/> + <name name="listen" arity="2" since=""/> <fsummary>Set up a socket to listen on a port.</fsummary> <desc> <p>Sets up a socket to listen on port <c><anno>Port</anno></c> on @@ -349,8 +349,8 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="recv" arity="2"/> - <name name="recv" arity="3"/> + <name name="recv" arity="2" since=""/> + <name name="recv" arity="3" since=""/> <fsummary>Receive a packet from a passive socket.</fsummary> <type_desc variable="HttpPacket">See the description of <c>HttpPacket</c> in @@ -375,7 +375,7 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="send" arity="2"/> + <name name="send" arity="2" since=""/> <fsummary>Send a packet.</fsummary> <desc> <p>Sends a packet on a socket.</p> @@ -386,7 +386,7 @@ do_recv(Sock, Bs) -> </func> <func> - <name name="shutdown" arity="2"/> + <name name="shutdown" arity="2" since=""/> <fsummary>Asynchronously close a socket.</fsummary> <desc> <p>Closes a socket in one or two directions.</p> diff --git a/lib/kernel/doc/src/gen_udp.xml b/lib/kernel/doc/src/gen_udp.xml index 840ca3c188..d20fc1fdfd 100644 --- a/lib/kernel/doc/src/gen_udp.xml +++ b/lib/kernel/doc/src/gen_udp.xml @@ -28,7 +28,7 @@ <date>1997-12-03</date> <rev>A</rev> </header> - <module>gen_udp</module> + <module since="">gen_udp</module> <modulesummary>Interface to UDP sockets.</modulesummary> <description> <p>This module provides functions for communicating @@ -53,7 +53,7 @@ <funcs> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a UDP socket.</fsummary> <desc> <p>Closes a UDP socket.</p> @@ -61,7 +61,7 @@ </func> <func> - <name name="controlling_process" arity="2"/> + <name name="controlling_process" arity="2" since=""/> <fsummary>Change controlling process of a socket.</fsummary> <desc> <p>Assigns a new controlling process <c><anno>Pid</anno></c> to @@ -77,8 +77,8 @@ </func> <func> - <name name="open" arity="1"/> - <name name="open" arity="2"/> + <name name="open" arity="1" since=""/> + <name name="open" arity="2" since=""/> <fsummary>Associate a UDP port number with the process calling it.</fsummary> <desc> <p>Associates a UDP port number (<c><anno>Port</anno></c>) with the @@ -189,8 +189,8 @@ </func> <func> - <name name="recv" arity="2"/> - <name name="recv" arity="3"/> + <name name="recv" arity="2" since=""/> + <name name="recv" arity="3" since=""/> <fsummary>Receive a packet from a passive socket.</fsummary> <desc> <p> @@ -213,7 +213,7 @@ </func> <func> - <name name="send" arity="4"/> + <name name="send" arity="4" since=""/> <fsummary>Send a packet.</fsummary> <desc> <p> diff --git a/lib/kernel/doc/src/global.xml b/lib/kernel/doc/src/global.xml index 4442741f54..dfe71de5ce 100644 --- a/lib/kernel/doc/src/global.xml +++ b/lib/kernel/doc/src/global.xml @@ -28,7 +28,7 @@ <date>1997-11-17</date> <rev></rev> </header> - <module>global</module> + <module since="">global</module> <modulesummary>A global name registration facility.</modulesummary> <description> <p>This module consists of the following services:</p> @@ -100,8 +100,8 @@ <funcs> <func> - <name name="del_lock" arity="1"/> - <name name="del_lock" arity="2"/> + <name name="del_lock" arity="1" since=""/> + <name name="del_lock" arity="2" since=""/> <fsummary>Delete a lock.</fsummary> <desc> <p>Deletes the lock <c><anno>Id</anno></c> synchronously.</p> @@ -109,7 +109,7 @@ </func> <func> - <name name="notify_all_name" arity="3"/> + <name name="notify_all_name" arity="3" since=""/> <fsummary>Name resolving function that notifies both pids.</fsummary> <desc> <p>Can be used as a name resolving function for @@ -123,7 +123,7 @@ </func> <func> - <name name="random_exit_name" arity="3"/> + <name name="random_exit_name" arity="3" since=""/> <fsummary>Name resolving function that kills one pid.</fsummary> <desc> <p>Can be used as a name resolving function for @@ -136,7 +136,7 @@ </func> <func> - <name name="random_notify_name" arity="3"/> + <name name="random_notify_name" arity="3" since=""/> <fsummary>Name resolving function that notifies one pid.</fsummary> <desc> <p>Can be used as a name resolving function for @@ -150,8 +150,8 @@ </func> <func> - <name name="re_register_name" arity="2"/> - <name name="re_register_name" arity="3"/> + <name name="re_register_name" arity="2" since=""/> + <name name="re_register_name" arity="3" since=""/> <fsummary>Atomically re-register a name.</fsummary> <type name="method"/> <type_desc name="method">{<c>Module</c>, <c>Function</c>} @@ -167,8 +167,8 @@ </func> <func> - <name name="register_name" arity="2"/> - <name name="register_name" arity="3"/> + <name name="register_name" arity="2" since=""/> + <name name="register_name" arity="3" since=""/> <fsummary>Globally register a name for a pid.</fsummary> <type name="method"/> <type_desc name="method">{<c>Module</c>, <c>Function</c>} is also @@ -221,7 +221,7 @@ </func> <func> - <name name="registered_names" arity="0"/> + <name name="registered_names" arity="0" since=""/> <fsummary>All globally registered names.</fsummary> <desc> <p>Returns a list of all globally registered names.</p> @@ -229,7 +229,7 @@ </func> <func> - <name name="send" arity="2"/> + <name name="send" arity="2" since=""/> <fsummary>Send a message to a globally registered pid.</fsummary> <desc> <p>Sends message <c><anno>Msg</anno></c> to the pid globally registered @@ -241,9 +241,9 @@ </func> <func> - <name name="set_lock" arity="1"/> - <name name="set_lock" arity="2"/> - <name name="set_lock" arity="3"/> + <name name="set_lock" arity="1" since=""/> + <name name="set_lock" arity="2" since=""/> + <name name="set_lock" arity="3" since=""/> <fsummary>Set a lock on the specified nodes.</fsummary> <type name="id"/> <type name="retries"/> @@ -287,7 +287,7 @@ </func> <func> - <name name="sync" arity="0"/> + <name name="sync" arity="0" since=""/> <fsummary>Synchronize the global name server.</fsummary> <desc> <p>Synchronizes the global name server with all nodes known to @@ -302,9 +302,9 @@ </func> <func> - <name name="trans" arity="2"/> - <name name="trans" arity="3"/> - <name name="trans" arity="4"/> + <name name="trans" arity="2" since=""/> + <name name="trans" arity="3" since=""/> + <name name="trans" arity="4" since=""/> <fsummary>Micro transaction facility.</fsummary> <type name="retries"/> <type name="trans_fun"/> @@ -322,7 +322,7 @@ </func> <func> - <name name="unregister_name" arity="1"/> + <name name="unregister_name" arity="1" since=""/> <fsummary>Remove a globally registered name for a pid.</fsummary> <desc> <p>Removes the globally registered name <c><anno>Name</anno></c> from @@ -331,7 +331,7 @@ </func> <func> - <name name="whereis_name" arity="1"/> + <name name="whereis_name" arity="1" since=""/> <fsummary>Get the pid with a specified globally registered name.</fsummary> <desc> <p>Returns the pid with the globally registered name diff --git a/lib/kernel/doc/src/global_group.xml b/lib/kernel/doc/src/global_group.xml index 8f947b9adf..74d15cd476 100644 --- a/lib/kernel/doc/src/global_group.xml +++ b/lib/kernel/doc/src/global_group.xml @@ -28,7 +28,7 @@ <date>1998-12-18</date> <rev>B</rev> </header> - <module>global_group</module> + <module since="">global_group</module> <modulesummary>Grouping nodes to global name registration groups.</modulesummary> <description> <p>This module makes it possible to partition the nodes of a @@ -105,7 +105,7 @@ <funcs> <func> - <name name="global_groups" arity="0"/> + <name name="global_groups" arity="0" since=""/> <fsummary>Return the global group names.</fsummary> <desc> <p>Returns a tuple containing the name of the global group that @@ -116,7 +116,7 @@ </func> <func> - <name name="info" arity="0"/> + <name name="info" arity="0" since=""/> <fsummary>Information about global groups.</fsummary> <type name="info_item"/> <type name="sync_state"/> @@ -173,7 +173,7 @@ </func> <func> - <name name="monitor_nodes" arity="1"/> + <name name="monitor_nodes" arity="1" since=""/> <fsummary>Subscribe to node status changes.</fsummary> <desc> <p>Depending on <c><anno>Flag</anno></c>, the calling process @@ -187,7 +187,7 @@ </func> <func> - <name name="own_nodes" arity="0"/> + <name name="own_nodes" arity="0" since=""/> <fsummary>Return the group nodes.</fsummary> <desc> <p>Returns the names of all group nodes, regardless of their @@ -196,7 +196,7 @@ </func> <func> - <name name="registered_names" arity="1"/> + <name name="registered_names" arity="1" since=""/> <fsummary>Return globally registered names.</fsummary> <desc> <p>Returns a list of all names that are globally registered @@ -205,8 +205,8 @@ </func> <func> - <name name="send" arity="2"/> - <name name="send" arity="3"/> + <name name="send" arity="2" since=""/> + <name name="send" arity="3" since=""/> <fsummary>Send a message to a globally registered pid.</fsummary> <desc> <p>Searches for <c><anno>Name</anno></c>, globally registered on @@ -224,7 +224,7 @@ </func> <func> - <name name="sync" arity="0"/> + <name name="sync" arity="0" since=""/> <fsummary>Synchronize the group nodes.</fsummary> <desc> <p>Synchronizes the group nodes, that is, the global name @@ -242,8 +242,8 @@ </func> <func> - <name name="whereis_name" arity="1"/> - <name name="whereis_name" arity="2"/> + <name name="whereis_name" arity="1" since=""/> + <name name="whereis_name" arity="2" since=""/> <fsummary>Get the pid with a specified globally registered name.</fsummary> <desc> <p>Searches for <c><anno>Name</anno></c>, globally registered on diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml index ad1a2ffeb9..4243b1ffe8 100644 --- a/lib/kernel/doc/src/heart.xml +++ b/lib/kernel/doc/src/heart.xml @@ -28,7 +28,7 @@ <date>1998-01-28</date> <rev>A</rev> </header> - <module>heart</module> + <module since="">heart</module> <modulesummary>Heartbeat monitoring of an Erlang runtime system.</modulesummary> <description> <p>This modules contains the interface to the <c>heart</c> process. @@ -119,7 +119,7 @@ <funcs> <func> - <name name="set_cmd" arity="1"/> + <name name="set_cmd" arity="1" since=""/> <fsummary>Set a temporary reboot command.</fsummary> <desc> <p>Sets a temporary reboot command. This command is used if @@ -136,7 +136,7 @@ </func> <func> - <name name="clear_cmd" arity="0"/> + <name name="clear_cmd" arity="0" since=""/> <fsummary>Clear the temporary boot command.</fsummary> <desc> <p>Clears the temporary boot command. If the system terminates, @@ -145,7 +145,7 @@ </func> <func> - <name name="get_cmd" arity="0"/> + <name name="get_cmd" arity="0" since=""/> <fsummary>Get the temporary reboot command.</fsummary> <desc> <p>Gets the temporary reboot command. If the command is cleared, @@ -154,7 +154,7 @@ </func> <func> - <name name="set_callback" arity="2"/> + <name name="set_callback" arity="2" since="OTP 18.3"/> <fsummary>Set a validation callback</fsummary> <desc> <p> This validation callback will be executed before any @@ -166,14 +166,14 @@ </desc> </func> <func> - <name name="clear_callback" arity="0"/> + <name name="clear_callback" arity="0" since="OTP 18.3"/> <fsummary>Clear the validation callback</fsummary> <desc> <p>Removes the validation callback call before heartbeats.</p> </desc> </func> <func> - <name name="get_callback" arity="0"/> + <name name="get_callback" arity="0" since="OTP 18.3"/> <fsummary>Get the validation callback</fsummary> <desc> <p>Get the validation callback. If the callback is cleared, <c>none</c> will be returned.</p> @@ -181,7 +181,7 @@ </func> <func> - <name name="set_options" arity="1"/> + <name name="set_options" arity="1" since="OTP 18.3"/> <fsummary>Set a list of options</fsummary> <desc> <p> Valid options <c>set_options</c> are: </p> @@ -199,7 +199,7 @@ </desc> </func> <func> - <name name="get_options" arity="0"/> + <name name="get_options" arity="0" since="OTP 18.3"/> <fsummary>Get the temporary reboot command</fsummary> <desc> <p>Returns <c>{ok, Options}</c> where <c>Options</c> is a list of current options enabled for heart. diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index 87b08e4e36..709ba8e8fd 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -28,7 +28,7 @@ <date>1998-02-04</date> <rev>A</rev> </header> - <module>inet</module> + <module since="">inet</module> <modulesummary>Access to TCP/IP protocols.</modulesummary> <description> <p>This module provides access to TCP/IP protocols.</p> @@ -298,7 +298,7 @@ fe80::204:acff:fe17:bf38 <funcs> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a socket of any type.</fsummary> <desc> <p>Closes a socket of any type.</p> @@ -306,7 +306,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="format_error" arity="1"/> + <name name="format_error" arity="1" since=""/> <fsummary>Return a descriptive string for an error reason.</fsummary> <desc> <p>Returns a diagnostic error string. For possible POSIX values and @@ -316,7 +316,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="get_rc" arity="0"/> + <name name="get_rc" arity="0" since=""/> <fsummary>Return a list of IP configuration parameters.</fsummary> <desc> <p> @@ -335,7 +335,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="getaddr" arity="2"/> + <name name="getaddr" arity="2" since=""/> <fsummary>Return the IP address for a host.</fsummary> <desc> <p>Returns the IP address for <c><anno>Host</anno></c> as a tuple of @@ -345,7 +345,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="getaddrs" arity="2"/> + <name name="getaddrs" arity="2" since=""/> <fsummary>Return the IP addresses for a host.</fsummary> <desc> <p>Returns a list of all IP addresses for <c><anno>Host</anno></c>. @@ -355,7 +355,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="gethostbyaddr" arity="1"/> + <name name="gethostbyaddr" arity="1" since=""/> <fsummary>Return a hostent record for the host with the specified address.</fsummary> <desc> @@ -364,7 +364,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="gethostbyname" arity="1"/> + <name name="gethostbyname" arity="1" since=""/> <fsummary>Return a hostent record for the host with the specified name. </fsummary> <desc> @@ -376,7 +376,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="gethostbyname" arity="2"/> + <name name="gethostbyname" arity="2" since=""/> <fsummary>Return a hostent record for the host with the specified name. </fsummary> <desc> @@ -386,7 +386,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="gethostname" arity="0"/> + <name name="gethostname" arity="0" since=""/> <fsummary>Return the local hostname.</fsummary> <desc> <p>Returns the local hostname. Never fails.</p> @@ -394,7 +394,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="getifaddrs" arity="0"/> + <name name="getifaddrs" arity="0" since="OTP R14B01"/> <fsummary>Return a list of interfaces and their addresses.</fsummary> <desc> <p> @@ -416,7 +416,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name>getifaddrs(Opts) -> + <name since="OTP 21.2">getifaddrs(Opts) -> {ok, [{Ifname, Ifopts}]} | {error, Posix} </name> <fsummary>Return a list of interfaces and their addresses.</fsummary> @@ -459,7 +459,7 @@ fe80::204:acff:fe17:bf38 </func> <func> - <name name="getopts" arity="2"/> + <name name="getopts" arity="2" since=""/> <fsummary>Get one or more options for a socket.</fsummary> <desc> <p>Gets one or more options for a socket. For a list of available @@ -529,8 +529,8 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="getstat" arity="1"/> - <name name="getstat" arity="2"/> + <name name="getstat" arity="1" since=""/> + <name name="getstat" arity="2" since=""/> <fsummary>Get one or more statistic options for a socket.</fsummary> <type name="stat_option"/> <desc> @@ -586,9 +586,9 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="i" arity="0" /> - <name name="i" arity="1" /> - <name name="i" arity="2" /> + <name name="i" arity="0" since="OTP 21.0"/> + <name name="i" arity="1" since="OTP 21.0"/> + <name name="i" arity="2" since="OTP 21.0"/> <fsummary>Displays information and statistics about sockets on the terminal</fsummary> <desc> <p> @@ -641,7 +641,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="ntoa" arity="1" /> + <name name="ntoa" arity="1" since="OTP R16B02"/> <fsummary>Convert IPv6/IPV4 address to ASCII.</fsummary> <desc> <p>Parses an @@ -651,7 +651,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="parse_address" arity="1" /> + <name name="parse_address" arity="1" since="OTP R16B"/> <fsummary>Parse an IPv4 or IPv6 address.</fsummary> <desc> <p>Parses an IPv4 or IPv6 address string and returns an @@ -662,7 +662,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="parse_ipv4_address" arity="1" /> + <name name="parse_ipv4_address" arity="1" since="OTP R16B"/> <fsummary>Parse an IPv4 address.</fsummary> <desc> <p>Parses an IPv4 address string and returns an @@ -672,7 +672,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="parse_ipv4strict_address" arity="1" /> + <name name="parse_ipv4strict_address" arity="1" since="OTP R16B"/> <fsummary>Parse an IPv4 address strict.</fsummary> <desc> <p>Parses an IPv4 address string containing four fields, that is, @@ -683,7 +683,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="parse_ipv6_address" arity="1" /> + <name name="parse_ipv6_address" arity="1" since="OTP R16B"/> <fsummary>Parse an IPv6 address.</fsummary> <desc> <p>Parses an IPv6 address string and returns an @@ -694,7 +694,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="parse_ipv6strict_address" arity="1" /> + <name name="parse_ipv6strict_address" arity="1" since="OTP R16B"/> <fsummary>Parse an IPv6 address strict.</fsummary> <desc> <p>Parses an IPv6 address string and returns an @@ -704,7 +704,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="ipv4_mapped_ipv6_address" arity="1" /> + <name name="ipv4_mapped_ipv6_address" arity="1" since="OTP 21.0"/> <fsummary>Convert to and from IPv4-mapped IPv6 address.</fsummary> <desc> <p> @@ -717,7 +717,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="parse_strict_address" arity="1" /> + <name name="parse_strict_address" arity="1" since="OTP R16B"/> <fsummary>Parse an IPv4 or IPv6 address strict.</fsummary> <desc> <p>Parses an IPv4 or IPv6 address string and returns an @@ -728,7 +728,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="peername" arity="1"/> + <name name="peername" arity="1" since=""/> <fsummary>Return the address and port for the other end of a connection. </fsummary> <desc> @@ -741,7 +741,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="peernames" arity="1"/> + <name name="peernames" arity="1" since="OTP R16B03"/> <fsummary>Return all address/port numbers for the other end of a connection.</fsummary> <desc> @@ -755,7 +755,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="peernames" arity="2"/> + <name name="peernames" arity="2" since="OTP R16B03"/> <fsummary>Return all address/port numbers for the other end of a connection.</fsummary> <desc> @@ -774,7 +774,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="port" arity="1"/> + <name name="port" arity="1" since=""/> <fsummary>Return the local port number for a socket.</fsummary> <desc> <p>Returns the local port number for a socket.</p> @@ -782,7 +782,7 @@ get_tcpi_sacked(Sock) -> </func> <func> - <name name="setopts" arity="2"/> + <name name="setopts" arity="2" since=""/> <fsummary>Set one or more options for a socket.</fsummary> <desc> <p>Sets one or more options for a socket.</p> @@ -1007,13 +1007,34 @@ get_tcpi_sacked(Sock) -> <marker id="option-linger"></marker> </item> <tag><c>{linger, {true|false, Seconds}}</c></tag> - <item> + <item> <p>Determines the time-out, in seconds, for flushing unsent data - in the <c>close/1</c> socket call. If the first component of - the value tuple is <c>false</c>, the second is ignored. This - means that <c>close/1</c> returns immediately, not waiting - for data to be flushed. Otherwise, the second component is - the flushing time-out, in seconds.</p> + in the <c>close/1</c> socket call. </p> + <p>The first component is if linger is enabled, the second component + is the flushing time-out, in seconds. There are 3 alternatives:</p> + <taglist> + <tag><c>{false, _}</c></tag> + <item> + <p>close/1 or shutdown/2 returns immediately, + not waiting for data to be flushed, with closing + happening in the background.</p> + </item> + <tag><c>{true, 0}</c></tag> + <item> + <p>Aborts the connection when it is closed. + Discards any data still remaining in the send buffers + and sends RST to the peer.</p> + <p>This avoids TCP's TIME_WAIT state, but leaves open + the possibility that another "incarnation" of this connection + being created.</p> + </item> + <tag><c>{true, Time} when Time > 0</c></tag> + <item> + <p>close/1 or shutdown/2 will not return until + all queued messages for the socket have been successfully + sent or the linger timeout (Time) has been reached.</p> + </item> + </taglist> </item> <tag><c>{low_msgq_watermark, Size}</c></tag> <item> @@ -1486,7 +1507,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code> </func> <func> - <name name="sockname" arity="1"/> + <name name="sockname" arity="1" since=""/> <fsummary>Return the local address and port number for a socket. </fsummary> <desc> @@ -1499,7 +1520,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code> </func> <func> - <name name="socknames" arity="1"/> + <name name="socknames" arity="1" since="OTP R16B03"/> <fsummary>Return all local address/port numbers for a socket.</fsummary> <desc> <p>Equivalent to @@ -1509,7 +1530,7 @@ inet:setopts(Sock,[{raw,6,8,<<30:32/native>>}]),]]></code> </func> <func> - <name name="socknames" arity="2"/> + <name name="socknames" arity="2" since="OTP R16B03"/> <fsummary>Return all local address/port numbers for a socket.</fsummary> <desc> <p>Returns a list of all local address/port number pairs for a socket diff --git a/lib/kernel/doc/src/inet_res.xml b/lib/kernel/doc/src/inet_res.xml index 351d86a93a..1904e371f7 100644 --- a/lib/kernel/doc/src/inet_res.xml +++ b/lib/kernel/doc/src/inet_res.xml @@ -28,7 +28,7 @@ <date>2009-09-11</date> <rev>A</rev> </header> - <module>inet_res</module> + <module since="">inet_res</module> <modulesummary>A rudimentary DNS client.</modulesummary> <description> <p>This module performs DNS name resolving to recursive name servers.</p> @@ -185,8 +185,8 @@ inet_dns:record_type(_) -> undefined.</pre> <funcs> <func> - <name name="getbyname" arity="2"/> - <name name="getbyname" arity="3"/> + <name name="getbyname" arity="2" since=""/> + <name name="getbyname" arity="3" since=""/> <fsummary>Resolve a DNS record of the specified type for the specified host.</fsummary> <desc> @@ -205,8 +205,8 @@ inet_dns:record_type(_) -> undefined.</pre> </func> <func> - <name name="gethostbyaddr" arity="1"/> - <name name="gethostbyaddr" arity="2"/> + <name name="gethostbyaddr" arity="1" since=""/> + <name name="gethostbyaddr" arity="2" since=""/> <fsummary>Return a hostent record for the host with the specified address.</fsummary> <desc> @@ -217,9 +217,9 @@ inet_dns:record_type(_) -> undefined.</pre> </func> <func> - <name name="gethostbyname" arity="1"/> - <name name="gethostbyname" arity="2"/> - <name name="gethostbyname" arity="3"/> + <name name="gethostbyname" arity="1" since=""/> + <name name="gethostbyname" arity="2" since=""/> + <name name="gethostbyname" arity="3" since=""/> <fsummary>Return a hostent record for the host with the specified name. </fsummary> <desc> @@ -235,9 +235,9 @@ inet_dns:record_type(_) -> undefined.</pre> </func> <func> - <name name="lookup" arity="3"/> - <name name="lookup" arity="4"/> - <name name="lookup" arity="5"/> + <name name="lookup" arity="3" since=""/> + <name name="lookup" arity="4" since=""/> + <name name="lookup" arity="5" since=""/> <fsummary>Resolve the DNS data for the record of the specified type and class for the specified name.</fsummary> <desc> @@ -257,9 +257,9 @@ inet_dns:record_type(_) -> undefined.</pre> </func> <func> - <name name="resolve" arity="3"/> - <name name="resolve" arity="4"/> - <name name="resolve" arity="5"/> + <name name="resolve" arity="3" since=""/> + <name name="resolve" arity="4" since=""/> + <name name="resolve" arity="5" since=""/> <fsummary>Resolve a DNS record of the specified type and class for the specified name.</fsummary> <desc> @@ -326,9 +326,9 @@ example_lookup(Name, Class, Type) -> <funcs> <func> - <name name="nslookup" arity="3"/> - <name name="nslookup" arity="4" clause_i="1"/> - <name name="nslookup" arity="4" clause_i="2"/> + <name name="nslookup" arity="3" since=""/> + <name name="nslookup" arity="4" clause_i="1" since=""/> + <name name="nslookup" arity="4" clause_i="2" since=""/> <fsummary>Resolve a DNS record of the specified type and class for the specified name.</fsummary> <type variable="Name"/> @@ -344,8 +344,8 @@ example_lookup(Name, Class, Type) -> </func> <func> - <name name="nnslookup" arity="4"/> - <name name="nnslookup" arity="5"/> + <name name="nnslookup" arity="4" since=""/> + <name name="nnslookup" arity="5" since=""/> <fsummary>Resolve a DNS record of the specified type and class for the specified name.</fsummary> <desc> diff --git a/lib/kernel/doc/src/logger.xml b/lib/kernel/doc/src/logger.xml index e0b95fa4ad..e09c5db5e3 100644 --- a/lib/kernel/doc/src/logger.xml +++ b/lib/kernel/doc/src/logger.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>logger.xml</file> </header> - <module>logger</module> + <module since="OTP 21.0">logger</module> <modulesummary>API module for Logger, the standard logging facility in Erlang/OTP.</modulesummary> @@ -334,9 +334,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </section> <funcs> <func> - <name>emergency(StringOrReport[,Metadata])</name> - <name>emergency(Format,Args[,Metadata])</name> - <name>emergency(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">emergency(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">emergency(Format,Args[,Metadata])</name> + <name since="OTP 21.0">emergency(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>emergency</c>.</fsummary> <desc> <p>Equivalent to @@ -345,9 +345,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>alert(StringOrReport[,Metadata])</name> - <name>alert(Format,Args[,Metadata])</name> - <name>alert(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">alert(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">alert(Format,Args[,Metadata])</name> + <name since="OTP 21.0">alert(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>alert</c>.</fsummary> <desc> <p>Equivalent to @@ -356,9 +356,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>critical(StringOrReport[,Metadata])</name> - <name>critical(Format,Args[,Metadata])</name> - <name>critical(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">critical(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">critical(Format,Args[,Metadata])</name> + <name since="OTP 21.0">critical(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>critical</c>.</fsummary> <desc> <p>Equivalent to @@ -367,9 +367,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>error(StringOrReport[,Metadata])</name> - <name>error(Format,Args[,Metadata])</name> - <name>error(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">error(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">error(Format,Args[,Metadata])</name> + <name since="OTP 21.0">error(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>error</c>.</fsummary> <desc> <p>Equivalent to @@ -378,9 +378,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>warning(StringOrReport[,Metadata])</name> - <name>warning(Format,Args[,Metadata])</name> - <name>warning(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">warning(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">warning(Format,Args[,Metadata])</name> + <name since="OTP 21.0">warning(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>warning</c>.</fsummary> <desc> <p>Equivalent to @@ -389,9 +389,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>notice(StringOrReport[,Metadata])</name> - <name>notice(Format,Args[,Metadata])</name> - <name>notice(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">notice(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">notice(Format,Args[,Metadata])</name> + <name since="OTP 21.0">notice(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>notice</c>.</fsummary> <desc> <p>Equivalent to @@ -400,9 +400,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>info(StringOrReport[,Metadata])</name> - <name>info(Format,Args[,Metadata])</name> - <name>info(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">info(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">info(Format,Args[,Metadata])</name> + <name since="OTP 21.0">info(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>info</c>.</fsummary> <desc> <p>Equivalent to @@ -411,9 +411,9 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name>debug(StringOrReport[,Metadata])</name> - <name>debug(Format,Args[,Metadata])</name> - <name>debug(Fun,FunArgs[,Metadata])</name> + <name since="OTP 21.0">debug(StringOrReport[,Metadata])</name> + <name since="OTP 21.0">debug(Format,Args[,Metadata])</name> + <name since="OTP 21.0">debug(Fun,FunArgs[,Metadata])</name> <fsummary>Logs the given message as level <c>debug</c>.</fsummary> <desc> <p>Equivalent to @@ -422,12 +422,12 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name name="log" arity="2"/> - <name name="log" arity="3" clause_i="1"/> - <name name="log" arity="3" clause_i="2"/> - <name name="log" arity="3" clause_i="3"/> - <name name="log" arity="4" clause_i="1"/> - <name name="log" arity="4" clause_i="2"/> + <name name="log" arity="2" since="OTP 21.0"/> + <name name="log" arity="3" clause_i="1" since="OTP 21.0"/> + <name name="log" arity="3" clause_i="2" since="OTP 21.0"/> + <name name="log" arity="3" clause_i="3" since="OTP 21.0"/> + <name name="log" arity="4" clause_i="1" since="OTP 21.0"/> + <name name="log" arity="4" clause_i="2" since="OTP 21.0"/> <fsummary>Logs the given message.</fsummary> <type variable="Level"/> <type variable="StringOrReport" name_i="1"/> @@ -448,7 +448,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </section> <funcs> <func> - <name name="add_handler" arity="3"/> + <name name="add_handler" arity="3" since="OTP 21.0"/> <fsummary>Add a handler with the given configuration.</fsummary> <desc> <p>Add a handler with the given configuration.</p> @@ -459,7 +459,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name name="add_handler_filter" arity="3"/> + <name name="add_handler_filter" arity="3" since="OTP 21.0"/> <fsummary>Add a filter to the specified handler.</fsummary> <desc> <p>Add a filter to the specified handler.</p> @@ -500,7 +500,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name name="add_handlers" arity="1" clause_i="1"/> + <name name="add_handlers" arity="1" clause_i="1" since="OTP 21.0"/> <fsummary>Set up log handlers from the application's configuration parameters.</fsummary> <desc> @@ -510,7 +510,7 @@ logger:error("error happened because: ~p", [Reason]). % Without macro </func> <func> - <name name="add_handlers" arity="1" clause_i="2"/> + <name name="add_handlers" arity="1" clause_i="2" since="OTP 21.0"/> <fsummary>Setup logger handlers.</fsummary> <type name="config_handler"/> <desc> @@ -553,7 +553,7 @@ start(_, []) -> </func> <func> - <name name="add_primary_filter" arity="2"/> + <name name="add_primary_filter" arity="2" since="OTP 21.0"/> <fsummary>Add a primary filter to Logger.</fsummary> <desc> <p>Add a primary filter to Logger.</p> @@ -594,7 +594,7 @@ start(_, []) -> </func> <func> - <name name="get_config" arity="0"/> + <name name="get_config" arity="0" since="OTP 21.0"/> <fsummary>Look up the current Logger configuration</fsummary> <desc> <p>Look up all current Logger configuration, including primary @@ -603,7 +603,7 @@ start(_, []) -> </func> <func> - <name name="get_handler_config" arity="0"/> + <name name="get_handler_config" arity="0" since="OTP 21.0"/> <fsummary>Look up the current configuration for all handlers.</fsummary> <desc> <p>Look up the current configuration for all handlers.</p> @@ -611,7 +611,7 @@ start(_, []) -> </func> <func> - <name name="get_handler_config" arity="1"/> + <name name="get_handler_config" arity="1" since="OTP 21.0"/> <fsummary>Look up the current configuration for the given handler.</fsummary> <desc> @@ -620,7 +620,7 @@ start(_, []) -> </func> <func> - <name name="get_handler_ids" arity="0"/> + <name name="get_handler_ids" arity="0" since="OTP 21.0"/> <fsummary>Look up the identities for all installed handlers.</fsummary> <desc> <p>Look up the identities for all installed handlers.</p> @@ -628,7 +628,7 @@ start(_, []) -> </func> <func> - <name name="get_primary_config" arity="0"/> + <name name="get_primary_config" arity="0" since="OTP 21.0"/> <fsummary>Look up the current primary configuration for Logger.</fsummary> <desc> <p>Look up the current primary configuration for Logger.</p> @@ -636,7 +636,7 @@ start(_, []) -> </func> <func> - <name name="get_module_level" arity="0"/> + <name name="get_module_level" arity="0" since="OTP 21.0"/> <fsummary>Look up all current module levels.</fsummary> <desc> <p>Look up all current module levels. Returns a list @@ -648,7 +648,7 @@ start(_, []) -> </func> <func> - <name name="get_module_level" arity="1"/> + <name name="get_module_level" arity="1" since="OTP 21.0"/> <fsummary>Look up the current level for the given modules.</fsummary> <desc> <p>Look up the current level for the given modules. Returns a @@ -660,7 +660,7 @@ start(_, []) -> </func> <func> - <name name="get_process_metadata" arity="0"/> + <name name="get_process_metadata" arity="0" since="OTP 21.0"/> <fsummary>Retrieve data set with set_process_metadata/1.</fsummary> <desc> <p>Retrieve data set @@ -672,7 +672,7 @@ start(_, []) -> </func> <func> - <name name="remove_handler" arity="1"/> + <name name="remove_handler" arity="1" since="OTP 21.0"/> <fsummary>Remove the handler with the specified identity.</fsummary> <desc> <p>Remove the handler identified by <c><anno>HandlerId</anno></c>.</p> @@ -680,7 +680,7 @@ start(_, []) -> </func> <func> - <name name="remove_handler_filter" arity="2"/> + <name name="remove_handler_filter" arity="2" since="OTP 21.0"/> <fsummary>Remove a filter from the specified handler.</fsummary> <desc> <p>Remove the filter identified @@ -690,7 +690,7 @@ start(_, []) -> </func> <func> - <name name="remove_primary_filter" arity="1"/> + <name name="remove_primary_filter" arity="1" since="OTP 21.0"/> <fsummary>Remove a primary filter from Logger.</fsummary> <desc> <p>Remove the primary filter identified @@ -699,7 +699,7 @@ start(_, []) -> </func> <func> - <name name="set_application_level" arity="2"/> + <name name="set_application_level" arity="2" since="OTP 21.1"/> <fsummary>Set the log level for all modules in the specified application.</fsummary> <desc> <p>Set the log level for all the modules of the specified application.</p> @@ -710,7 +710,7 @@ start(_, []) -> </func> <func> - <name name="set_handler_config" arity="2"/> + <name name="set_handler_config" arity="2" since="OTP 21.0"/> <fsummary>Set configuration data for the specified handler.</fsummary> <desc> <p>Set configuration data for the specified handler. This @@ -731,11 +731,11 @@ start(_, []) -> </func> <func> - <name name="set_handler_config" arity="3" clause_i="1"/> - <name name="set_handler_config" arity="3" clause_i="2"/> - <name name="set_handler_config" arity="3" clause_i="3"/> - <name name="set_handler_config" arity="3" clause_i="4"/> - <name name="set_handler_config" arity="3" clause_i="5"/> + <name name="set_handler_config" arity="3" clause_i="1" since="OTP 21.0"/> + <name name="set_handler_config" arity="3" clause_i="2" since="OTP 21.0"/> + <name name="set_handler_config" arity="3" clause_i="3" since="OTP 21.0"/> + <name name="set_handler_config" arity="3" clause_i="4" since="OTP 21.0"/> + <name name="set_handler_config" arity="3" clause_i="5" since="OTP 21.0"/> <fsummary>Add or update configuration data for the specified handler.</fsummary> <type variable="HandlerId"/> @@ -767,7 +767,7 @@ start(_, []) -> </func> <func> - <name name="set_primary_config" arity="1"/> + <name name="set_primary_config" arity="1" since="OTP 21.0"/> <fsummary>Set primary configuration data for Logger.</fsummary> <desc> <p>Set primary configuration data for Logger. This @@ -785,9 +785,9 @@ start(_, []) -> </func> <func> - <name name="set_primary_config" arity="2" clause_i="1"/> - <name name="set_primary_config" arity="2" clause_i="2"/> - <name name="set_primary_config" arity="2" clause_i="3"/> + <name name="set_primary_config" arity="2" clause_i="1" since="OTP 21.0"/> + <name name="set_primary_config" arity="2" clause_i="2" since="OTP 21.0"/> + <name name="set_primary_config" arity="2" clause_i="3" since="OTP 21.0"/> <fsummary>Add or update primary configuration data for Logger.</fsummary> <type variable="Level" name_i="1"/> <type variable="FilterDefault" name_i="2"/> @@ -801,7 +801,7 @@ start(_, []) -> </func> <func> - <name name="set_module_level" arity="2"/> + <name name="set_module_level" arity="2" since="OTP 21.0"/> <fsummary>Set the log level for the specified modules.</fsummary> <desc> <p>Set the log level for the specified modules.</p> @@ -841,7 +841,7 @@ start(_, []) -> </func> <func> - <name name="set_process_metadata" arity="1"/> + <name name="set_process_metadata" arity="1" since="OTP 21.0"/> <fsummary>Set metadata to use when logging from current process.</fsummary> <desc> <p>Set metadata which Logger shall automatically insert in @@ -860,7 +860,7 @@ start(_, []) -> </func> <func> - <name name="unset_application_level" arity="1"/> + <name name="unset_application_level" arity="1" since="OTP 21.1"/> <fsummary>Unset the log level for all modules in the specified application.</fsummary> <desc> <p>Unset the log level for all the modules of the specified application.</p> @@ -871,7 +871,7 @@ start(_, []) -> </func> <func> - <name name="unset_module_level" arity="0"/> + <name name="unset_module_level" arity="0" since="OTP 21.0"/> <fsummary>Remove module specific log settings for all modules.</fsummary> <desc> <p>Remove module specific log settings. After this, the @@ -880,7 +880,7 @@ start(_, []) -> </func> <func> - <name name="unset_module_level" arity="1"/> + <name name="unset_module_level" arity="1" since="OTP 21.0"/> <fsummary>Remove module specific log settings for the given modules.</fsummary> <desc> @@ -890,7 +890,7 @@ start(_, []) -> </func> <func> - <name name="unset_process_metadata" arity="0"/> + <name name="unset_process_metadata" arity="0" since="OTP 21.0"/> <fsummary>Delete data set with set_process_metadata/1.</fsummary> <desc> <p>Delete data set @@ -902,7 +902,7 @@ start(_, []) -> </func> <func> - <name name="update_formatter_config" arity="2"/> + <name name="update_formatter_config" arity="2" since="OTP 21.0"/> <fsummary>Update the formatter configuration for the specified handler.</fsummary> <desc> <p>Update the formatter configuration for the specified handler.</p> @@ -917,7 +917,7 @@ start(_, []) -> </func> <func> - <name name="update_formatter_config" arity="3"/> + <name name="update_formatter_config" arity="3" since="OTP 21.0"/> <fsummary>Update the formatter configuration for the specified handler.</fsummary> <desc> <p>Update the formatter configuration for the specified handler.</p> @@ -928,7 +928,7 @@ start(_, []) -> </func> <func> - <name name="update_handler_config" arity="2"/> + <name name="update_handler_config" arity="2" since="OTP 21.0"/> <fsummary>Update configuration data for the specified handler.</fsummary> <desc> <p>Update configuration data for the specified handler. This function @@ -944,11 +944,11 @@ logger:set_handler_config(HandlerId, maps:merge(Old, Config)). </func> <func> - <name name="update_handler_config" arity="3" clause_i="1"/> - <name name="update_handler_config" arity="3" clause_i="2"/> - <name name="update_handler_config" arity="3" clause_i="3"/> - <name name="update_handler_config" arity="3" clause_i="4"/> - <name name="update_handler_config" arity="3" clause_i="5"/> + <name name="update_handler_config" arity="3" clause_i="1" since="OTP 21.2"/> + <name name="update_handler_config" arity="3" clause_i="2" since="OTP 21.2"/> + <name name="update_handler_config" arity="3" clause_i="3" since="OTP 21.2"/> + <name name="update_handler_config" arity="3" clause_i="4" since="OTP 21.2"/> + <name name="update_handler_config" arity="3" clause_i="5" since="OTP 21.2"/> <fsummary>Add or update configuration data for the specified handler.</fsummary> <type variable="HandlerId"/> @@ -980,7 +980,7 @@ logger:set_handler_config(HandlerId, maps:merge(Old, Config)). </func> <func> - <name name="update_primary_config" arity="1"/> + <name name="update_primary_config" arity="1" since="OTP 21.0"/> <fsummary>Update primary configuration data for Logger.</fsummary> <desc> <p>Update primary configuration data for Logger. This function @@ -996,7 +996,7 @@ logger:set_primary_config(maps:merge(Old, Config)). </func> <func> - <name name="update_process_metadata" arity="1"/> + <name name="update_process_metadata" arity="1" since="OTP 21.0"/> <fsummary>Set or update metadata to use when logging from current process.</fsummary> <desc> @@ -1021,7 +1021,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </section> <funcs> <func> - <name name="compare_levels" arity="2"/> + <name name="compare_levels" arity="2" since="OTP 21.0"/> <fsummary>Compare the severity of two log levels.</fsummary> <desc> <p>Compare the severity of two log levels. Returns <c>gt</c> @@ -1032,7 +1032,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </func> <func> - <name name="format_report" arity="1"/> + <name name="format_report" arity="1" since="OTP 21.0"/> <fsummary>Convert a log message on report form to {Format, Args}.</fsummary> <desc> <p>Convert a log message on report form to <c>{Format, @@ -1062,7 +1062,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). <funcs> <func> - <name>HModule:adding_handler(Config1) -> {ok, Config2} | {error, + <name since="OTP 21.0">HModule:adding_handler(Config1) -> {ok, Config2} | {error, Reason}</name> <fsummary>An instance of this handler is about to be added.</fsummary> <type> @@ -1088,7 +1088,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </func> <func> - <name>HModule:changing_config(SetOrUpdate, OldConfig, NewConfig) -> {ok, Config} | {error, Reason}</name> + <name since="OTP 21.2">HModule:changing_config(SetOrUpdate, OldConfig, NewConfig) -> {ok, Config} | {error, Reason}</name> <fsummary>The configuration for this handler is about to change.</fsummary> <type> <v>SetOrUpdate = set | update</v> @@ -1126,7 +1126,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </func> <func> - <name>HModule:filter_config(Config) -> FilteredConfig</name> + <name since="OTP 21.2">HModule:filter_config(Config) -> FilteredConfig</name> <fsummary>Remove internal data from configuration.</fsummary> <type> <v>Config = FilteredConfig = @@ -1146,7 +1146,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </func> <func> - <name>HModule:log(LogEvent, Config) -> void()</name> + <name since="OTP 21.0">HModule:log(LogEvent, Config) -> void()</name> <fsummary>Log the given log event.</fsummary> <type> <v>LogEvent = @@ -1169,7 +1169,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </func> <func> - <name>HModule:removing_handler(Config) -> ok</name> + <name since="OTP 21.0">HModule:removing_handler(Config) -> ok</name> <fsummary>The given handler is about to be removed.</fsummary> <type> <v>Config = @@ -1197,7 +1197,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). <funcs> <func> - <name>FModule:check_config(FConfig) -> ok | {error, Reason}</name> + <name since="OTP 21.0">FModule:check_config(FConfig) -> ok | {error, Reason}</name> <fsummary>Validate the given formatter configuration.</fsummary> <type> <v>FConfig = @@ -1217,7 +1217,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). <item><seealso marker="logger#set_handler_config-2"> <c>logger:set_handler_config/2,3</c></seealso></item> <item><seealso marker="logger#update_handler_config-2"> - <c>logger:updata_handler_config/2,3</c></seealso></item> + <c>logger:update_handler_config/2,3</c></seealso></item> <item><seealso marker="logger#update_formatter_config-2"> <c>logger:update_formatter_config/2</c></seealso></item> </list> @@ -1228,7 +1228,7 @@ logger:set_process_metadata(maps:merge(logger:get_process_metadata(), Meta)). </desc> </func> <func> - <name>FModule:format(LogEvent, FConfig) -> FormattedLogEntry</name> + <name since="OTP 21.0">FModule:format(LogEvent, FConfig) -> FormattedLogEntry</name> <fsummary>Format the given log event.</fsummary> <type> <v>LogEvent = diff --git a/lib/kernel/doc/src/logger_disk_log_h.xml b/lib/kernel/doc/src/logger_disk_log_h.xml index d9b941a0a9..5b2374690e 100644 --- a/lib/kernel/doc/src/logger_disk_log_h.xml +++ b/lib/kernel/doc/src/logger_disk_log_h.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>logger_disk_log_h.xml</file> </header> - <module>logger_disk_log_h</module> + <module since="OTP 21.0">logger_disk_log_h</module> <modulesummary>A disk_log based handler for Logger</modulesummary> <description> @@ -148,7 +148,7 @@ erl -kernel logger '[{handler,default,logger_disk_log_h, <funcs> <func> - <name name="filesync" arity="1" clause_i="1"/> + <name name="filesync" arity="1" clause_i="1" since="OTP 21.0"/> <fsummary>Writes buffered data to disk.</fsummary> <desc> <p>Write buffered data to disk.</p> diff --git a/lib/kernel/doc/src/logger_filters.xml b/lib/kernel/doc/src/logger_filters.xml index 90f1fcc270..0a02342864 100644 --- a/lib/kernel/doc/src/logger_filters.xml +++ b/lib/kernel/doc/src/logger_filters.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>logger_filters.xml</file> </header> - <module>logger_filters</module> + <module since="OTP 21.0">logger_filters</module> <modulesummary>Filters to use with Logger.</modulesummary> <description> @@ -51,7 +51,7 @@ <funcs> <func> - <name name="domain" arity="2"/> + <name name="domain" arity="2" since="OTP 21.0"/> <fsummary>Filter log events based on the domain field in metadata.</fsummary> <desc> @@ -152,7 +152,7 @@ ok</code> </func> <func> - <name name="level" arity="2"/> + <name name="level" arity="2" since="OTP 21.0"/> <fsummary>Filter log events based on the log level.</fsummary> <desc> <p>This filter provides a way of filtering log events based @@ -212,7 +212,7 @@ ok</code> </func> <func> - <name name="progress" arity="2"/> + <name name="progress" arity="2" since="OTP 21.0"/> <fsummary>Filter progress reports from supervisor and application_controller.</fsummary> <desc> <p>This filter matches all progress reports @@ -227,7 +227,7 @@ ok</code> </func> <func> - <name name="remote_gl" arity="2"/> + <name name="remote_gl" arity="2" since="OTP 21.0"/> <fsummary>Filter events with group leader on remote node.</fsummary> <desc> <p>This filter matches all events originating from a process diff --git a/lib/kernel/doc/src/logger_formatter.xml b/lib/kernel/doc/src/logger_formatter.xml index 24772fd6c4..6dc83d24e1 100644 --- a/lib/kernel/doc/src/logger_formatter.xml +++ b/lib/kernel/doc/src/logger_formatter.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>logger_formatter.xml</file> </header> - <module>logger_formatter</module> + <module since="OTP 21.0">logger_formatter</module> <modulesummary>Default formatter for Logger.</modulesummary> <description> @@ -289,7 +289,7 @@ exit_reason: "It crashed"</code> <funcs> <func> - <name name="check_config" arity="1"/> + <name name="check_config" arity="1" since="OTP 21.0"/> <fsummary>Validates the given formatter configuration.</fsummary> <desc> <p>The function is called by Logger when the formatter @@ -303,14 +303,14 @@ exit_reason: "It crashed"</code> <item><seealso marker="logger#set_handler_config-2"> <c>logger:set_handler_config/2,3</c></seealso></item> <item><seealso marker="logger#update_handler_config-2"> - <c>logger:updata_handler_config/2</c></seealso></item> + <c>logger:update_handler_config/2</c></seealso></item> <item><seealso marker="logger#update_formatter_config-2"> <c>logger:update_formatter_config/2</c></seealso></item> </list> </desc> </func> <func> - <name name="format" arity="2"/> + <name name="format" arity="2" since="OTP 21.0"/> <fsummary>Formats the given message.</fsummary> <desc> <p>This the formatter callback function to be called from diff --git a/lib/kernel/doc/src/logger_std_h.xml b/lib/kernel/doc/src/logger_std_h.xml index e156f5719b..fcd180abd6 100644 --- a/lib/kernel/doc/src/logger_std_h.xml +++ b/lib/kernel/doc/src/logger_std_h.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>logger_std_h.xml</file> </header> - <module>logger_std_h</module> + <module since="OTP 21.0">logger_std_h</module> <modulesummary>Standard handler for Logger.</modulesummary> <description> @@ -121,7 +121,7 @@ erl -kernel logger '[{handler,default,logger_std_h, <funcs> <func> - <name name="filesync" arity="1" clause_i="1"/> + <name name="filesync" arity="1" clause_i="1" since="OTP 21.0"/> <fsummary>Writes buffered data to disk.</fsummary> <desc> <p>Write buffered data to disk.</p> diff --git a/lib/kernel/doc/src/net_adm.xml b/lib/kernel/doc/src/net_adm.xml index 6957a3b5e4..c3e1619f1b 100644 --- a/lib/kernel/doc/src/net_adm.xml +++ b/lib/kernel/doc/src/net_adm.xml @@ -28,7 +28,7 @@ <date>1996-09-10</date> <rev>A</rev> </header> - <module>net_adm</module> + <module since="">net_adm</module> <modulesummary>Various Erlang net administration routines.</modulesummary> <description> <p>This module contains various network utility functions.</p> @@ -36,7 +36,7 @@ <funcs> <func> - <name name="dns_hostname" arity="1"/> + <name name="dns_hostname" arity="1" since=""/> <fsummary>Official name of a host.</fsummary> <desc> <p>Returns the official name of <c><anno>Host</anno></c>, or @@ -46,7 +46,7 @@ </func> <func> - <name name="host_file" arity="0"/> + <name name="host_file" arity="0" since=""/> <fsummary>Read file <c>.hosts.erlang</c>.</fsummary> <desc> <p>Reads file <c>.hosts.erlang</c>, see section @@ -58,7 +58,7 @@ </func> <func> - <name name="localhost" arity="0"/> + <name name="localhost" arity="0" since=""/> <fsummary>Name of the local host.</fsummary> <desc> <p>Returns the name of the local host. If Erlang was started @@ -68,8 +68,8 @@ </func> <func> - <name name="names" arity="0"/> - <name name="names" arity="1"/> + <name name="names" arity="0" since=""/> + <name name="names" arity="1" since=""/> <fsummary>Names of Erlang nodes at a host.</fsummary> <desc> <p>Similar to <c>epmd -names</c>, see @@ -86,7 +86,7 @@ </func> <func> - <name name="ping" arity="1"/> + <name name="ping" arity="1" since=""/> <fsummary>Set up a connection to a node.</fsummary> <desc> <p>Sets up a connection to <c><anno>Node</anno></c>. Returns @@ -95,8 +95,8 @@ </func> <func> - <name name="world" arity="0"/> - <name name="world" arity="1"/> + <name name="world" arity="0" since=""/> + <name name="world" arity="1" since=""/> <fsummary>Lookup and connect to all nodes at all hosts in <c>.hosts.erlang</c>.</fsummary> <type name="verbosity"/> @@ -117,8 +117,8 @@ </func> <func> - <name name="world_list" arity="1"/> - <name name="world_list" arity="2"/> + <name name="world_list" arity="1" since=""/> + <name name="world_list" arity="2" since=""/> <fsummary>Lookup and connect to all nodes at specified hosts.</fsummary> <type name="verbosity"/> <desc> diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml index bfbe7a6470..419d3cad84 100644 --- a/lib/kernel/doc/src/net_kernel.xml +++ b/lib/kernel/doc/src/net_kernel.xml @@ -28,7 +28,7 @@ <date>1996-09-10</date> <rev>A</rev> </header> - <module>net_kernel</module> + <module since="">net_kernel</module> <modulesummary>Erlang networking kernel.</modulesummary> <description> <p>The net kernel is a system process, registered as @@ -81,7 +81,7 @@ $ <input>erl -sname foobar</input></pre> <funcs> <func> - <name name="allow" arity="1"/> + <name name="allow" arity="1" since=""/> <fsummary>Permit access to a specified set of nodes</fsummary> <desc> <p>Permits access to the specified set of nodes.</p> @@ -98,7 +98,7 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="connect_node" arity="1"/> + <name name="connect_node" arity="1" since=""/> <fsummary>Establish a connection to a node.</fsummary> <desc> <p>Establishes a connection to <c><anno>Node</anno></c>. Returns @@ -110,7 +110,7 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="get_net_ticktime" arity="0"/> + <name name="get_net_ticktime" arity="0" since=""/> <fsummary>Get <c>net_ticktime</c>.</fsummary> <desc> <p>Gets <c>net_ticktime</c> (see @@ -131,7 +131,7 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="getopts" arity="2"/> + <name name="getopts" arity="2" since="OTP 19.1"/> <fsummary>Get distribution socket options.</fsummary> <desc> <p>Get one or more options for the distribution socket @@ -146,8 +146,8 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="monitor_nodes" arity="1"/> - <name name="monitor_nodes" arity="2"/> + <name name="monitor_nodes" arity="1" since=""/> + <name name="monitor_nodes" arity="2" since=""/> <fsummary>Subscribe to node status change messages.</fsummary> <desc> <p>The calling process subscribes or unsubscribes to node @@ -267,8 +267,8 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="set_net_ticktime" arity="1"/> - <name name="set_net_ticktime" arity="2"/> + <name name="set_net_ticktime" arity="1" since=""/> + <name name="set_net_ticktime" arity="2" since=""/> <fsummary>Set <c>net_ticktime</c>.</fsummary> <desc> <p>Sets <c>net_ticktime</c> (see @@ -324,7 +324,7 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="setopts" arity="2"/> + <name name="setopts" arity="2" since="OTP 19.1"/> <fsummary>Set distribution socket options.</fsummary> <desc> <p>Set one or more options for distribution sockets. @@ -345,9 +345,9 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name>start([Name]) -> {ok, pid()} | {error, Reason}</name> - <name>start([Name, NameType]) -> {ok, pid()} | {error, Reason}</name> - <name>start([Name, NameType, Ticktime]) -> {ok, pid()} | {error, Reason}</name> + <name since="">start([Name]) -> {ok, pid()} | {error, Reason}</name> + <name since="">start([Name, NameType]) -> {ok, pid()} | {error, Reason}</name> + <name since="">start([Name, NameType, Ticktime]) -> {ok, pid()} | {error, Reason}</name> <fsummary>Turn an Erlang runtime system into a distributed node.</fsummary> <type> <v>Name = atom()</v> @@ -364,7 +364,7 @@ $ <input>erl -sname foobar</input></pre> </func> <func> - <name name="stop" arity="0"/> + <name name="stop" arity="0" since=""/> <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 8188ede6a2..021ecfa40d 100644 --- a/lib/kernel/doc/src/notes.xml +++ b/lib/kernel/doc/src/notes.xml @@ -31,6 +31,123 @@ </header> <p>This document describes the changes made to the Kernel application.</p> +<section><title>Kernel 6.2</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + A new function, <c>logger:update_handler_config/3</c> is + added, and the handler callback <c>changing_config</c> + now has a new argument, <c>SetOrUpdate</c>, which + indicates if the configuration change comes from + <c>set_handler_config/2,3</c> or + <c>update_handler_config/2,3</c>.</p> + <p> + This allows the handler to consistently merge the new + configuration with the old (if the change comes from + <c>update_handler_config/2,3</c>) or with the default (if + the change comes from <c>set_handler_config/2,3</c>).</p> + <p> + The built-in handlers <c>logger_std_h</c> and + <c>logger_disk_log_h</c> are updated accordingly. A bug + which could cause inconsistency between the handlers' + internal state and the stored configuration is also + corrected.</p> + <p> + *** POTENTIAL INCOMPATIBILITY ***</p> + <p> + Own Id: OTP-15364</p> + </item> + <item> + <p> + Fix fallback when custom erl_epmd client does not + implement address_please.</p> + <p> + Own Id: OTP-15388 Aux Id: PR-1983 </p> + </item> + <item> + <p> + The logger ets table did not have the + <c>read_concurrency</c> option. This is now added.</p> + <p> + Own Id: OTP-15453 Aux Id: ERL-782 </p> + </item> + <item> + <p> + During system start, logger has a simple handler which + prints to stdout. After the kernel supervision is + started, this handler is removed and replaced by the + default handler. Due to a bug, logger earlier issued a + debug printout saying it received an unexpected message, + which was the EXIT message from the simple handler's + process. This is now corrected. The simple handler's + process now unlinks from the logger process before + terminating.</p> + <p> + Own Id: OTP-15466 Aux Id: ERL-788 </p> + </item> + <item> + <p> + The logger handler <c>logger_std_h</c> would not + re-create it's log file if it was removed. Due to this it + could not be used with tools like 'logrotate'. This is + now corrected.</p> + <p> + Own Id: OTP-15469</p> + </item> + </list> + </section> + + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + A function <c>inet:getifaddrs/1</c> that takes a list + with a namespace option has been added, for platforms + that support that feature, for example Linux (only?).</p> + <p> + Own Id: OTP-15121 Aux Id: ERIERL-189, PR-1974 </p> + </item> + <item> + <p>Added the <c>nopush</c> option for TCP sockets, which + corresponds to <c>TCP_NOPUSH</c> on *BSD and + <c>TCP_CORK</c> on Linux.</p> + <p>This is also used internally in <c>file:sendfile</c> + to reduce latency on subsequent send operations.</p> + <p> + Own Id: OTP-15357 Aux Id: ERL-698 </p> + </item> + <item> + <p> + Optimize handling of send_delay for tcp sockes to better + work with the new pollthread implementation introduced in + OTP-21.</p> + <p> + Own Id: OTP-15471 Aux Id: ERIERL-229 </p> + </item> + </list> + </section> + +</section> + +<section><title>Kernel 6.1.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + Fix bug causing net_kernel process crash on connection + attempt from node with name identical to local node.</p> + <p> + Own Id: OTP-15438 Aux Id: ERL-781 </p> + </item> + </list> + </section> + +</section> + <section><title>Kernel 6.1</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/kernel/doc/src/os.xml b/lib/kernel/doc/src/os.xml index c95e615c6b..0500e4cfb3 100644 --- a/lib/kernel/doc/src/os.xml +++ b/lib/kernel/doc/src/os.xml @@ -28,7 +28,7 @@ <date></date> <rev></rev> </header> - <module>os</module> + <module since="">os</module> <modulesummary>Operating system-specific functions.</modulesummary> <description> <p>The functions in this module are operating system-specific. @@ -134,8 +134,8 @@ <funcs> <func> - <name name="cmd" arity="1"/> - <name name="cmd" arity="2"/> + <name name="cmd" arity="1" since=""/> + <name name="cmd" arity="2" since="OTP 20.2.3"/> <fsummary>Execute a command in a shell of the target OS.</fsummary> <desc> <p>Executes <c><anno>Command</anno></c> in a command shell of the @@ -173,8 +173,8 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="find_executable" arity="1"/> - <name name="find_executable" arity="2"/> + <name name="find_executable" arity="1" since=""/> + <name name="find_executable" arity="2" since=""/> <fsummary>Absolute filename of a program.</fsummary> <desc> <p>These two functions look up an executable program, with the @@ -190,7 +190,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="getenv" arity="0"/> + <name name="getenv" arity="0" since=""/> <fsummary>List all environment variables.</fsummary> <desc> <p>Returns a list of all environment variables. @@ -205,7 +205,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="getenv" arity="1"/> + <name name="getenv" arity="1" since=""/> <fsummary>Get the value of an environment variable.</fsummary> <desc> <p>Returns the <c><anno>Value</anno></c> of the environment variable @@ -220,7 +220,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="getenv" arity="2"/> + <name name="getenv" arity="2" since="OTP 18.0"/> <fsummary>Get the value of an environment variable.</fsummary> <desc> <p>Returns the <c><anno>Value</anno></c> of the environment variable @@ -235,7 +235,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="getpid" arity="0"/> + <name name="getpid" arity="0" since=""/> <fsummary>Return the process identifier of the emulator process.</fsummary> <desc> @@ -251,7 +251,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="putenv" arity="2"/> + <name name="putenv" arity="2" since=""/> <fsummary>Set a new value for an environment variable.</fsummary> <desc> <p>Sets a new <c><anno>Value</anno></c> for environment variable @@ -277,7 +277,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="set_signal" arity="2"/> + <name name="set_signal" arity="2" since="OTP 20.0"/> <fsummary>Enables or disables handling of OS signals.</fsummary> <desc> <p>Enables or disables OS signals.</p> @@ -304,7 +304,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="system_time" arity="0"/> + <name name="system_time" arity="0" since="OTP 18.0"/> <fsummary>Current OS system time.</fsummary> <desc> <p>Returns the current @@ -317,7 +317,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="system_time" arity="1"/> + <name name="system_time" arity="1" since="OTP 18.0"/> <fsummary>Current OS system time.</fsummary> <desc> <p>Returns the current @@ -332,7 +332,7 @@ DirOut = os:cmd("dir"), % on Win32 platform</code> </func> <func> - <name name="timestamp" arity="0"/> + <name name="timestamp" arity="0" since=""/> <fsummary>Current OS system time on the <c>erlang:timestamp/0</c> format.</fsummary> <type_desc variable="Timestamp">Timestamp = {MegaSecs, Secs, MicroSecs}</type_desc> <desc> @@ -373,7 +373,7 @@ calendar:now_to_universal_time(TS), </func> <func> - <name name="perf_counter" arity="0"/> + <name name="perf_counter" arity="0" since="OTP 19.0"/> <fsummary>Returns a performance counter</fsummary> <desc> <p>Returns the current performance counter value in <c>perf_counter</c> @@ -383,7 +383,7 @@ calendar:now_to_universal_time(TS), </desc> </func> <func> - <name name="perf_counter" arity="1"/> + <name name="perf_counter" arity="1" since="OTP 19.0"/> <fsummary>Returns a performance counter</fsummary> <desc><p>Returns a performance counter that can be used as a very fast and high resolution timestamp. This counter is read directly from the hardware or operating @@ -397,7 +397,7 @@ calendar:now_to_universal_time(TS), </desc> </func> <func> - <name name="type" arity="0"/> + <name name="type" arity="0" since=""/> <fsummary>Return the OS family and, in some cases, the OS name of the current OS.</fsummary> <desc> @@ -417,7 +417,7 @@ calendar:now_to_universal_time(TS), </func> <func> - <name name="unsetenv" arity="1"/> + <name name="unsetenv" arity="1" since="OTP R16B03"/> <fsummary>Delete an environment variable.</fsummary> <desc> <p>Deletes the environment variable <c><anno>VarName</anno></c>.</p> @@ -429,7 +429,7 @@ calendar:now_to_universal_time(TS), </func> <func> - <name name="version" arity="0"/> + <name name="version" arity="0" since=""/> <fsummary>Return the OS versions.</fsummary> <desc> <p>Returns the OS version. diff --git a/lib/kernel/doc/src/pg2.xml b/lib/kernel/doc/src/pg2.xml index 0631b317b4..058d711756 100644 --- a/lib/kernel/doc/src/pg2.xml +++ b/lib/kernel/doc/src/pg2.xml @@ -32,7 +32,7 @@ <rev>A2</rev> <file>pg2.xml</file> </header> - <module>pg2</module> + <module since="">pg2</module> <modulesummary>Distributed named process groups.</modulesummary> <description> <p>This module implements process groups. Each message can be sent @@ -66,7 +66,7 @@ <funcs> <func> - <name name="create" arity="1"/> + <name name="create" arity="1" since=""/> <fsummary>Create a new, empty process group.</fsummary> <desc> <p>Creates a new, empty process group. The group is globally @@ -75,7 +75,7 @@ </func> <func> - <name name="delete" arity="1"/> + <name name="delete" arity="1" since=""/> <fsummary>Delete a process group.</fsummary> <desc> <p>Deletes a process group.</p> @@ -83,7 +83,7 @@ </func> <func> - <name name="get_closest_pid" arity="1"/> + <name name="get_closest_pid" arity="1" since=""/> <fsummary>Common dispatch function.</fsummary> <desc> <p>A useful dispatch function that can be used from @@ -93,7 +93,7 @@ </func> <func> - <name name="get_local_members" arity="1"/> + <name name="get_local_members" arity="1" since=""/> <fsummary>Return all local processes in a group.</fsummary> <desc> <p>Returns all processes running on the local node in the @@ -104,7 +104,7 @@ </func> <func> - <name name="get_members" arity="1"/> + <name name="get_members" arity="1" since=""/> <fsummary>Return all processes in a group.</fsummary> <desc> <p>Returns all processes in the group <c>Name</c>. This @@ -114,7 +114,7 @@ </func> <func> - <name name="join" arity="2"/> + <name name="join" arity="2" since=""/> <fsummary>Join a process to a group.</fsummary> <desc> <p>Joins the process <c>Pid</c> to the group <c>Name</c>. @@ -124,7 +124,7 @@ </func> <func> - <name name="leave" arity="2"/> + <name name="leave" arity="2" since=""/> <fsummary>Make a process leave a group.</fsummary> <desc> <p>Makes the process <c>Pid</c> leave the group <c>Name</c>. @@ -134,8 +134,8 @@ </func> <func> - <name name="start" arity="0"/> - <name name="start_link" arity="0"/> + <name name="start" arity="0" since=""/> + <name name="start_link" arity="0" since=""/> <fsummary>Start the <c>pg2</c> server.</fsummary> <desc> <p>Starts the <c>pg2</c> server. Normally, the server does not need @@ -149,7 +149,7 @@ </func> <func> - <name name="which_groups" arity="0"/> + <name name="which_groups" arity="0" since=""/> <fsummary>Return a list of all known groups.</fsummary> <desc> <p>Returns a list of all known groups.</p> diff --git a/lib/kernel/doc/src/rpc.xml b/lib/kernel/doc/src/rpc.xml index fab616e630..c55454506e 100644 --- a/lib/kernel/doc/src/rpc.xml +++ b/lib/kernel/doc/src/rpc.xml @@ -28,7 +28,7 @@ <date>1996-09-10</date> <rev>A</rev> </header> - <module>rpc</module> + <module since="">rpc</module> <modulesummary>Remote Procedure Call services.</modulesummary> <description> <p>This module contains services similar to Remote @@ -51,7 +51,7 @@ <funcs> <func> - <name name="abcast" arity="2"/> + <name name="abcast" arity="2" since=""/> <fsummary>Broadcast a message asynchronously to a registered process on all nodes.</fsummary> <desc> @@ -61,7 +61,7 @@ </func> <func> - <name name="abcast" arity="3"/> + <name name="abcast" arity="3" since=""/> <fsummary>Broadcast a message asynchronously to a registered process on specific nodes.</fsummary> <desc> @@ -72,7 +72,7 @@ </func> <func> - <name name="async_call" arity="4"/> + <name name="async_call" arity="4" since=""/> <fsummary>Evaluate a function call on a node, asynchronous version.</fsummary> <desc> @@ -98,7 +98,7 @@ </func> <func> - <name name="block_call" arity="4"/> + <name name="block_call" arity="4" since=""/> <fsummary>Evaluate a function call on a node in the RPC server's context.</fsummary> <desc> @@ -115,7 +115,7 @@ </func> <func> - <name name="block_call" arity="5"/> + <name name="block_call" arity="5" since=""/> <fsummary>Evaluate a function call on a node in the RPC server's context.</fsummary> <desc> @@ -127,7 +127,7 @@ </func> <func> - <name name="call" arity="4"/> + <name name="call" arity="4" since=""/> <fsummary>Evaluate a function call on a node.</fsummary> <desc> <p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, @@ -138,7 +138,7 @@ </func> <func> - <name name="call" arity="5"/> + <name name="call" arity="5" since=""/> <fsummary>Evaluate a function call on a node.</fsummary> <desc> <p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, @@ -158,7 +158,7 @@ </func> <func> - <name name="cast" arity="4"/> + <name name="cast" arity="4" since=""/> <fsummary>Run a function on a node ignoring the result.</fsummary> <desc> <p>Evaluates <c>apply(<anno>Module</anno>, <anno>Function</anno>, @@ -171,7 +171,7 @@ </func> <func> - <name name="eval_everywhere" arity="3"/> + <name name="eval_everywhere" arity="3" since=""/> <fsummary>Run a function on all nodes, ignoring the result.</fsummary> <desc> <p>Equivalent to <c>eval_everywhere([node()|nodes()], @@ -181,7 +181,7 @@ </func> <func> - <name name="eval_everywhere" arity="4"/> + <name name="eval_everywhere" arity="4" since=""/> <fsummary>Run a function on specific nodes, ignoring the result.</fsummary> <desc> @@ -192,7 +192,7 @@ </func> <func> - <name name="multi_server_call" arity="2"/> + <name name="multi_server_call" arity="2" since=""/> <fsummary>Interact with the servers on a number of nodes.</fsummary> <desc> <p>Equivalent to <c>multi_server_call([node()|nodes()], @@ -201,7 +201,7 @@ </func> <func> - <name name="multi_server_call" arity="3"/> + <name name="multi_server_call" arity="3" since=""/> <fsummary>Interact with the servers on a number of nodes.</fsummary> <desc> <p>Can be used when interacting with servers called @@ -224,7 +224,7 @@ </func> <func> - <name name="multicall" arity="3"/> + <name name="multicall" arity="3" since=""/> <fsummary>Evaluate a function call on a number of nodes.</fsummary> <desc> <p>Equivalent to <c>multicall([node()|nodes()], <anno>Module</anno>, @@ -233,7 +233,7 @@ </func> <func> - <name name="multicall" arity="4" clause_i="1"/> + <name name="multicall" arity="4" clause_i="1" since=""/> <fsummary>Evaluate a function call on a number of nodes.</fsummary> <desc> <p>Equivalent to <c>multicall(<anno>Nodes</anno>, <anno>Module</anno>, @@ -242,7 +242,7 @@ </func> <func> - <name name="multicall" arity="4" clause_i="2"/> + <name name="multicall" arity="4" clause_i="2" since=""/> <fsummary>Evaluate a function call on a number of nodes.</fsummary> <desc> <p>Equivalent to <c>multicall([node()|nodes()], <anno>Module</anno>, @@ -252,7 +252,7 @@ </func> <func> - <name name="multicall" arity="5"/> + <name name="multicall" arity="5" since=""/> <fsummary>Evaluate a function call on a number of nodes.</fsummary> <desc> <p>In contrast to an RPC, a multicall is an RPC that is sent @@ -288,7 +288,7 @@ </func> <func> - <name name="nb_yield" arity="1"/> + <name name="nb_yield" arity="1" since=""/> <fsummary>Deliver the result of evaluating a function call on a node (non-blocking).</fsummary> <desc> @@ -297,7 +297,7 @@ </func> <func> - <name name="nb_yield" arity="2"/> + <name name="nb_yield" arity="2" since=""/> <fsummary>Deliver the result of evaluating a function call on a node (non-blocking).</fsummary> <desc> @@ -315,7 +315,7 @@ </func> <func> - <name name="parallel_eval" arity="1"/> + <name name="parallel_eval" arity="1" since=""/> <fsummary>Evaluate many function calls on all nodes in parallel.</fsummary> <desc> @@ -328,7 +328,7 @@ </func> <func> - <name name="pinfo" arity="1"/> + <name name="pinfo" arity="1" since=""/> <fsummary>Information about a process.</fsummary> <desc> <p>Location transparent version of the BIF @@ -337,8 +337,8 @@ </func> <func> - <name name="pinfo" arity="2" clause_i="1"/> - <name name="pinfo" arity="2" clause_i="2"/> + <name name="pinfo" arity="2" clause_i="1" since=""/> + <name name="pinfo" arity="2" clause_i="2" since=""/> <fsummary>Information about a process.</fsummary> <desc> <p>Location transparent version of the BIF @@ -347,7 +347,7 @@ </func> <func> - <name name="pmap" arity="3"/> + <name name="pmap" arity="3" since=""/> <fsummary>Parallel evaluation of mapping a function over a list.</fsummary> <desc> @@ -360,7 +360,7 @@ </func> <func> - <name name="sbcast" arity="2"/> + <name name="sbcast" arity="2" since=""/> <fsummary>Broadcast a message synchronously to a registered process on all nodes.</fsummary> <desc> @@ -370,7 +370,7 @@ </func> <func> - <name name="sbcast" arity="3"/> + <name name="sbcast" arity="3" since=""/> <fsummary>Broadcast a message synchronously to a registered process on specific nodes.</fsummary> <desc> @@ -391,7 +391,7 @@ </func> <func> - <name name="server_call" arity="4"/> + <name name="server_call" arity="4" since=""/> <fsummary>Interact with a server on a node.</fsummary> <desc> <p>Can be used when interacting with a server called @@ -410,7 +410,7 @@ </func> <func> - <name name="yield" arity="1"/> + <name name="yield" arity="1" since=""/> <fsummary>Deliver the result of evaluating a function call on a node (blocking).</fsummary> <desc> diff --git a/lib/kernel/doc/src/seq_trace.xml b/lib/kernel/doc/src/seq_trace.xml index 1a4a74419a..aa29223dd0 100644 --- a/lib/kernel/doc/src/seq_trace.xml +++ b/lib/kernel/doc/src/seq_trace.xml @@ -28,7 +28,7 @@ <date>1998-04-16</date> <rev>A</rev> </header> - <module>seq_trace</module> + <module since="">seq_trace</module> <modulesummary>Sequential tracing of messages.</modulesummary> <description> <p>Sequential tracing makes it possible to trace all messages @@ -51,7 +51,7 @@ </datatypes> <funcs> <func> - <name name="set_token" arity="1"/> + <name name="set_token" arity="1" since=""/> <fsummary>Set the trace token</fsummary> <desc> <p>Sets the trace token for the calling process to <c><anno>Token</anno></c>. @@ -71,7 +71,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="set_token" arity="2"/> + <name name="set_token" arity="2" since=""/> <fsummary>Set a component of the trace token</fsummary> <type name="component"/> <type name="flag"/> @@ -158,7 +158,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="get_token" arity="0"/> + <name name="get_token" arity="0" since=""/> <fsummary>Return the value of the trace token</fsummary> <desc> <p>Returns the value of the trace token for the calling process. @@ -169,7 +169,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="get_token" arity="1"/> + <name name="get_token" arity="1" since=""/> <fsummary>Return the value of a trace token component</fsummary> <type name="component"/> <type name="flag"/> @@ -182,7 +182,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="print" arity="1"/> + <name name="print" arity="1" since=""/> <fsummary>Put the Erlang term <c>TraceInfo</c>into the sequential trace output</fsummary> <desc> <p>Puts the Erlang term <c><anno>TraceInfo</anno></c> into the sequential @@ -192,7 +192,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="print" arity="2"/> + <name name="print" arity="2" since=""/> <fsummary>Put the Erlang term <c>TraceInfo</c>into the sequential trace output</fsummary> <desc> <p>Same as <c>print/1</c> with the additional condition that @@ -201,7 +201,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="reset_trace" arity="0"/> + <name name="reset_trace" arity="0" since=""/> <fsummary>Stop all sequential tracing on the local node</fsummary> <desc> <p>Sets the trace token to empty for all processes on the @@ -213,7 +213,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="set_system_tracer" arity="1"/> + <name name="set_system_tracer" arity="1" since=""/> <fsummary>Set the system tracer</fsummary> <type name="tracer"/> <desc> @@ -227,7 +227,7 @@ seq_trace:set_token(OldToken), % activate the trace token again </desc> </func> <func> - <name name="get_system_tracer" arity="0"/> + <name name="get_system_tracer" arity="0" since=""/> <fsummary>Return the pid() or port() of the current system tracer.</fsummary> <type name="tracer"/> <desc> diff --git a/lib/kernel/doc/src/wrap_log_reader.xml b/lib/kernel/doc/src/wrap_log_reader.xml index 7fb9c1c023..5f37e7ec5f 100644 --- a/lib/kernel/doc/src/wrap_log_reader.xml +++ b/lib/kernel/doc/src/wrap_log_reader.xml @@ -32,7 +32,7 @@ <rev>A</rev> <file>wrap_log_reader.sgml</file> </header> - <module>wrap_log_reader</module> + <module since="">wrap_log_reader</module> <modulesummary>A service to read internally formatted wrap disk logs. </modulesummary> <description> @@ -65,8 +65,8 @@ <funcs> <func> - <name name="chunk" arity="1"/> - <name name="chunk" arity="2"/> + <name name="chunk" arity="1" since=""/> + <name name="chunk" arity="2" since=""/> <fsummary>Read a chunk of objects written to a wrap log.</fsummary> <type name="chunk_ret"/> <desc> @@ -105,7 +105,7 @@ </func> <func> - <name name="close" arity="1"/> + <name name="close" arity="1" since=""/> <fsummary>Close a log.</fsummary> <desc> <p>Closes a log file properly.</p> @@ -113,8 +113,8 @@ </func> <func> - <name name="open" arity="1"/> - <name name="open" arity="2"/> + <name name="open" arity="1" since=""/> + <name name="open" arity="2" since=""/> <fsummary>Open a log file.</fsummary> <type name="open_ret"/> <desc> diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src index 0c0435e051..ccf0a82ced 100644 --- a/lib/kernel/src/kernel.appup.src +++ b/lib/kernel/src/kernel.appup.src @@ -16,15 +16,42 @@ %% limitations under the License. %% %% %CopyrightEnd% +%% +%% We allow upgrade from, and downgrade to all previous +%% versions from the following OTP releases: +%% - OTP 20 +%% - OTP 21 +%% +%% We also allow upgrade from, and downgrade to all +%% versions that have branched off from the above +%% stated previous versions. +%% {"%VSN%", - %% Up from - max one major revision back - [{<<"5\\.3(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.0 - {<<"5\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.1+ - {<<"6\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-21.0 - {<<"6\\.1(\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-21.1 - %% Down to - max one major revision back - [{<<"5\\.3(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.0 - {<<"5\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-20.1+ - {<<"6\\.0(\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-21.0 - {<<"6\\.1(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-21.1 -}. + [{<<"^5\\.3$">>,[restart_new_emulator]}, + {<<"^5\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^5\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^5\\.4$">>,[restart_new_emulator]}, + {<<"^5\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^5\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^5\\.4\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^5\\.4\\.3(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^6\\.0$">>,[restart_new_emulator]}, + {<<"^6\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^6\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^6\\.1$">>,[restart_new_emulator]}, + {<<"^6\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}], + [{<<"^5\\.3$">>,[restart_new_emulator]}, + {<<"^5\\.3\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^5\\.3\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^5\\.4$">>,[restart_new_emulator]}, + {<<"^5\\.4\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^5\\.4\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^5\\.4\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^5\\.4\\.3(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^6\\.0$">>,[restart_new_emulator]}, + {<<"^6\\.0\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^6\\.0\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}, + {<<"^6\\.1$">>,[restart_new_emulator]}, + {<<"^6\\.1\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]}, + {<<"^6\\.1\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]}]}. diff --git a/lib/kernel/src/logger_config.erl b/lib/kernel/src/logger_config.erl index 6bfe658552..5e9faf332c 100644 --- a/lib/kernel/src/logger_config.erl +++ b/lib/kernel/src/logger_config.erl @@ -31,7 +31,9 @@ -include("logger_internal.hrl"). new(Name) -> - _ = ets:new(Name,[set,protected,named_table,{write_concurrency,true}]), + _ = ets:new(Name,[set,protected,named_table, + {read_concurrency,true}, + {write_concurrency,true}]), ets:whereis(Name). delete(Tid,Id) -> diff --git a/lib/kernel/src/logger_disk_log_h.erl b/lib/kernel/src/logger_disk_log_h.erl index 2a81458ec8..41e0d51a9d 100644 --- a/lib/kernel/src/logger_disk_log_h.erl +++ b/lib/kernel/src/logger_disk_log_h.erl @@ -19,59 +19,33 @@ %% -module(logger_disk_log_h). --behaviour(gen_server). - -include("logger.hrl"). -include("logger_internal.hrl"). -include("logger_h_common.hrl"). %%% API --export([start_link/3, info/1, filesync/1, reset/1]). +-export([info/1, filesync/1, reset/1]). -%% gen_server callbacks --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). +%% logger_h_common callbacks +-export([init/2, check_config/4, reset_state/2, + filesync/3, write/4, handle_info/3, terminate/3]). %% logger callbacks -export([log/2, adding_handler/1, removing_handler/1, changing_config/3, filter_config/1]). -%% handler internal --export([log_handler_info/4]). - %%%=================================================================== %%% API %%%=================================================================== %%%----------------------------------------------------------------- -%%% Start a disk_log handler process and link to caller. -%%% This function is called by the kernel supervisor when this -%%% handler process gets added (as a result of calling add/3). --spec start_link(Name, Config, HandlerState) -> {ok,Pid} | {error,Reason} when - Name :: atom(), - Config :: logger:handler_config(), - HandlerState :: map(), - Pid :: pid(), - Reason :: term(). - -start_link(Name, Config, HandlerState) -> - proc_lib:start_link(?MODULE,init,[[Name,Config,HandlerState]]). - -%%%----------------------------------------------------------------- %%% -spec filesync(Name) -> ok | {error,Reason} when Name :: atom(), Reason :: handler_busy | {badarg,term()}. -filesync(Name) when is_atom(Name) -> - try - gen_server:call(?name_to_reg_name(?MODULE,Name), - disk_log_sync, ?DEFAULT_CALL_TIMEOUT) - catch - _:{timeout,_} -> {error,handler_busy} - end; filesync(Name) -> - {error,{badarg,{filesync,[Name]}}}. + logger_h_common:filesync(?MODULE,Name). %%%----------------------------------------------------------------- %%% @@ -80,15 +54,8 @@ filesync(Name) -> Info :: term(), Reason :: handler_busy | {badarg,term()}. -info(Name) when is_atom(Name) -> - try - gen_server:call(?name_to_reg_name(?MODULE,Name), - info, ?DEFAULT_CALL_TIMEOUT) - catch - _:{timeout,_} -> {error,handler_busy} - end; info(Name) -> - {error,{badarg,{info,[Name]}}}. + logger_h_common:info(?MODULE,Name). %%%----------------------------------------------------------------- %%% @@ -96,16 +63,8 @@ info(Name) -> Name :: atom(), Reason :: handler_busy | {badarg,term()}. -reset(Name) when is_atom(Name) -> - try - gen_server:call(?name_to_reg_name(?MODULE,Name), - reset, ?DEFAULT_CALL_TIMEOUT) - catch - _:{timeout,_} -> {error,handler_busy} - end; reset(Name) -> - {error,{badarg,{reset,[Name]}}}. - + logger_h_common:reset(?MODULE,Name). %%%=================================================================== %%% logger callbacks @@ -113,30 +72,55 @@ reset(Name) -> %%%----------------------------------------------------------------- %%% Handler being added -adding_handler(#{id:=Name}=Config) -> - case check_config(adding, Config) of - {ok, #{config:=HConfig}=Config1} -> - %% create initial handler state by merging defaults with config - HState = maps:merge(get_init_state(), HConfig), - case logger_h_common:overload_levels_ok(HState) of - true -> - start(Name, Config1, HState); - false -> - #{sync_mode_qlen := SMQL, - drop_mode_qlen := DMQL, - flush_qlen := FQL} = HState, - {error,{invalid_levels,{SMQL,DMQL,FQL}}} - end; +adding_handler(Config) -> + logger_h_common:adding_handler(Config). + +%%%----------------------------------------------------------------- +%%% Updating handler config +changing_config(SetOrUpdate, OldConfig, NewConfig) -> + logger_h_common:changing_config(SetOrUpdate, OldConfig, NewConfig). + +%%%----------------------------------------------------------------- +%%% Handler being removed +removing_handler(Config) -> + logger_h_common:removing_handler(Config). + +%%%----------------------------------------------------------------- +%%% Log a string or report +-spec log(LogEvent, Config) -> ok when + LogEvent :: logger:log_event(), + Config :: logger:handler_config(). + +log(LogEvent, Config) -> + logger_h_common:log(LogEvent, Config). + +%%%----------------------------------------------------------------- +%%% Remove internal fields from configuration +filter_config(Config) -> + logger_h_common:filter_config(Config). + +%%%=================================================================== +%%% logger_h_common callbacks +%%%=================================================================== +init(Name, #{file:=File,type:=Type,max_no_bytes:=MNB,max_no_files:=MNF}) -> + case open_disk_log(Name, File, Type, MNB, MNF) of + ok -> + {ok,#{log_opts => #{file => File, + type => Type, + max_no_bytes => MNB, + max_no_files => MNF}, + prev_log_result => ok, + prev_sync_result => ok, + prev_disk_log_info => undefined}}; Error -> Error end. -%%%----------------------------------------------------------------- -%%% Updating handler config -changing_config(SetOrUpdate,OldConfig=#{config:=OldHConfig},NewConfig) -> +check_config(Name,set,undefined,HConfig0) -> + HConfig=merge_default_logopts(Name,maps:merge(get_default_config(),HConfig0)), + check_config(HConfig); +check_config(_Name,SetOrUpdate,OldHConfig,NewHConfig0) -> WriteOnce = maps:with([type,file,max_no_files,max_no_bytes],OldHConfig), - ReadOnly = maps:with([handler_pid,mode_tab],OldHConfig), - NewHConfig0 = maps:get(config, NewConfig, #{}), Default = case SetOrUpdate of set -> @@ -146,66 +130,25 @@ changing_config(SetOrUpdate,OldConfig=#{config:=OldHConfig},NewConfig) -> OldHConfig end, - %% Allow (accidentially) included read-only fields - just overwrite them - NewHConfig = maps:merge(maps:merge(Default,NewHConfig0),ReadOnly), + NewHConfig = maps:merge(Default,NewHConfig0), - %% But fail if write-once fields are changed + %% Fail if write-once fields are changed case maps:with([type,file,max_no_files,max_no_bytes],NewHConfig) of WriteOnce -> - changing_config1(maps:get(handler_pid,OldHConfig), - OldConfig, - NewConfig#{config=>NewHConfig}); + check_config(NewHConfig); Other -> {Old,New} = logger_server:diff_maps(WriteOnce,Other), - {error,{illegal_config_change,#{config=>Old},#{config=>New}}} + {error,{illegal_config_change,?MODULE,Old,New}} end. -changing_config1(HPid, OldConfig, NewConfig) -> - case check_config(changing, NewConfig) of - Result = {ok,NewConfig1} -> - try gen_server:call(HPid, {change_config,OldConfig,NewConfig1}, - ?DEFAULT_CALL_TIMEOUT) of - ok -> Result; - Error -> Error - catch - _:{timeout,_} -> {error,handler_busy} - end; - Error -> - Error - end. - -check_config(adding, #{id:=Name}=Config) -> - %% merge handler specific config data - HConfig1 = maps:get(config, Config, #{}), - HConfig2 = maps:merge(get_default_config(), HConfig1), - HConfig3 = merge_default_logopts(Name, HConfig2), - case check_h_config(maps:to_list(HConfig3)) of - ok -> - {ok,Config#{config=>HConfig3}}; - Error -> - Error - end; -check_config(changing, Config) -> - HConfig = maps:get(config, Config, #{}), +check_config(HConfig) -> case check_h_config(maps:to_list(HConfig)) of - ok -> {ok,Config}; - Error -> Error + ok -> + {ok,HConfig}; + {error,{Key,Value}} -> + {error,{invalid_config,?MODULE,#{Key=>Value}}} end. -merge_default_logopts(Name, HConfig) -> - Type = maps:get(type, HConfig, wrap), - {DefaultNoFiles,DefaultNoBytes} = - case Type of - halt -> {undefined,infinity}; - _wrap -> {10,1048576} - end, - {ok,Dir} = file:get_cwd(), - Defaults = #{file => filename:join(Dir,Name), - max_no_files => DefaultNoFiles, - max_no_bytes => DefaultNoBytes, - type => Type}, - maps:merge(Defaults, HConfig). - check_h_config([{file,File}|Config]) when is_list(File) -> check_h_config(Config); check_h_config([{max_no_files,undefined}|Config]) -> @@ -218,454 +161,59 @@ check_h_config([{max_no_bytes,N}|Config]) when is_integer(N), N>0 -> check_h_config(Config); check_h_config([{type,Type}|Config]) when Type==wrap; Type==halt -> check_h_config(Config); -check_h_config([Other | Config]) -> - case logger_h_common:check_common_config(Other) of - valid -> - check_h_config(Config); - invalid -> - {error,{invalid_config,?MODULE,Other}} - end; +check_h_config([Other | _]) -> + {error,Other}; check_h_config([]) -> ok. -%%%----------------------------------------------------------------- -%%% Handler being removed -removing_handler(#{id:=Name}) -> - stop(Name). - -%%%----------------------------------------------------------------- -%%% Log a string or report --spec log(LogEvent, Config) -> ok when - LogEvent :: logger:log_event(), - Config :: logger:handler_config(). - -log(LogEvent, Config = #{id := Name, - config := #{handler_pid := HPid, - mode_tab := ModeTab}}) -> - %% if the handler has crashed, we must drop this event - %% and hope the handler restarts so we can try again - true = is_process_alive(HPid), - Bin = logger_h_common:log_to_binary(LogEvent, Config), - logger_h_common:call_cast_or_drop(Name, HPid, ModeTab, Bin). +get_default_config() -> + #{}. -%%%----------------------------------------------------------------- -%%% Remove internal fields from configuration -filter_config(#{config:=HConfig}=Config) -> - Config#{config=>maps:without([handler_pid,mode_tab],HConfig)}. +merge_default_logopts(Name, HConfig) -> + Type = maps:get(type, HConfig, wrap), + {DefaultNoFiles,DefaultNoBytes} = + case Type of + halt -> {undefined,infinity}; + _wrap -> {10,1048576} + end, + {ok,Dir} = file:get_cwd(), + Defaults = #{file => filename:join(Dir,Name), + max_no_files => DefaultNoFiles, + max_no_bytes => DefaultNoBytes, + type => Type}, + maps:merge(Defaults, HConfig). -%%%=================================================================== -%%% gen_server callbacks -%%%=================================================================== +filesync(Name,_Mode,State) -> + Result = ?disk_log_sync(Name), + maybe_notify_error(Name, filesync, Result, prev_sync_result, State). -init([Name, - Config = #{config := HConfig = #{file:=File, - type:=Type, - max_no_bytes:=MNB, - max_no_files:=MNF}}, - State = #{dl_sync_int := DLSyncInt}]) -> - - RegName = ?name_to_reg_name(?MODULE,Name), - register(RegName, self()), - process_flag(trap_exit, true), - process_flag(message_queue_data, off_heap), - - ?init_test_hooks(), - ?start_observation(Name), - - LogOpts = #{file=>File, type=>Type, max_no_bytes=>MNB, max_no_files=>MNF}, - case open_disk_log(Name, File, Type, MNB, MNF) of - ok -> - try ets:new(Name, [public]) of - ModeTab -> - ?set_mode(ModeTab, async), - T0 = ?timestamp(), - State1 = - ?merge_with_stats(State#{ - id => Name, - mode_tab => ModeTab, - mode => async, - dl_sync => DLSyncInt, - log_opts => LogOpts, - last_qlen => 0, - last_log_ts => T0, - burst_win_ts => T0, - burst_msg_count => 0, - last_op => sync, - prev_log_result => ok, - prev_sync_result => ok, - prev_disk_log_info => undefined}), - Config1 = - Config#{config => HConfig#{handler_pid => self(), - mode_tab => ModeTab}}, - proc_lib:init_ack({ok,self(),Config1}), - gen_server:cast(self(), repeated_disk_log_sync), - case logger_h_common:unset_restart_flag(Name, ?MODULE) of - true -> - %% inform about restart - gen_server:cast(self(), {log_handler_info, - "Handler ~p restarted", - [Name]}); - false -> - %% initial start - ok - end, - gen_server:enter_loop(?MODULE, [], State1) - catch - _:Error -> - unregister(RegName), - logger_h_common:error_notify({open_disk_log,Name,Error}), - proc_lib:init_ack(Error) - end; - Error -> - unregister(RegName), - logger_h_common:error_notify({open_disk_log,Name,Error}), - proc_lib:init_ack(Error) - end. +write(Name, Mode, Bin, State) -> + Result = ?disk_log_write(Name, Mode, Bin), + maybe_notify_error(Name, log, Result, prev_log_result, State). -%% This is the synchronous log event. -handle_call({log, Bin}, _From, State) -> - {Result,State1} = do_log(Bin, call, State), - %% Result == ok | dropped - {reply, Result, State1}; - -handle_call(disk_log_sync, _From, State = #{id := Name}) -> - State1 = #{prev_sync_result := Result} = disk_log_sync(Name, State), - {reply, Result, State1}; - -handle_call({change_config,_OldConfig,NewConfig}, _From, - State = #{filesync_repeat_interval := FSyncInt0}) -> - HConfig = maps:get(config, NewConfig, #{}), - State1 = #{sync_mode_qlen := SMQL, - drop_mode_qlen := DMQL, - flush_qlen := FQL} = maps:merge(State, HConfig), - case logger_h_common:overload_levels_ok(State1) of - true -> - _ = - case maps:get(filesync_repeat_interval, HConfig, undefined) of - undefined -> - ok; - no_repeat -> - _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref, - State, - undefined)); - FSyncInt0 -> - ok; - _FSyncInt1 -> - _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref, - State, - undefined)), - _ = gen_server:cast(self(), repeated_disk_log_sync) - end, - {reply, ok, State1}; - false -> - {reply, {error,{invalid_levels,{SMQL,DMQL,FQL}}}, State} - end; - -handle_call(info, _From, State) -> - {reply, State, State}; - -handle_call(reset, _From, State) -> - State1 = ?merge_with_stats(State), - {reply, ok, State1#{last_qlen => 0, - last_log_ts => ?timestamp(), - prev_log_result => ok, - prev_sync_result => ok, - prev_disk_log_info => undefined}}; - -handle_call(stop, _From, State) -> - {stop, {shutdown,stopped}, ok, State}. - - -%% This is the asynchronous log event. -handle_cast({log, Bin}, State) -> - {_,State1} = do_log(Bin, cast, State), - {noreply, State1}; - -handle_cast({log_handler_info, Format, Args}, State = #{id:=Name}) -> - log_handler_info(Name, Format, Args, State), - {noreply, State}; - -%% If FILESYNC_REPEAT_INTERVAL is set to a millisec value, this -%% clause gets called repeatedly by the handler. In order to -%% guarantee that a filesync *always* happens after the last log -%% event, the repeat operation must be active! -handle_cast(repeated_disk_log_sync, - State = #{id := Name, - filesync_repeat_interval := FSyncInt, - last_op := LastOp}) -> - State1 = - if is_integer(FSyncInt) -> - %% only do filesync if something has been - %% written since last time we checked - NewState = if LastOp == sync -> - State; - true -> - disk_log_sync(Name, State) - end, - {ok,TRef} = - timer:apply_after(FSyncInt, gen_server,cast, - [self(),repeated_disk_log_sync]), - NewState#{rep_sync_tref => TRef, last_op => sync}; - true -> - State - end, - {noreply,State1}. +reset_state(_Name, State) -> + State#{prev_log_result => ok, + prev_sync_result => ok, + prev_disk_log_info => undefined}. %% The disk log owner must handle status messages from disk_log. -handle_info({disk_log, _Node, _Log, {wrap,_NoLostItems}}, State) -> - {noreply, State}; -handle_info({disk_log, _Node, Log, Info = {truncated,_NoLostItems}}, - State = #{id := Name, prev_disk_log_info := PrevInfo}) -> - error_notify_new(Info, PrevInfo, {disk_log,Name,Log,Info}), - {noreply, State#{prev_disk_log_info => Info}}; -handle_info({disk_log, _Node, Log, Info = {blocked_log,_Items}}, - State = #{id := Name, prev_disk_log_info := PrevInfo}) -> - error_notify_new(Info, PrevInfo, {disk_log,Name,Log,Info}), - {noreply, State#{prev_disk_log_info => Info}}; -handle_info({disk_log, _Node, Log, full}, - State = #{id := Name, prev_disk_log_info := PrevInfo}) -> - error_notify_new(full, PrevInfo, {disk_log,Name,Log,full}), - {noreply, State#{prev_disk_log_info => full}}; -handle_info({disk_log, _Node, Log, Info = {error_status,_Status}}, - State = #{id := Name, prev_disk_log_info := PrevInfo}) -> - error_notify_new(Info, PrevInfo, {disk_log,Name,Log,Info}), - {noreply, State#{prev_disk_log_info => Info}}; - -handle_info({'EXIT',_Pid,_Why}, State = #{id := _Name}) -> - {noreply, State}; - -handle_info(_, State) -> - {noreply, State}. - -terminate(Reason, State = #{id := Name}) -> - _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref, State, - undefined)), +handle_info(Name, {disk_log, _Node, Log, Info={truncated,_NoLostItems}}, State) -> + maybe_notify_status(Name, Log, Info, prev_disk_log_info, State); +handle_info(Name, {disk_log, _Node, Log, Info = {blocked_log,_Items}}, State) -> + maybe_notify_status(Name, Log, Info, prev_disk_log_info, State); +handle_info(Name, {disk_log, _Node, Log, Info = full}, State) -> + maybe_notify_status(Name, Log, Info, prev_disk_log_info, State); +handle_info(Name, {disk_log, _Node, Log, Info = {error_status,_Status}}, State) -> + maybe_notify_status(Name, Log, Info, prev_disk_log_info, State); +handle_info(_, _, State) -> + State. + +terminate(Name, _Reason, _State) -> _ = close_disk_log(Name, normal), - ok = logger_h_common:stop_or_restart(Name, Reason, State), - unregister(?name_to_reg_name(?MODULE, Name)), ok. -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - %%%----------------------------------------------------------------- %%% Internal functions - -%%%----------------------------------------------------------------- -%%% -get_default_config() -> - #{sync_mode_qlen => ?SYNC_MODE_QLEN, - drop_mode_qlen => ?DROP_MODE_QLEN, - flush_qlen => ?FLUSH_QLEN, - burst_limit_enable => ?BURST_LIMIT_ENABLE, - burst_limit_max_count => ?BURST_LIMIT_MAX_COUNT, - burst_limit_window_time => ?BURST_LIMIT_WINDOW_TIME, - overload_kill_enable => ?OVERLOAD_KILL_ENABLE, - overload_kill_qlen => ?OVERLOAD_KILL_QLEN, - overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE, - overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER, - filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}. - -get_init_state() -> - #{dl_sync_int => ?CONTROLLER_SYNC_INTERVAL, - filesync_ok_qlen => ?FILESYNC_OK_QLEN}. - -%%%----------------------------------------------------------------- -%%% Add a disk_log handler to the logger. -%%% This starts a dedicated handler process which should always -%%% exist if the handler is registered with logger (and should not -%%% exist if the handler is not registered). -%%% -%%% Config is the logger:handler_config() map. Handler specific parameters -%%% should be provided with a sub map associated with a key named -%%% 'config', e.g: -%%% -%%% Config = #{config => #{sync_mode_qlen => 50} -%%% -%%% The 'config' sub map will also contain parameters for configuring -%%% the disk_log: -%%% -%%% Config = #{config => #{file => file:filename(), -%%% max_no_bytes => integer(), -%%% max_no_files => integer(), -%%% type => wrap | halt}}. -%%% -%%% If type == halt, then max_no_files is ignored. -%%% -%%% The disk_log handler process is linked to logger_sup, which is -%%% part of the kernel application's supervision tree. -start(Name, Config, HandlerState) -> - LoggerDLH = - #{id => Name, - start => {?MODULE, start_link, [Name,Config,HandlerState]}, - restart => temporary, - shutdown => 2000, - type => worker, - modules => [?MODULE]}, - case supervisor:start_child(logger_sup, LoggerDLH) of - {ok,Pid,Config1} -> - ok = logger_handler_watcher:register_handler(Name,Pid), - {ok,Config1}; - Error -> - Error - end. - -%%%----------------------------------------------------------------- -%%% Stop and remove the handler. -stop(Name) -> - case whereis(?name_to_reg_name(?MODULE,Name)) of - undefined -> - ok; - Pid -> - %% We don't want to do supervisor:terminate_child here - %% since we need to distinguish this explicit stop from a - %% system termination in order to avoid circular attempts - %% at removing the handler (implying deadlocks and - %% timeouts). - %% And we don't need to do supervisor:delete_child, since - %% the restart type is temporary, which means that the - %% child specification is automatically removed from the - %% supervisor when the process dies. - _ = gen_server:call(Pid, stop), - ok - end. - -%%%----------------------------------------------------------------- -%%% Logging and overload control. --define(update_dl_sync(C, Interval), - if C == 0 -> Interval; - true -> C-1 end). - -%% check for overload between every event (and set Mode to async, -%% sync or drop accordingly), but never flush the whole mailbox -%% before LogWindowSize events have been handled -do_log(Bin, CallOrCast, State = #{id:=Name, mode := Mode0}) -> - T1 = ?timestamp(), - - %% check if the handler is getting overloaded, or if it's - %% recovering from overload (the check must be done for each - %% event to react quickly to large bursts of events and - %% to ensure that the handler can never end up in drop mode - %% with an empty mailbox, which would stop operation) - {Mode1,QLen,Mem,State1} = logger_h_common:check_load(State), - - if (Mode1 == drop) andalso (Mode0 =/= drop) -> - log_handler_info(Name, "Handler ~p switched to drop mode", - [Name], State); - (Mode0 == drop) andalso ((Mode1 == async) orelse (Mode1 == sync)) -> - log_handler_info(Name, "Handler ~p switched to ~w mode", - [Name,Mode1], State); - true -> - ok - end, - - %% kill the handler if it can't keep up with the load - logger_h_common:kill_if_choked(Name, QLen, Mem, ?MODULE, State), - - if Mode1 == flush -> - flush(Name, QLen, T1, State1); - true -> - write(Name, Mode1, T1, Bin, CallOrCast, State1) - end. - -%% this function is called by do_log/3 after an overload check -%% has been performed, where QLen > FlushQLen -flush(Name, _QLen0, T1, State=#{last_log_ts := _T0, mode_tab := ModeTab}) -> - %% flush messages in the mailbox (a limited number in - %% order to not cause long delays) - NewFlushed = logger_h_common:flush_log_events(?FLUSH_MAX_N), - - %% write info in log about flushed messages - log_handler_info(Name, "Handler ~p flushed ~w log events", - [Name,NewFlushed], State), - - %% because of the receive loop when flushing messages, the - %% handler will be scheduled out often and the mailbox could - %% grow very large, so we'd better check the queue again here - {_,_QLen1} = process_info(self(), message_queue_len), - ?observe(Name,{max_qlen,_QLen1}), - - %% Add 1 for the current log event - ?observe(Name,{flushed,NewFlushed+1}), - - State1 = ?update_max_time(?diff_time(T1,_T0),State), - {dropped,?update_other(flushed,FLUSHED,NewFlushed, - State1#{mode => ?set_mode(ModeTab,async), - last_qlen => 0, - last_log_ts => T1})}. - -%% this function is called to write to disk_log -write(Name, Mode, T1, Bin, _CallOrCast, - State = #{mode_tab := ModeTab, - dl_sync := DLSync, - dl_sync_int := DLSyncInt, - last_qlen := LastQLen, - last_log_ts := T0}) -> - %% check if we need to limit the number of writes - %% during a burst of log events - {DoWrite,BurstWinT,BurstMsgCount} = logger_h_common:limit_burst(State), - - %% only send a synhrounous event to the disk_log process - %% every DLSyncInt time, to give the handler time between - %% writes so it can keep up with incoming messages - {Status,LastQLen1,State1} = - if DoWrite, DLSync == 0 -> - ?observe(Name,{_CallOrCast,1}), - NewState = disk_log_write(Name, Bin, State), - {ok, element(2,process_info(self(),message_queue_len)), - NewState}; - DoWrite -> - ?observe(Name,{_CallOrCast,1}), - NewState = disk_log_write(Name, Bin, State), - {ok, LastQLen, NewState}; - not DoWrite -> - ?observe(Name,{flushed,1}), - {dropped, LastQLen, State} - end, - - %% Check if the time since the previous log event is long enough - - %% and the queue length small enough - to assume the mailbox has - %% been emptied, and if so, do filesync operation and reset mode to - %% async. Note that this is the best we can do to detect an idle - %% handler without setting a timer after each log call/cast. If the - %% time between two consecutive log events is fast and no new - %% event comes in after the last one, idle state won't be detected! - Time = ?diff_time(T1,T0), - {Mode1,BurstMsgCount1,State2} = - if (LastQLen1 < ?FILESYNC_OK_QLEN) andalso - (Time > ?IDLE_DETECT_TIME_USEC) -> - {?change_mode(ModeTab,Mode,async), 0, disk_log_sync(Name,State1)}; - true -> - {Mode, BurstMsgCount,State1} - end, - - State3 = - ?update_calls_or_casts(_CallOrCast,1,State2), - State4 = - ?update_max_time(Time, - State3#{mode => Mode1, - last_qlen := LastQLen1, - last_log_ts => T1, - burst_win_ts => BurstWinT, - burst_msg_count => BurstMsgCount1, - dl_sync => ?update_dl_sync(DLSync,DLSyncInt)}), - {Status,State4}. - - -log_handler_info(Name, Format, Args, State) -> - Config = - case logger:get_handler_config(Name) of - {ok,Conf} -> Conf; - _ -> #{formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}} - end, - Meta = #{time=>erlang:system_time(microsecond)}, - Bin = logger_h_common:log_to_binary(#{level => notice, - msg => {Format,Args}, - meta => Meta}, Config), - _ = disk_log_write(Name, Bin, State), - ok. - - open_disk_log(Name, File, Type, MaxNoBytes, MaxNoFiles) -> case filelib:ensure_dir(File) of ok -> @@ -698,43 +246,26 @@ close_disk_log(Name, _) -> _ = disk_log:lclose(Name), ok. -disk_log_write(Name, Bin, State) -> - case ?disk_log_blog(Name, Bin) of - ok -> - State#{prev_log_result => ok, last_op => write}; - LogError -> - _ = case maps:get(prev_log_result, State) of - LogError -> - %% don't report same error twice - ok; - _ -> - LogOpts = maps:get(log_opts, State), - logger_h_common:error_notify({Name,log, - LogOpts, - LogError}) - end, - State#{prev_log_result => LogError} - end. - -disk_log_sync(Name, State) -> - case ?disk_log_sync(Name) of - ok -> - State#{prev_sync_result => ok, last_op => sync}; - SyncError -> - _ = case maps:get(prev_sync_result, State) of - SyncError -> - %% don't report same error twice - ok; - _ -> - LogOpts = maps:get(log_opts, State), - logger_h_common:error_notify({Name,filesync, - LogOpts, - SyncError}) - end, - State#{prev_sync_result => SyncError} - end. +disk_log_write(Name, sync, Bin) -> + disk_log:blog(Name, Bin); +disk_log_write(Name, async, Bin) -> + disk_log:balog(Name, Bin). + +%%%----------------------------------------------------------------- +%%% Print error messages, but don't repeat the same message +maybe_notify_error(Name, Op, Result, Key, #{log_opts:=LogOpts}=State) -> + {Result,error_notify_new({Name, Op, LogOpts, Result}, Result, Key, State)}. -error_notify_new(Info,Info, _Term) -> +maybe_notify_status(Name, Log, Info, Key, State) -> + error_notify_new({disk_log, Name, Log, Info}, Info, Key, State). + +error_notify_new(Term, What, Key, State) -> + error_notify_new(What, maps:get(Key,State), Term), + State#{Key => What}. + +error_notify_new(ok,_Prev,_Term) -> + ok; +error_notify_new(Same,Same,_Term) -> ok; -error_notify_new(_Info0,_Info1, Term) -> +error_notify_new(_New,_Prev,Term) -> logger_h_common:error_notify(Term). diff --git a/lib/kernel/src/logger_h_common.erl b/lib/kernel/src/logger_h_common.erl index 94c640cb92..74a2d158fc 100644 --- a/lib/kernel/src/logger_h_common.erl +++ b/lib/kernel/src/logger_h_common.erl @@ -18,26 +18,469 @@ %% %CopyrightEnd% %% -module(logger_h_common). +-behaviour(gen_server). -include("logger_h_common.hrl"). -include("logger_internal.hrl"). --export([log_to_binary/2, - check_common_config/1, - call_cast_or_drop/4, - check_load/1, - limit_burst/1, - kill_if_choked/5, - flush_log_events/0, - flush_log_events/1, - handler_exit/2, - set_restart_flag/2, - unset_restart_flag/2, - cancel_timer/1, - stop_or_restart/3, - overload_levels_ok/1, - error_notify/1, - info_notify/1]). +%% API +-export([start_link/1, info/2, filesync/2, reset/2]). + +%% gen_server and proc_lib callbacks +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, + terminate/2, code_change/3]). + +%% logger callbacks +-export([log/2, adding_handler/1, removing_handler/1, changing_config/3, + filter_config/1]). + +%% Library functions for handlers +-export([error_notify/1]). + +%%%----------------------------------------------------------------- +-define(CONFIG_KEYS,[sync_mode_qlen, + drop_mode_qlen, + flush_qlen, + burst_limit_enable, + burst_limit_max_count, + burst_limit_window_time, + overload_kill_enable, + overload_kill_qlen, + overload_kill_mem_size, + overload_kill_restart_after, + filesync_repeat_interval]). +-define(READ_ONLY_KEYS,[handler_pid,mode_tab]). + +%%%----------------------------------------------------------------- +%%% API + +%% This function is called by the logger_sup supervisor +start_link(Args) -> + proc_lib:start_link(?MODULE,init,[Args]). + +filesync(Module, Name) -> + call(Module, Name, filesync). + +info(Module, Name) -> + call(Module, Name, info). + +reset(Module, Name) -> + call(Module, Name, reset). + +%%%----------------------------------------------------------------- +%%% Handler being added +adding_handler(#{id:=Name,module:=Module}=Config) -> + HConfig0 = maps:get(config, Config, #{}), + HandlerConfig0 = maps:without(?CONFIG_KEYS,HConfig0), + case Module:check_config(Name,set,undefined,HandlerConfig0) of + {ok,HandlerConfig} -> + ModifiedCommon = maps:with(?CONFIG_KEYS,HandlerConfig), + CommonConfig0 = maps:with(?CONFIG_KEYS,HConfig0), + CommonConfig = maps:merge( + maps:merge(get_default_config(), CommonConfig0), + ModifiedCommon), + case check_config(CommonConfig) of + ok -> + HConfig = maps:merge(CommonConfig,HandlerConfig), + start(Config#{config => HConfig}); + {error,Faulty} -> + {error,{invalid_config,Module,Faulty}} + end; + Error -> + Error + end. + +%%%----------------------------------------------------------------- +%%% Handler being removed +removing_handler(#{id:=Name, module:=Module}) -> + case whereis(?name_to_reg_name(Module,Name)) of + undefined -> + ok; + Pid -> + %% We don't want to do supervisor:terminate_child here + %% since we need to distinguish this explicit stop from a + %% system termination in order to avoid circular attempts + %% at removing the handler (implying deadlocks and + %% timeouts). + %% And we don't need to do supervisor:delete_child, since + %% the restart type is temporary, which means that the + %% child specification is automatically removed from the + %% supervisor when the process dies. + _ = gen_server:call(Pid, stop), + ok + end. + +%%%----------------------------------------------------------------- +%%% Updating handler config +changing_config(SetOrUpdate, + #{id:=Name,config:=OldHConfig,module:=Module}, + NewConfig0) -> + NewHConfig0 = maps:get(config, NewConfig0, #{}), + OldHandlerConfig = maps:without(?CONFIG_KEYS++?READ_ONLY_KEYS,OldHConfig), + NewHandlerConfig0 = maps:without(?CONFIG_KEYS++?READ_ONLY_KEYS,NewHConfig0), + case Module:check_config(Name, SetOrUpdate, + OldHandlerConfig,NewHandlerConfig0) of + {ok, NewHandlerConfig} -> + ModifiedCommon = maps:with(?CONFIG_KEYS,NewHandlerConfig), + NewCommonConfig0 = maps:with(?CONFIG_KEYS,NewHConfig0), + CommonDefault = + case SetOrUpdate of + set -> + get_default_config(); + update -> + maps:with(?CONFIG_KEYS,OldHConfig) + end, + NewCommonConfig = maps:merge( + maps:merge(CommonDefault,NewCommonConfig0), + ModifiedCommon), + case check_config(NewCommonConfig) of + ok -> + ReadOnly = maps:with(?READ_ONLY_KEYS,OldHConfig), + NewHConfig = maps:merge( + maps:merge(NewCommonConfig,NewHandlerConfig), + ReadOnly), + NewConfig = NewConfig0#{config=>NewHConfig}, + HPid = maps:get(handler_pid,OldHConfig), + case call(HPid, {change_config,NewConfig}) of + ok -> {ok,NewConfig}; + Error -> Error + end; + {error,Faulty} -> + {error,{invalid_config,Module,Faulty}} + end; + Error -> + Error + end. + +%%%----------------------------------------------------------------- +%%% Log a string or report +-spec log(LogEvent, Config) -> ok when + LogEvent :: logger:log_event(), + Config :: logger:handler_config(). + +log(LogEvent, Config = #{id := Name, + config := #{handler_pid := HPid, + mode_tab := ModeTab}}) -> + %% if the handler has crashed, we must drop this event + %% and hope the handler restarts so we can try again + true = is_process_alive(HPid), + Bin = log_to_binary(LogEvent, Config), + call_cast_or_drop(Name, HPid, ModeTab, Bin). + +%%%----------------------------------------------------------------- +%%% Remove internal fields from configuration +filter_config(#{config:=HConfig}=Config) -> + Config#{config=>maps:without(?READ_ONLY_KEYS,HConfig)}. + +%%%----------------------------------------------------------------- +%%% Start the handler process +%%% +%%% The process must always exist if the handler is registered with +%%% logger (and must not exist if the handler is not registered). +%%% +%%% The handler process is linked to logger_sup, which is part of the +%%% kernel application's supervision tree. +start(#{id := Name} = Config0) -> + ChildSpec = + #{id => Name, + start => {?MODULE, start_link, [Config0]}, + restart => temporary, + shutdown => 2000, + type => worker, + modules => [?MODULE]}, + case supervisor:start_child(logger_sup, ChildSpec) of + {ok,Pid,Config} -> + ok = logger_handler_watcher:register_handler(Name,Pid), + {ok,Config}; + Error -> + Error + end. + +%%%=================================================================== +%%% gen_server callbacks +%%%=================================================================== + +init(#{id := Name, module := Module, + formatter := Formatter, config := HConfig0} = Config0) -> + RegName = ?name_to_reg_name(Module,Name), + register(RegName, self()), + process_flag(trap_exit, true), + process_flag(message_queue_data, off_heap), + + ?init_test_hooks(), + ?start_observation(Name), + + case Module:init(Name, HConfig0) of + {ok,HState} -> + try ets:new(Name, [public]) of + ModeTab -> + ?set_mode(ModeTab, async), + T0 = ?timestamp(), + HConfig = HConfig0#{handler_pid => self(), + mode_tab => ModeTab}, + Config = Config0#{config => HConfig}, + proc_lib:init_ack({ok,self(),Config}), + %% Storing common config in state to avoid copying + %% (sending) the config data for each log message + CommonConfig = maps:with(?CONFIG_KEYS,HConfig), + State = + ?merge_with_stats( + CommonConfig#{id => Name, + module => Module, + mode_tab => ModeTab, + mode => async, + ctrl_sync_count => + ?CONTROLLER_SYNC_INTERVAL, + last_qlen => 0, + last_log_ts => T0, + last_op => sync, + burst_win_ts => T0, + burst_msg_count => 0, + formatter => Formatter, + handler_state => HState}), + State1 = set_repeated_filesync(State), + unset_restart_flag(State1), + gen_server:enter_loop(?MODULE, [], State1) + catch + _:Error -> + unregister(RegName), + error_notify({init_handler,Name,Error}), + proc_lib:init_ack(Error) + end; + Error -> + unregister(RegName), + error_notify({init_handler,Name,Error}), + proc_lib:init_ack(Error) + end. + +%% This is the synchronous log event. +handle_call({log, Bin}, _From, State) -> + {Result,State1} = do_log(Bin, call, State), + %% Result == ok | dropped + {reply,Result, State1}; + +handle_call(filesync, _From, State = #{id := Name, + module := Module, + handler_state := HandlerState}) -> + {Result,HandlerState1} = Module:filesync(Name,sync,HandlerState), + {reply, Result, State#{handler_state=>HandlerState1, last_op=>sync}}; + +handle_call({change_config, #{formatter:=Formatter, config:=NewHConfig}}, _From, + State = #{filesync_repeat_interval := FSyncInt0}) -> + %% In the future, if handler_state must be updated due to config + %% change, then we need to add a callback to Module here. + CommonConfig = maps:with(?CONFIG_KEYS,NewHConfig), + State1 = maps:merge(State, CommonConfig), + State2 = + case maps:get(filesync_repeat_interval, NewHConfig) of + FSyncInt0 -> + State1; + _FSyncInt1 -> + set_repeated_filesync(cancel_repeated_filesync(State1)) + end, + {reply, ok, State2#{formatter:=Formatter}}; + +handle_call(info, _From, State) -> + {reply, State, State}; + +handle_call(reset, _From, + #{id:=Name,module:=Module,handler_state:=HandlerState}=State) -> + State1 = ?merge_with_stats(State), + {reply, ok, State1#{last_qlen => 0, + last_log_ts => ?timestamp(), + handler_state => Module:reset_state(Name,HandlerState)}}; + +handle_call(stop, _From, State) -> + {stop, {shutdown,stopped}, ok, State}. + +%% This is the asynchronous log event. +handle_cast({log, Bin}, State) -> + {_,State1} = do_log(Bin, cast, State), + {noreply, State1}; + +%% If FILESYNC_REPEAT_INTERVAL is set to a millisec value, this +%% clause gets called repeatedly by the handler. In order to +%% guarantee that a filesync *always* happens after the last log +%% event, the repeat operation must be active! +handle_cast(repeated_filesync,State = #{filesync_repeat_interval := no_repeat}) -> + %% This clause handles a race condition which may occur when + %% config changes filesync_repeat_interval from an integer value + %% to no_repeat. + {noreply,State}; +handle_cast(repeated_filesync, + State = #{id := Name, + module := Module, + handler_state := HandlerState, + last_op := LastOp}) -> + State1 = + if LastOp == sync -> + State; + true -> + {_,HS} = Module:filesync(Name, async, HandlerState), + State#{handler_state => HS, last_op => sync} + end, + {noreply,set_repeated_filesync(State1)}. + +handle_info(Info, #{id := Name, module := Module, + handler_state := HandlerState} = State) -> + {noreply,State#{handler_state => Module:handle_info(Name,Info,HandlerState)}}. + +terminate(Reason, State = #{id := Name, + module := Module, + handler_state := HandlerState}) -> + _ = cancel_repeated_filesync(State), + _ = Module:terminate(Name, Reason, HandlerState), + ok = stop_or_restart(Name, Reason, State), + unregister(?name_to_reg_name(Module, Name)), + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + + +%%%----------------------------------------------------------------- +%%% Internal functions +call(Module, Name, Op) when is_atom(Name) -> + call(?name_to_reg_name(Module,Name), Op); +call(_, Name, Op) -> + {error,{badarg,{Op,[Name]}}}. + +call(Server, Msg) -> + try + gen_server:call(Server, Msg, ?DEFAULT_CALL_TIMEOUT) + catch + _:{timeout,_} -> {error,handler_busy} + end. + +%% check for overload between every event (and set Mode to async, +%% sync or drop accordingly), but never flush the whole mailbox +%% before LogWindowSize events have been handled +do_log(Bin, CallOrCast, State = #{id:=Name, mode:=Mode0}) -> + T1 = ?timestamp(), + + %% check if the handler is getting overloaded, or if it's + %% recovering from overload (the check must be done for each + %% event to react quickly to large bursts of events and + %% to ensure that the handler can never end up in drop mode + %% with an empty mailbox, which would stop operation) + {Mode1,QLen,Mem,State1} = check_load(State), + + if (Mode1 == drop) andalso (Mode0 =/= drop) -> + log_handler_info(Name, "Handler ~p switched to drop mode", + [Name], State); + (Mode0 == drop) andalso ((Mode1 == async) orelse (Mode1 == sync)) -> + log_handler_info(Name, "Handler ~p switched to ~w mode", + [Name,Mode1], State); + true -> + ok + end, + + %% kill the handler if it can't keep up with the load + kill_if_choked(Name, QLen, Mem, State), + + if Mode1 == flush -> + flush(Name, QLen, T1, State1); + true -> + write(Name, Mode1, T1, Bin, CallOrCast, State1) + end. + +%% this clause is called by do_log/3 after an overload check +%% has been performed, where QLen > FlushQLen +flush(Name, _QLen0, T1, State=#{last_log_ts := _T0, mode_tab := ModeTab}) -> + %% flush messages in the mailbox (a limited number in + %% order to not cause long delays) + NewFlushed = flush_log_events(?FLUSH_MAX_N), + + %% write info in log about flushed messages + log_handler_info(Name, "Handler ~p flushed ~w log events", + [Name,NewFlushed], State), + + %% because of the receive loop when flushing messages, the + %% handler will be scheduled out often and the mailbox could + %% grow very large, so we'd better check the queue again here + {_,_QLen1} = process_info(self(), message_queue_len), + ?observe(Name,{max_qlen,_QLen1}), + + %% Add 1 for the current log event + ?observe(Name,{flushed,NewFlushed+1}), + + State1 = ?update_max_time(?diff_time(T1,_T0),State), + State2 = ?update_max_qlen(_QLen1,State1), + {dropped,?update_other(flushed,FLUSHED,NewFlushed, + State2#{mode => ?set_mode(ModeTab,async), + last_qlen => 0, + last_log_ts => T1})}. + +%% this clause is called to write to file +write(Name, Mode, T1, Bin, _CallOrCast, + State = #{module := Module, + handler_state := HandlerState, + mode_tab := ModeTab, + ctrl_sync_count := CtrlSync, + last_qlen := LastQLen, + last_log_ts := T0}) -> + %% check if we need to limit the number of writes + %% during a burst of log events + {DoWrite,State1} = limit_burst(State), + + %% only log synhrounously every ?CONTROLLER_SYNC_INTERVAL time, to + %% give the handler time between writes so it can keep up with + %% incoming messages + {Result,LastQLen1,HandlerState1} = + if DoWrite, CtrlSync == 0 -> + ?observe(Name,{_CallOrCast,1}), + {_,HS1} = Module:write(Name, sync, Bin, HandlerState), + {ok,element(2, process_info(self(), message_queue_len)),HS1}; + DoWrite -> + ?observe(Name,{_CallOrCast,1}), + {_,HS1} = Module:write(Name, async, Bin, HandlerState), + {ok,LastQLen,HS1}; + not DoWrite -> + ?observe(Name,{flushed,1}), + {dropped,LastQLen,HandlerState} + end, + + %% Check if the time since the previous log event is long enough - + %% and the queue length small enough - to assume the mailbox has + %% been emptied, and if so, do filesync operation and reset mode to + %% async. Note that this is the best we can do to detect an idle + %% handler without setting a timer after each log call/cast. If the + %% time between two consecutive log events is fast and no new + %% event comes in after the last one, idle state won't be detected! + Time = ?diff_time(T1,T0), + State2 = + if (LastQLen1 < ?FILESYNC_OK_QLEN) andalso + (Time > ?IDLE_DETECT_TIME_USEC) -> + {_,HS2} = Module:filesync(Name,async,HandlerState), + State1#{mode => ?change_mode(ModeTab, Mode, async), + burst_msg_count => 0, + handler_state => HS2}; + true -> + State1#{mode => Mode, handler_state => HandlerState1} + end, + State3 = ?update_calls_or_casts(_CallOrCast,1,State2), + State4 = ?update_max_qlen(LastQLen1,State3), + State5 = + ?update_max_time(Time, + State4#{last_qlen := LastQLen1, + last_log_ts => T1, + last_op => write, + ctrl_sync_count => + if CtrlSync==0 -> ?CONTROLLER_SYNC_INTERVAL; + true -> CtrlSync-1 + end}), + {Result,State5}. + +log_handler_info(Name, Format, Args, #{module:=Module, + formatter:=Formatter, + handler_state:=HandlerState}) -> + Config = #{formatter=>Formatter}, + Meta = #{time=>erlang:system_time(microsecond)}, + Bin = log_to_binary(#{level => notice, + msg => {Format,Args}, + meta => Meta}, Config), + _ = Module:write(Name, async, Bin, HandlerState), + ok. %%%----------------------------------------------------------------- %%% Convert log data on any form to binary @@ -94,46 +537,65 @@ string_to_binary(String) -> throw(Error) end. - %%%----------------------------------------------------------------- %%% Check that the configuration term is valid -check_common_config({mode_tab,_Tid}) -> - valid; -check_common_config({handler_pid,Pid}) when is_pid(Pid) -> - valid; - -check_common_config({sync_mode_qlen,N}) when is_integer(N) -> - valid; -check_common_config({drop_mode_qlen,N}) when is_integer(N) -> - valid; -check_common_config({flush_qlen,N}) when is_integer(N) -> - valid; - -check_common_config({burst_limit_enable,Bool}) when Bool == true; - Bool == false -> - valid; -check_common_config({burst_limit_max_count,N}) when is_integer(N) -> - valid; -check_common_config({burst_limit_window_time,N}) when is_integer(N) -> - valid; - -check_common_config({overload_kill_enable,Bool}) when Bool == true; - Bool == false -> - valid; -check_common_config({overload_kill_qlen,N}) when is_integer(N) -> - valid; -check_common_config({overload_kill_mem_size,N}) when is_integer(N) -> - valid; -check_common_config({overload_kill_restart_after,NorA}) when is_integer(NorA); - NorA == infinity -> - valid; - -check_common_config({filesync_repeat_interval,NorA}) when is_integer(NorA); - NorA == no_repeat -> - valid; -check_common_config(_) -> - invalid. +check_config(Config) when is_map(Config) -> + case check_common_config(maps:to_list(Config)) of + ok -> + case overload_levels_ok(Config) of + true -> + ok; + false -> + Faulty = maps:with([sync_mode_qlen, + drop_mode_qlen, + flush_qlen],Config), + {error,{invalid_levels,Faulty}} + end; + Error -> + Error + end. + +check_common_config([{sync_mode_qlen,N}|Config]) when is_integer(N) -> + check_common_config(Config); +check_common_config([{drop_mode_qlen,N}|Config]) when is_integer(N) -> + check_common_config(Config); +check_common_config([{flush_qlen,N}|Config]) when is_integer(N) -> + check_common_config(Config); +check_common_config([{burst_limit_enable,Bool}|Config]) when is_boolean(Bool) -> + check_common_config(Config); +check_common_config([{burst_limit_max_count,N}|Config]) when is_integer(N) -> + check_common_config(Config); +check_common_config([{burst_limit_window_time,N}|Config]) when is_integer(N) -> + check_common_config(Config); +check_common_config([{overload_kill_enable,Bool}|Config]) when is_boolean(Bool) -> + check_common_config(Config); +check_common_config([{overload_kill_qlen,N}|Config]) when is_integer(N) -> + check_common_config(Config); +check_common_config([{overload_kill_mem_size,N}|Config]) when is_integer(N) -> + check_common_config(Config); +check_common_config([{overload_kill_restart_after,NorA}|Config]) + when is_integer(NorA); NorA == infinity -> + check_common_config(Config); +check_common_config([{filesync_repeat_interval,NorA}|Config]) + when is_integer(NorA); NorA == no_repeat -> + check_common_config(Config); +check_common_config([{Key,Value}|_]) -> + {error,#{Key=>Value}}; +check_common_config([]) -> + ok. +get_default_config() -> + #{sync_mode_qlen => ?SYNC_MODE_QLEN, + drop_mode_qlen => ?DROP_MODE_QLEN, + flush_qlen => ?FLUSH_QLEN, + burst_limit_enable => ?BURST_LIMIT_ENABLE, + burst_limit_max_count => ?BURST_LIMIT_MAX_COUNT, + burst_limit_window_time => ?BURST_LIMIT_WINDOW_TIME, + overload_kill_enable => ?OVERLOAD_KILL_ENABLE, + overload_kill_qlen => ?OVERLOAD_KILL_QLEN, + overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE, + overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER, + filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}. %%%----------------------------------------------------------------- %%% Overload Protection @@ -146,15 +608,13 @@ call_cast_or_drop(_Name, HandlerPid, ModeTab, Bin) -> async -> gen_server:cast(HandlerPid, {log,Bin}); sync -> - try gen_server:call(HandlerPid, {log,Bin}, ?DEFAULT_CALL_TIMEOUT) of - %% if return value from call == dropped, the - %% message has been flushed by handler and should - %% therefore not be counted as dropped in stats - ok -> ok; - dropped -> ok - catch - _:{timeout,_} -> - ?observe(_Name,{dropped,1}) + case call(HandlerPid, {log,Bin}) of + ok -> + ok; + _Other -> + %% dropped or {error,handler_busy} + ?observe(_Name,{dropped,1}), + ok end; drop -> ?observe(_Name,{dropped,1}) @@ -165,10 +625,8 @@ call_cast_or_drop(_Name, HandlerPid, ModeTab, Bin) -> end, ok. -handler_exit(_Name, Reason) -> - exit(Reason). - -set_restart_flag(Name, Module) -> +set_restart_flag(#{id := Name, module := Module} = State) -> + log_handler_info(Name, "Handler ~p overloaded and stopping", [Name], State), Flag = list_to_atom(lists:concat([Module,"_",Name,"_restarting"])), spawn(fun() -> register(Flag, self()), @@ -176,14 +634,14 @@ set_restart_flag(Name, Module) -> end), ok. -unset_restart_flag(Name, Module) -> +unset_restart_flag(#{id := Name, module := Module} = State) -> Flag = list_to_atom(lists:concat([Module,"_",Name,"_restarting"])), case whereis(Flag) of undefined -> - false; + ok; Pid -> exit(Pid, kill), - true + log_handler_info(Name, "Handler ~p restarted", [Name], State) end. check_load(State = #{id:=_Name, mode_tab := ModeTab, mode := Mode, @@ -221,46 +679,41 @@ check_load(State = #{id:=_Name, mode_tab := ModeTab, mode := Mode, ?update_other(flushes,FLUSHES,_NewFlushes, State1#{last_qlen => QLen})}. -limit_burst(#{burst_limit_enable := false}) -> - {true,0,0}; +limit_burst(#{burst_limit_enable := false}=State) -> + {true,State}; limit_burst(#{burst_win_ts := BurstWinT0, burst_msg_count := BurstMsgCount, burst_limit_window_time := BurstLimitWinTime, - burst_limit_max_count := BurstLimitMaxCnt}) -> + burst_limit_max_count := BurstLimitMaxCnt} = State) -> if (BurstMsgCount >= BurstLimitMaxCnt) -> %% the limit for allowed messages has been reached BurstWinT1 = ?timestamp(), case ?diff_time(BurstWinT1,BurstWinT0) of BurstCheckTime when BurstCheckTime < (BurstLimitWinTime*1000) -> %% we're still within the burst time frame - {false,BurstWinT0,BurstMsgCount}; + {false,?update_other(burst_drops,BURSTS,1,State)}; _BurstCheckTime -> %% burst time frame passed, reset counters - {true,BurstWinT1,0} + {true,State#{burst_win_ts => BurstWinT1, + burst_msg_count => 0}} end; true -> %% the limit for allowed messages not yet reached - {true,BurstWinT0,BurstMsgCount+1} + {true,State#{burst_win_ts => BurstWinT0, + burst_msg_count => BurstMsgCount+1}} end. -kill_if_choked(Name, QLen, Mem, HandlerMod, - State = #{overload_kill_enable := KillIfOL, - overload_kill_qlen := OLKillQLen, - overload_kill_mem_size := OLKillMem}) -> +kill_if_choked(Name, QLen, Mem, State = #{overload_kill_enable := KillIfOL, + overload_kill_qlen := OLKillQLen, + overload_kill_mem_size := OLKillMem}) -> if KillIfOL andalso ((QLen > OLKillQLen) orelse (Mem > OLKillMem)) -> - HandlerMod:log_handler_info(Name, - "Handler ~p overloaded and stopping", - [Name], State), - set_restart_flag(Name, HandlerMod), - handler_exit(Name, {shutdown,{overloaded,Name,QLen,Mem}}); + set_restart_flag(State), + exit({shutdown,{overloaded,Name,QLen,Mem}}); true -> ok end. -flush_log_events() -> - flush_log_events(-1). - flush_log_events(Limit) -> process_flag(priority, high), Flushed = flush_log_events(0, Limit), @@ -283,16 +736,29 @@ flush_log_events(N, Limit) -> 0 -> N end. -cancel_timer(TRef) when is_atom(TRef) -> ok; -cancel_timer(TRef) -> timer:cancel(TRef). +set_repeated_filesync(#{filesync_repeat_interval:=FSyncInt} = State) + when is_integer(FSyncInt) -> + {ok,TRef} = timer:apply_after(FSyncInt, gen_server, cast, + [self(),repeated_filesync]), + State#{rep_sync_tref=>TRef}; +set_repeated_filesync(State) -> + State. +cancel_repeated_filesync(State) -> + case maps:take(rep_sync_tref,State) of + {TRef,State1} -> + _ = timer:cancel(TRef), + State1; + error -> + State + end. stop_or_restart(Name, {shutdown,Reason={overloaded,_Name,_QLen,_Mem}}, #{overload_kill_restart_after := RestartAfter}) -> %% If we're terminating because of an overload situation (see - %% logger_h_common:kill_if_choked/4), we need to remove the handler - %% and set a restart timer. A separate process must perform this - %% in order to avoid deadlock. + %% kill_if_choked/4), we need to remove the handler and set a + %% restart timer. A separate process must perform this in order to + %% avoid deadlock. HandlerPid = self(), ConfigResult = logger:get_handler_config(Name), RemoveAndRestart = @@ -334,6 +800,3 @@ overload_levels_ok(HandlerConfig) -> error_notify(Term) -> ?internal_log(error, Term). - -info_notify(Term) -> - ?internal_log(info, Term). diff --git a/lib/kernel/src/logger_h_common.hrl b/lib/kernel/src/logger_h_common.hrl index e0a7b6e3ca..261b0a6246 100644 --- a/lib/kernel/src/logger_h_common.hrl +++ b/lib/kernel/src/logger_h_common.hrl @@ -137,7 +137,7 @@ ets:insert(?TEST_HOOKS_TAB, {internal_log,{logger,internal_log}}), ets:insert(?TEST_HOOKS_TAB, {file_write,ok}), ets:insert(?TEST_HOOKS_TAB, {file_datasync,ok}), - ets:insert(?TEST_HOOKS_TAB, {disk_log_blog,ok}), + ets:insert(?TEST_HOOKS_TAB, {disk_log_write,ok}), ets:insert(?TEST_HOOKS_TAB, {disk_log_sync,ok})). -define(set_internal_log(MOD_FUNC), @@ -150,7 +150,7 @@ ets:insert(?TEST_HOOKS_TAB, {internal_log,{logger,internal_log}}), ets:insert(?TEST_HOOKS_TAB, {file_write,ok}), ets:insert(?TEST_HOOKS_TAB, {file_datasync,ok}), - ets:insert(?TEST_HOOKS_TAB, {disk_log_blog,ok}), + ets:insert(?TEST_HOOKS_TAB, {disk_log_write,ok}), ets:insert(?TEST_HOOKS_TAB, {disk_log_sync,ok})). -define(internal_log(TYPE, TERM), @@ -171,11 +171,11 @@ [{_,ERROR}] -> ERROR catch _:_ -> file:datasync(DEVICE) end). - -define(disk_log_blog(LOG, DATA), - try ets:lookup(?TEST_HOOKS_TAB, disk_log_blog) of - [{_,ok}] -> disk_log:blog(LOG, DATA); + -define(disk_log_write(LOG, MODE, DATA), + try ets:lookup(?TEST_HOOKS_TAB, disk_log_write) of + [{_,ok}] -> disk_log_write(LOG, MODE, DATA); [{_,ERROR}] -> ERROR - catch _:_ -> disk_log:blog(LOG, DATA) end). + catch _:_ -> disk_log_write(LOG, MODE, DATA) end). -define(disk_log_sync(LOG), try ets:lookup(?TEST_HOOKS_TAB, disk_log_sync) of @@ -194,7 +194,7 @@ -define(internal_log(TYPE, TERM), logger:internal_log(TYPE, TERM)). -define(file_write(DEVICE, DATA), file:write(DEVICE, DATA)). -define(file_datasync(DEVICE), file:datasync(DEVICE)). - -define(disk_log_blog(LOG, DATA), disk_log:blog(LOG, DATA)). + -define(disk_log_write(LOG, MODE, DATA), disk_log_write(LOG, MODE, DATA)). -define(disk_log_sync(LOG), disk_log:sync(LOG)). -define(DEFAULT_CALL_TIMEOUT, 10000). -endif. @@ -210,7 +210,7 @@ -ifdef(SAVE_STATS). -define(merge_with_stats(STATE), STATE#{flushes => 0, flushed => 0, drops => 0, - casts => 0, calls => 0, + burst_drops => 0, casts => 0, calls => 0, max_qlen => 0, max_time => 0}). -define(update_max_qlen(QLEN, STATE), diff --git a/lib/kernel/src/logger_simple_h.erl b/lib/kernel/src/logger_simple_h.erl index 8b51dd8569..fe181722f3 100644 --- a/lib/kernel/src/logger_simple_h.erl +++ b/lib/kernel/src/logger_simple_h.erl @@ -50,7 +50,6 @@ removing_handler(#{id:=simple}) -> ok; Pid -> Ref = erlang:monitor(process,Pid), - unlink(Pid), Pid ! stop, receive {'DOWN',Ref,process,Pid,_} -> ok @@ -99,7 +98,11 @@ loop(Buffer) -> replay_buffer(Buffer); _ -> ok - end; + end, + %% Before stopping, we unlink the logger process to avoid + %% an unexpected EXIT message + unlink(whereis(logger)), + ok; {log,#{msg:=_,meta:=#{time:=_}}=Log} -> do_log(Log), loop(update_buffer(Buffer,Log)); diff --git a/lib/kernel/src/logger_std_h.erl b/lib/kernel/src/logger_std_h.erl index 42e0f5caf4..63d1dbaba2 100644 --- a/lib/kernel/src/logger_std_h.erl +++ b/lib/kernel/src/logger_std_h.erl @@ -19,8 +19,6 @@ %% -module(logger_std_h). --behaviour(gen_server). - -include("logger.hrl"). -include("logger_internal.hrl"). -include("logger_h_common.hrl"). @@ -28,52 +26,28 @@ -include_lib("kernel/include/file.hrl"). %% API --export([start_link/3, info/1, filesync/1, reset/1]). +-export([info/1, filesync/1, reset/1]). -%% gen_server and proc_lib callbacks --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). +%% logger_h_common callbacks +-export([init/2, check_config/4, reset_state/2, + filesync/3, write/4, handle_info/3, terminate/3]). %% logger callbacks -export([log/2, adding_handler/1, removing_handler/1, changing_config/3, filter_config/1]). -%% handler internal --export([log_handler_info/4]). - %%%=================================================================== %%% API %%%=================================================================== %%%----------------------------------------------------------------- -%%% Start a standard handler process and link to caller. -%%% This function is called by the kernel supervisor when this -%%% handler process gets added --spec start_link(Name, Config, HandlerState) -> {ok,Pid} | {error,Reason} when - Name :: atom(), - Config :: logger:handler_config(), - HandlerState :: map(), - Pid :: pid(), - Reason :: term(). - -start_link(Name, Config, HandlerState) -> - proc_lib:start_link(?MODULE,init,[[Name,Config,HandlerState]]). - -%%%----------------------------------------------------------------- %%% -spec filesync(Name) -> ok | {error,Reason} when Name :: atom(), Reason :: handler_busy | {badarg,term()}. -filesync(Name) when is_atom(Name) -> - try - gen_server:call(?name_to_reg_name(?MODULE,Name), - filesync, ?DEFAULT_CALL_TIMEOUT) - catch - _:{timeout,_} -> {error,handler_busy} - end; filesync(Name) -> - {error,{badarg,{filesync,[Name]}}}. + logger_h_common:filesync(?MODULE,Name). %%%----------------------------------------------------------------- %%% @@ -82,15 +56,8 @@ filesync(Name) -> Info :: term(), Reason :: handler_busy | {badarg,term()}. -info(Name) when is_atom(Name) -> - try - gen_server:call(?name_to_reg_name(?MODULE,Name), - info, ?DEFAULT_CALL_TIMEOUT) - catch - _:{timeout,_} -> {error,handler_busy} - end; info(Name) -> - {error,{badarg,{info,[Name]}}}. + logger_h_common:info(?MODULE,Name). %%%----------------------------------------------------------------- %%% @@ -98,47 +65,75 @@ info(Name) -> Name :: atom(), Reason :: handler_busy | {badarg,term()}. -reset(Name) when is_atom(Name) -> - try - gen_server:call(?name_to_reg_name(?MODULE,Name), - reset, ?DEFAULT_CALL_TIMEOUT) - catch - _:{timeout,_} -> {error,handler_busy} - end; reset(Name) -> - {error,{badarg,{reset,[Name]}}}. - + logger_h_common:reset(?MODULE,Name). %%%=================================================================== -%%% logger callbacks +%%% logger callbacks - just forward to logger_h_common %%%=================================================================== %%%----------------------------------------------------------------- %%% Handler being added -adding_handler(#{id:=Name}=Config) -> - case check_config(adding, Config) of - {ok, #{config:=HConfig}=Config1} -> - %% create initial handler state by merging defaults with config - HState = maps:merge(get_init_state(), HConfig), - case logger_h_common:overload_levels_ok(HState) of - true -> - start(Name, Config1, HState); - false -> - #{sync_mode_qlen := SMQL, - drop_mode_qlen := DMQL, - flush_qlen := FQL} = HState, - {error,{invalid_levels,{SMQL,DMQL,FQL}}} - end; +-spec adding_handler(Config) -> {ok,Config} | {error,Reason} when + Config :: logger:handler_config(), + Reason :: term(). + +adding_handler(Config) -> + logger_h_common:adding_handler(Config). + +%%%----------------------------------------------------------------- +%%% Updating handler config +-spec changing_config(SetOrUpdate, OldConfig, NewConfig) -> + {ok,Config} | {error,Reason} when + SetOrUpdate :: set | update, + OldConfig :: logger:handler_config(), + NewConfig :: logger:handler_config(), + Config :: logger:handler_config(), + Reason :: term(). + +changing_config(SetOrUpdate, OldConfig, NewConfig) -> + logger_h_common:changing_config(SetOrUpdate, OldConfig, NewConfig). + +%%%----------------------------------------------------------------- +%%% Handler being removed +-spec removing_handler(Config) -> ok when + Config :: logger:handler_config(). + +removing_handler(Config) -> + logger_h_common:removing_handler(Config). + +%%%----------------------------------------------------------------- +%%% Log a string or report +-spec log(LogEvent, Config) -> ok when + LogEvent :: logger:log_event(), + Config :: logger:handler_config(). + +log(LogEvent, Config) -> + logger_h_common:log(LogEvent, Config). + +%%%----------------------------------------------------------------- +%%% Remove internal fields from configuration +-spec filter_config(Config) -> Config when + Config :: logger:handler_config(). + +filter_config(Config) -> + logger_h_common:filter_config(Config). + +%%%=================================================================== +%%% logger_h_common callbacks +%%%=================================================================== +init(Name, #{type := Type}) -> + case open_log_file(Name, Type) of + {ok,FileCtrlPid} -> + {ok,#{type=>Type,file_ctrl_pid=>FileCtrlPid}}; Error -> Error end. -%%%----------------------------------------------------------------- -%%% Updating handler config -changing_config(SetOrUpdate,OldConfig=#{config:=OldHConfig},NewConfig) -> +check_config(_Name,set,undefined,NewHConfig) -> + check_config(maps:merge(get_default_config(),NewHConfig)); +check_config(_Name,SetOrUpdate,OldHConfig,NewHConfig0) -> WriteOnce = maps:with([type],OldHConfig), - ReadOnly = maps:with([handler_pid,mode_tab],OldHConfig), - NewHConfig0 = maps:get(config, NewConfig, #{}), Default = case SetOrUpdate of set -> @@ -148,48 +143,24 @@ changing_config(SetOrUpdate,OldConfig=#{config:=OldHConfig},NewConfig) -> OldHConfig end, - %% Allow (accidentially) included read-only fields - just overwrite them - NewHConfig = maps:merge(maps:merge(Default, NewHConfig0),ReadOnly), + NewHConfig = maps:merge(Default, NewHConfig0), - %% But fail if write-once fields are changed + %% Fail if write-once fields are changed case maps:with([type],NewHConfig) of WriteOnce -> - changing_config1(maps:get(handler_pid,OldHConfig), - OldConfig, - NewConfig#{config=>NewHConfig}); + check_config(NewHConfig); Other -> - {error,{illegal_config_change,#{config=>WriteOnce},#{config=>Other}}} + {error,{illegal_config_change,?MODULE,WriteOnce,Other}} end. -changing_config1(HPid, OldConfig, NewConfig) -> - case check_config(changing, NewConfig) of - Result = {ok,NewConfig1} -> - try gen_server:call(HPid, {change_config,OldConfig,NewConfig1}, - ?DEFAULT_CALL_TIMEOUT) of - ok -> Result; - HError -> HError - catch - _:{timeout,_} -> {error,handler_busy} - end; - Error -> - Error - end. - -check_config(adding, Config) -> - %% Merge in defaults on handler level - HConfig0 = maps:get(config, Config, #{}), - HConfig = maps:merge(get_default_config(),HConfig0), +check_config(#{type:=Type}=HConfig) -> case check_h_config(maps:to_list(HConfig)) of + ok when is_atom(Type) -> + {ok,HConfig#{filesync_repeat_interval=>no_repeat}}; ok -> - {ok,Config#{config=>HConfig}}; - Error -> - Error - end; -check_config(changing, Config) -> - HConfig = maps:get(config, Config, #{}), - case check_h_config(maps:to_list(HConfig)) of - ok -> {ok,Config}; - Error -> Error + {ok,HConfig}; + {error,{Key,Value}} -> + {error,{invalid_config,?MODULE,#{Key=>Value}}} end. check_h_config([{type,Type} | Config]) when Type == standard_io; @@ -200,219 +171,40 @@ check_h_config([{type,{file,File}} | Config]) when is_list(File) -> check_h_config([{type,{file,File,Modes}} | Config]) when is_list(File), is_list(Modes) -> check_h_config(Config); -check_h_config([Other | Config]) -> - case logger_h_common:check_common_config(Other) of - valid -> - check_h_config(Config); - invalid -> - {error,{invalid_config,?MODULE,Other}} - end; +check_h_config([Other | _]) -> + {error,Other}; check_h_config([]) -> ok. - -%%%----------------------------------------------------------------- -%%% Handler being removed -removing_handler(#{id:=Name}) -> - stop(Name). - -%%%----------------------------------------------------------------- -%%% Log a string or report --spec log(LogEvent, Config) -> ok when - LogEvent :: logger:log_event(), - Config :: logger:handler_config(). - -log(LogEvent, Config = #{id := Name, - config := #{handler_pid := HPid, - mode_tab := ModeTab}}) -> - %% if the handler has crashed, we must drop this event - %% and hope the handler restarts so we can try again - true = is_process_alive(HPid), - Bin = logger_h_common:log_to_binary(LogEvent, Config), - logger_h_common:call_cast_or_drop(Name, HPid, ModeTab, Bin). - -%%%----------------------------------------------------------------- -%%% Remove internal fields from configuration -filter_config(#{config:=HConfig}=Config) -> - Config#{config=>maps:without([handler_pid,mode_tab],HConfig)}. - -%%%=================================================================== -%%% gen_server callbacks -%%%=================================================================== - -init([Name, Config = #{config := HConfig}, - State0 = #{type := Type, file_ctrl_sync_int := FileCtrlSyncInt}]) -> - RegName = ?name_to_reg_name(?MODULE,Name), - register(RegName, self()), - process_flag(trap_exit, true), - process_flag(message_queue_data, off_heap), - - ?init_test_hooks(), - ?start_observation(Name), - - case do_init(Name, Type) of - {ok,InitState} -> - try ets:new(Name, [public]) of - ModeTab -> - ?set_mode(ModeTab, async), - State = maps:merge(State0, InitState), - T0 = ?timestamp(), - State1 = - ?merge_with_stats(State#{ - mode_tab => ModeTab, - mode => async, - file_ctrl_sync => FileCtrlSyncInt, - last_qlen => 0, - last_log_ts => T0, - last_op => sync, - burst_win_ts => T0, - burst_msg_count => 0}), - Config1 = - Config#{config => HConfig#{handler_pid => self(), - mode_tab => ModeTab}}, - proc_lib:init_ack({ok,self(),Config1}), - gen_server:cast(self(), repeated_filesync), - gen_server:enter_loop(?MODULE, [], State1) - catch - _:Error -> - unregister(RegName), - logger_h_common:error_notify({init_handler,Name,Error}), - proc_lib:init_ack(Error) - end; - Error -> - unregister(RegName), - logger_h_common:error_notify({init_handler,Name,Error}), - proc_lib:init_ack(Error) - end. - -do_init(Name, Type) -> - case open_log_file(Name, Type) of - {ok,FileCtrlPid} -> - case logger_h_common:unset_restart_flag(Name, ?MODULE) of - true -> - %% inform about restart - gen_server:cast(self(), {log_handler_info, - "Handler ~p restarted", - [Name]}); - false -> - %% initial start - ok - end, - {ok,#{id=>Name,type=>Type,file_ctrl_pid=>FileCtrlPid}}; - Error -> - Error - end. - -%% This is the synchronous log event. -handle_call({log, Bin}, _From, State) -> - {Result,State1} = do_log(Bin, call, State), - %% Result == ok | dropped - {reply,Result, State1}; - -handle_call(filesync, _From, State = #{type := Type, - file_ctrl_pid := FileCtrlPid}) -> - if is_atom(Type) -> - {reply, ok, State}; - true -> - {reply, file_ctrl_filesync_sync(FileCtrlPid), State#{last_op=>sync}} - end; - -handle_call({change_config,_OldConfig,NewConfig}, _From, - State = #{filesync_repeat_interval := FSyncInt0}) -> - HConfig = maps:get(config, NewConfig, #{}), - State1 = maps:merge(State, HConfig), - case logger_h_common:overload_levels_ok(State1) of - true -> - _ = - case maps:get(filesync_repeat_interval, HConfig, undefined) of - undefined -> - ok; - no_repeat -> - _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref, - State, - undefined)); - FSyncInt0 -> - ok; - _FSyncInt1 -> - _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref, - State, - undefined)), - gen_server:cast(self(), repeated_filesync) - end, - {reply, ok, State1}; - false -> - #{sync_mode_qlen := SMQL, - drop_mode_qlen := DMQL, - flush_qlen := FQL} = State1, - {reply, {error,{invalid_levels,{SMQL,DMQL,FQL}}}, State} - end; - -handle_call(info, _From, State) -> - {reply, State, State}; - -handle_call(reset, _From, State) -> - State1 = ?merge_with_stats(State), - {reply, ok, State1#{last_qlen => 0, - last_log_ts => ?timestamp()}}; - -handle_call(stop, _From, State) -> - {stop, {shutdown,stopped}, ok, State}. - -%% This is the asynchronous log event. -handle_cast({log, Bin}, State) -> - {_,State1} = do_log(Bin, cast, State), - {noreply, State1}; - -handle_cast({log_handler_info, Format, Args}, State = #{id:=Name}) -> - log_handler_info(Name, Format, Args, State), - {noreply, State}; - -%% If FILESYNC_REPEAT_INTERVAL is set to a millisec value, this -%% clause gets called repeatedly by the handler. In order to -%% guarantee that a filesync *always* happens after the last log -%% event, the repeat operation must be active! -handle_cast(repeated_filesync, - State = #{type := Type, - file_ctrl_pid := FileCtrlPid, - filesync_repeat_interval := FSyncInt, - last_op := LastOp}) -> - State1 = - if not is_atom(Type), is_integer(FSyncInt) -> - %% only do filesync if something has been - %% written since last time we checked - if LastOp == sync -> - ok; - true -> - file_ctrl_filesync_async(FileCtrlPid) - end, - {ok,TRef} = - timer:apply_after(FSyncInt, gen_server,cast, - [self(),repeated_filesync]), - State#{rep_sync_tref => TRef, last_op => sync}; - true -> - State - end, - {noreply,State1}. - -handle_info({'EXIT',Pid,Why}, State = #{id := Name, type := FileInfo}) -> - case maps:get(file_ctrl_pid, State, undefined) of - Pid -> - %% file error, terminate handler - logger_h_common:handler_exit(Name, - {error,{write_failed,FileInfo,Why}}); - _Other -> - %% ignore EXIT - ok - end, - {noreply, State}; - -handle_info(_Info, State) -> - {noreply, State}. - -terminate(Reason, State = #{id:=Name, file_ctrl_pid:=FWPid, - type:=_FileInfo}) -> - _ = logger_h_common:cancel_timer(maps:get(rep_sync_tref, State, - undefined)), +get_default_config() -> + #{type => standard_io}. + +filesync(_Name, _Mode, #{type := Type}=State) when is_atom(Type) -> + {ok,State}; +filesync(_Name, async, #{file_ctrl_pid := FileCtrlPid} = State) -> + ok = file_ctrl_filesync_async(FileCtrlPid), + {ok,State}; +filesync(_Name, sync, #{file_ctrl_pid := FileCtrlPid} = State) -> + Result = file_ctrl_filesync_sync(FileCtrlPid), + {Result,State}. + +write(_Name, async, Bin, #{file_ctrl_pid:=FileCtrlPid} = State) -> + ok = file_write_async(FileCtrlPid, Bin), + {ok,State}; +write(_Name, sync, Bin, #{file_ctrl_pid:=FileCtrlPid} = State) -> + Result = file_write_sync(FileCtrlPid, Bin), + {Result,State}. + +reset_state(_Name, State) -> + State. + +handle_info(_Name, {'EXIT',Pid,Why}, #{type := FileInfo, file_ctrl_pid := Pid}) -> + %% file_ctrl_pid died, file error, terminate handler + exit({error,{write_failed,FileInfo,Why}}); +handle_info(_, _, State) -> + State. + +terminate(_Name, _Reason, #{file_ctrl_pid:=FWPid}) -> case is_process_alive(FWPid) of true -> unlink(FWPid), @@ -423,17 +215,12 @@ terminate(Reason, State = #{id:=Name, file_ctrl_pid:=FWPid, ok after ?DEFAULT_CALL_TIMEOUT -> - exit(FWPid, kill) + exit(FWPid, kill), + ok end; false -> ok - end, - ok = logger_h_common:stop_or_restart(Name, Reason, State), - unregister(?name_to_reg_name(?MODULE, Name)), - ok. - -code_change(_OldVsn, State, _Extra) -> - {ok, State}. + end. %%%=================================================================== %%% Internal functions @@ -441,203 +228,6 @@ code_change(_OldVsn, State, _Extra) -> %%%----------------------------------------------------------------- %%% -get_default_config() -> - #{type => standard_io, - sync_mode_qlen => ?SYNC_MODE_QLEN, - drop_mode_qlen => ?DROP_MODE_QLEN, - flush_qlen => ?FLUSH_QLEN, - burst_limit_enable => ?BURST_LIMIT_ENABLE, - burst_limit_max_count => ?BURST_LIMIT_MAX_COUNT, - burst_limit_window_time => ?BURST_LIMIT_WINDOW_TIME, - overload_kill_enable => ?OVERLOAD_KILL_ENABLE, - overload_kill_qlen => ?OVERLOAD_KILL_QLEN, - overload_kill_mem_size => ?OVERLOAD_KILL_MEM_SIZE, - overload_kill_restart_after => ?OVERLOAD_KILL_RESTART_AFTER, - filesync_repeat_interval => ?FILESYNC_REPEAT_INTERVAL}. - -get_init_state() -> - #{file_ctrl_sync_int => ?CONTROLLER_SYNC_INTERVAL, - filesync_ok_qlen => ?FILESYNC_OK_QLEN}. - -%%%----------------------------------------------------------------- -%%% Add a standard handler to the logger. -%%% This starts a dedicated handler process which should always -%%% exist if the handler is registered with logger (and should not -%%% exist if the handler is not registered). -%%% -%%% Handler specific config should be provided with a sub map associated -%%% with a key named 'config', e.g: -%%% -%%% Config = #{config => #{sync_mode_qlen => 50} -%%% -%%% The standard handler process is linked to logger_sup, which is -%%% part of the kernel application's supervision tree. -start(Name, Config, HandlerState) -> - LoggerStdH = - #{id => Name, - start => {?MODULE, start_link, [Name,Config,HandlerState]}, - restart => temporary, - shutdown => 2000, - type => worker, - modules => [?MODULE]}, - case supervisor:start_child(logger_sup, LoggerStdH) of - {ok,Pid,Config1} -> - ok = logger_handler_watcher:register_handler(Name,Pid), - {ok,Config1}; - Error -> - Error - end. - -%%%----------------------------------------------------------------- -%%% Stop and remove the handler. -stop(Name) -> - case whereis(?name_to_reg_name(?MODULE,Name)) of - undefined -> - ok; - Pid -> - %% We don't want to do supervisor:terminate_child here - %% since we need to distinguish this explicit stop from a - %% system termination in order to avoid circular attempts - %% at removing the handler (implying deadlocks and - %% timeouts). - %% And we don't need to do supervisor:delete_child, since - %% the restart type is temporary, which means that the - %% child specification is automatically removed from the - %% supervisor when the process dies. - _ = gen_server:call(Pid, stop), - ok - end. - -%%%----------------------------------------------------------------- -%%% Logging and overload control. --define(update_file_ctrl_sync(C, Interval), - if C == 0 -> Interval; - true -> C-1 end). - -%% check for overload between every event (and set Mode to async, -%% sync or drop accordingly), but never flush the whole mailbox -%% before LogWindowSize events have been handled -do_log(Bin, CallOrCast, State = #{id:=Name, mode:=Mode0}) -> - T1 = ?timestamp(), - - %% check if the handler is getting overloaded, or if it's - %% recovering from overload (the check must be done for each - %% event to react quickly to large bursts of events and - %% to ensure that the handler can never end up in drop mode - %% with an empty mailbox, which would stop operation) - {Mode1,QLen,Mem,State1} = logger_h_common:check_load(State), - - if (Mode1 == drop) andalso (Mode0 =/= drop) -> - log_handler_info(Name, "Handler ~p switched to drop mode", - [Name], State); - (Mode0 == drop) andalso ((Mode1 == async) orelse (Mode1 == sync)) -> - log_handler_info(Name, "Handler ~p switched to ~w mode", - [Name,Mode1], State); - true -> - ok - end, - - %% kill the handler if it can't keep up with the load - logger_h_common:kill_if_choked(Name, QLen, Mem, ?MODULE, State), - - if Mode1 == flush -> - flush(Name, QLen, T1, State1); - true -> - write(Name, Mode1, T1, Bin, CallOrCast, State1) - end. - -%% this clause is called by do_log/3 after an overload check -%% has been performed, where QLen > FlushQLen -flush(Name, _QLen0, T1, State=#{last_log_ts := _T0, mode_tab := ModeTab}) -> - %% flush messages in the mailbox (a limited number in - %% order to not cause long delays) - NewFlushed = logger_h_common:flush_log_events(?FLUSH_MAX_N), - - %% write info in log about flushed messages - log_handler_info(Name, "Handler ~p flushed ~w log events", - [Name,NewFlushed], State), - - %% because of the receive loop when flushing messages, the - %% handler will be scheduled out often and the mailbox could - %% grow very large, so we'd better check the queue again here - {_,_QLen1} = process_info(self(), message_queue_len), - ?observe(Name,{max_qlen,_QLen1}), - - %% Add 1 for the current log event - ?observe(Name,{flushed,NewFlushed+1}), - - State1 = ?update_max_time(?diff_time(T1,_T0),State), - {dropped,?update_other(flushed,FLUSHED,NewFlushed, - State1#{mode => ?set_mode(ModeTab,async), - last_qlen => 0, - last_log_ts => T1})}. - -%% this clause is called to write to file -write(_Name, Mode, T1, Bin, _CallOrCast, - State = #{mode_tab := ModeTab, - file_ctrl_pid := FileCtrlPid, - file_ctrl_sync := FileCtrlSync, - last_qlen := LastQLen, - last_log_ts := T0, - file_ctrl_sync_int := FileCtrlSyncInt}) -> - %% check if we need to limit the number of writes - %% during a burst of log events - {DoWrite,BurstWinT,BurstMsgCount} = logger_h_common:limit_burst(State), - - %% only send a synhrounous event to the file controller process - %% every FileCtrlSyncInt time, to give the handler time between - %% file writes so it can keep up with incoming messages - {Result,LastQLen1} = - if DoWrite, FileCtrlSync == 0 -> - ?observe(_Name,{_CallOrCast,1}), - file_write_sync(FileCtrlPid, Bin, false), - {ok,element(2, process_info(self(), message_queue_len))}; - DoWrite -> - ?observe(_Name,{_CallOrCast,1}), - file_write_async(FileCtrlPid, Bin), - {ok,LastQLen}; - not DoWrite -> - ?observe(_Name,{flushed,1}), - {dropped,LastQLen} - end, - - %% Check if the time since the previous log event is long enough - - %% and the queue length small enough - to assume the mailbox has - %% been emptied, and if so, do filesync operation and reset mode to - %% async. Note that this is the best we can do to detect an idle - %% handler without setting a timer after each log call/cast. If the - %% time between two consecutive log events is fast and no new - %% event comes in after the last one, idle state won't be detected! - Time = ?diff_time(T1,T0), - {Mode1,BurstMsgCount1} = - if (LastQLen1 < ?FILESYNC_OK_QLEN) andalso - (Time > ?IDLE_DETECT_TIME_USEC) -> - %% do filesync if necessary - case maps:get(type, State) of - Std when is_atom(Std) -> - ok; - _File -> - file_ctrl_filesync_async(FileCtrlPid) - end, - {?change_mode(ModeTab, Mode, async),0}; - true -> - {Mode,BurstMsgCount} - end, - State1 = - ?update_calls_or_casts(_CallOrCast,1,State), - State2 = - ?update_max_time(Time, - State1#{mode => Mode1, - last_qlen := LastQLen1, - last_log_ts => T1, - last_op => write, - burst_win_ts => BurstWinT, - burst_msg_count => BurstMsgCount1, - file_ctrl_sync => - ?update_file_ctrl_sync(FileCtrlSync, - FileCtrlSyncInt)}), - {Result,State2}. - open_log_file(HandlerName, FileInfo) -> case file_ctrl_start(HandlerName, FileInfo) of OK = {ok,_FileCtrlPid} -> OK; @@ -669,19 +259,6 @@ close_log_file(Fd) -> _ = file:close(Fd). -log_handler_info(Name, Format, Args, #{file_ctrl_pid := FileCtrlPid}) -> - Config = - case logger:get_handler_config(Name) of - {ok,Conf} -> Conf; - _ -> #{formatter=>{?DEFAULT_FORMATTER,?DEFAULT_FORMAT_CONFIG}} - end, - Meta = #{time=>erlang:system_time(microsecond)}, - Bin = logger_h_common:log_to_binary(#{level => notice, - msg => {Format,Args}, - meta => Meta}, Config), - _ = file_write_async(FileCtrlPid, Bin), - ok. - %%%----------------------------------------------------------------- %%% File control process @@ -708,24 +285,19 @@ file_write_async(Pid, Bin) -> Pid ! {log,Bin}, ok. -file_write_sync(Pid, Bin, FileSync) -> - case file_ctrl_call(Pid, {log,self(),Bin,FileSync}) of - {error,Reason} -> - {error,{write_failed,Bin,Reason}}; - Result -> - Result - end. +file_write_sync(Pid, Bin) -> + file_ctrl_call(Pid, {log,Bin}). file_ctrl_filesync_async(Pid) -> Pid ! filesync, ok. file_ctrl_filesync_sync(Pid) -> - file_ctrl_call(Pid, {filesync,self()}). + file_ctrl_call(Pid, filesync). file_ctrl_call(Pid, Msg) -> MRef = monitor(process, Pid), - Pid ! {Msg,MRef}, + Pid ! {Msg,{self(),MRef}}, receive {MRef,Result} -> demonitor(MRef, [flush]), @@ -743,74 +315,43 @@ file_ctrl_init(HandlerName, FileInfo, Starter) when is_tuple(FileInfo) -> case do_open_log_file(FileInfo) of {ok,Fd} -> Starter ! {self(),ok}, - file_ctrl_loop(Fd, file, FileName, false, ok, ok, HandlerName); + file_ctrl_loop(Fd, FileName, false, ok, ok, HandlerName); {error,Reason} -> Starter ! {self(),{error,{open_failed,FileName,Reason}}} end; file_ctrl_init(HandlerName, StdDev, Starter) -> Starter ! {self(),ok}, - file_ctrl_loop(StdDev, standard_io, StdDev, false, ok, ok, HandlerName). + file_ctrl_loop(StdDev, StdDev, false, ok, ok, HandlerName). -file_ctrl_loop(Fd, Type, DevName, Synced, +file_ctrl_loop(Fd, DevName, Synced, PrevWriteResult, PrevSyncResult, HandlerName) -> receive %% asynchronous event {log,Bin} -> - Result = if Type == file -> - write_to_dev(Fd, Bin, DevName, - PrevWriteResult, HandlerName); - true -> - io:put_chars(Fd, Bin) - end, - file_ctrl_loop(Fd, Type, DevName, false, + Fd1 = ensure(Fd, DevName), + Result = write_to_dev(Fd1, Bin, DevName, PrevWriteResult, HandlerName), + file_ctrl_loop(Fd1, DevName, false, Result, PrevSyncResult, HandlerName); %% synchronous event - {{log,From,Bin,FileSync},MRef} -> - if Type == file -> - %% check that file hasn't been deleted - CheckFile = - fun() -> {ok,_} = file:read_file_info(DevName) end, - spawn_link(CheckFile), - WResult = write_to_dev(Fd, Bin, DevName, - PrevWriteResult, HandlerName), - {Synced1,SResult} = - if not FileSync -> - {false,PrevSyncResult}; - true -> - case sync_dev(Fd, DevName, - PrevSyncResult, HandlerName) of - ok -> {true,ok}; - Error -> {false,Error} - end - end, - From ! {MRef,ok}, - file_ctrl_loop(Fd, Type, DevName, Synced1, - WResult, SResult, HandlerName); - true -> - _ = io:put_chars(Fd, Bin), - From ! {MRef,ok}, - file_ctrl_loop(Fd, Type, DevName, false, - ok, PrevSyncResult, HandlerName) - end; + {{log,Bin},{From,MRef}} -> + Fd1 = ensure(Fd, DevName), + Result = write_to_dev(Fd1, Bin, DevName, PrevWriteResult, HandlerName), + From ! {MRef,ok}, + file_ctrl_loop(Fd1, DevName, false, + Result, PrevSyncResult, HandlerName); - filesync when not Synced -> - Result = sync_dev(Fd, DevName, PrevSyncResult, HandlerName), - file_ctrl_loop(Fd, Type, DevName, true, + filesync -> + Fd1 = ensure(Fd, DevName), + Result = sync_dev(Fd1, DevName, Synced, PrevSyncResult, HandlerName), + file_ctrl_loop(Fd1, DevName, true, PrevWriteResult, Result, HandlerName); - filesync -> - file_ctrl_loop(Fd, Type, DevName, true, - PrevWriteResult, PrevSyncResult, HandlerName); - - {{filesync,From},MRef} -> - Result = if not Synced -> - sync_dev(Fd, DevName, PrevSyncResult, HandlerName); - true -> - ok - end, + {filesync,{From,MRef}} -> + Fd1 = ensure(Fd, DevName), + Result = sync_dev(Fd1, DevName, Synced, PrevSyncResult, HandlerName), From ! {MRef,ok}, - file_ctrl_loop(Fd, Type, DevName, true, + file_ctrl_loop(Fd1, DevName, true, PrevWriteResult, Result, HandlerName); stop -> @@ -818,26 +359,44 @@ file_ctrl_loop(Fd, Type, DevName, Synced, stopped end. -write_to_dev(Fd, Bin, FileName, PrevWriteResult, HandlerName) -> - case ?file_write(Fd, Bin) of - ok -> - ok; - PrevWriteResult -> - %% don't report same error twice - PrevWriteResult; - Error -> - logger_h_common:error_notify({HandlerName,write,FileName,Error}), - Error +%% In order to play well with tools like logrotate, we need to be able +%% to re-create the file if it has disappeared (e.g. if rotated by +%% logrotate) +ensure(Fd,DevName) when is_atom(DevName) -> + Fd; +ensure(Fd,FileName) -> + case file:read_file_info(FileName) of + {ok,_} -> + Fd; + _ -> + _ = file:close(Fd), + _ = file:close(Fd), % delayed_write cause close not to close + case do_open_log_file({file,FileName}) of + {ok,Fd1} -> + Fd1; + Error -> + exit({could_not_reopen_file,Error}) + end end. -sync_dev(Fd, DevName, PrevSyncResult, HandlerName) -> - case ?file_datasync(Fd) of - ok -> - ok; - PrevSyncResult -> - %% don't report same error twice - PrevSyncResult; - Error -> - logger_h_common:error_notify({HandlerName,filesync,DevName,Error}), - Error - end. +write_to_dev(DevName, Bin, _DevName, _PrevWriteResult, _HandlerName) + when is_atom(DevName) -> + io:put_chars(DevName, Bin); +write_to_dev(Fd, Bin, FileName, PrevWriteResult, HandlerName) -> + Result = ?file_write(Fd, Bin), + maybe_notify_error(write,Result,PrevWriteResult,FileName,HandlerName). + +sync_dev(_Fd, _FileName, true, PrevSyncResult, _HandlerName) -> + PrevSyncResult; +sync_dev(Fd, FileName, false, PrevSyncResult, HandlerName) -> + Result = ?file_datasync(Fd), + maybe_notify_error(filesync,Result,PrevSyncResult,FileName,HandlerName). + +maybe_notify_error(_Op, ok, _PrevResult, _FileName, _HandlerName) -> + ok; +maybe_notify_error(_Op, PrevResult, PrevResult, _FileName, _HandlerName) -> + %% don't report same error twice + PrevResult; +maybe_notify_error(Op, Error, _PrevResult, FileName, HandlerName) -> + logger_h_common:error_notify({HandlerName,Op,FileName,Error}), + Error. diff --git a/lib/kernel/src/seq_trace.erl b/lib/kernel/src/seq_trace.erl index 14fe21e9de..4f9d7b3e5c 100644 --- a/lib/kernel/src/seq_trace.erl +++ b/lib/kernel/src/seq_trace.erl @@ -98,7 +98,7 @@ print(Label, Term) -> -spec reset_trace() -> 'true'. reset_trace() -> - erlang:system_flag(1, 0). + erlang:system_flag(reset_seq_trace, true). %% reset_trace(Pid) -> % this might be a useful function too diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl index 04c0c48e3a..244bd7e2a0 100644 --- a/lib/kernel/test/gen_tcp_misc_SUITE.erl +++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl @@ -1969,20 +1969,20 @@ recvtclass(_Config) -> {skip,{ipv6_not_supported,IFs}} end. -%% These version numbers are the highest noted in daily tests -%% where the test fails for a plausible reason, so -%% skip on that platform. +%% These version numbers are above the highest noted +%% in daily tests where the test fails for a plausible reason, +%% so skip on platforms of lower version, i.e they are future +%% versions where it is possible that it might not fail. %% -%% On newer versions it might be fixed, but we'll see about that -%% when machines with newer versions gets installed... -%% If the test still fails for a plausible reason these +%% When machines with newer versions gets installed, +%% if the test still fails for a plausible reason these %% version numbers simply should be increased. %% Or maybe we should change to only test on known good %% platforms - change {unix,_} to false? %% pktoptions is not supported for IPv4 recvtos_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0}); -recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0}); +recvtos_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); %% Using the option returns einval, so it is not implemented. recvtos_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0}); recvtos_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); @@ -1994,18 +1994,19 @@ recvtos_ok(_, _) -> false. %% pktoptions is not supported for IPv4 recvttl_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0}); -recvttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0}); +recvttl_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); %% Using the option returns einval, so it is not implemented. recvttl_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0}); recvttl_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); +%% Does not return any value - not implemented for pktoptions +recvttl_ok({unix,linux}, OSVer) -> not semver_lt(OSVer, {2,7,0}); %% -recvttl_ok({unix,linux}, _) -> true; recvttl_ok({unix,_}, _) -> true; recvttl_ok(_, _) -> false. %% pktoptions is not supported for IPv6 recvtclass_ok({unix,openbsd}, OSVer) -> not semver_lt(OSVer, {6,4,0}); -recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {17,6,0}); +recvtclass_ok({unix,darwin}, OSVer) -> not semver_lt(OSVer, {19,0,0}); recvtclass_ok({unix,sunos}, OSVer) -> not semver_lt(OSVer, {5,12,0}); %% Using the option returns einval, so it is not implemented. recvtclass_ok({unix,freebsd}, OSVer) -> not semver_lt(OSVer, {11,2,0}); diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl index 7828cc4716..a0154b2694 100644 --- a/lib/kernel/test/init_SUITE.erl +++ b/lib/kernel/test/init_SUITE.erl @@ -295,7 +295,7 @@ is_real_system(KernelVsn, StdlibVsn) -> %% before restart. %% ------------------------------------------------ many_restarts() -> - [{timetrap,{minutes,8}}]. + [{timetrap,{minutes,16}}]. many_restarts(Config) when is_list(Config) -> {ok, Node} = loose_node:start(init_test, "", ?DEFAULT_TIMEOUT_SEC), @@ -315,7 +315,7 @@ loop_restart(N,Node,EHPid) -> loose_node:stop(Node), ct:fail(not_stopping) end, - ok = wait_for(30, Node, EHPid), + ok = wait_for(60, Node, EHPid), loop_restart(N-1,Node,rpc:call(Node,erlang,whereis,[logger])). wait_for(0,Node,_) -> @@ -367,7 +367,8 @@ restart(Config) when is_list(Config) -> SysProcs0 = rpc:call(Node, ?MODULE, find_system_processes, []), io:format("SysProcs0=~p~n", [SysProcs0]), [InitPid, PurgerPid, LitCollectorPid, - DirtySigNPid, DirtySigHPid, DirtySigMPid] = SysProcs0, + DirtySigNPid, DirtySigHPid, DirtySigMPid, + PrimFilePid] = SysProcs0, InitPid = rpc:call(Node, erlang, whereis, [init]), PurgerPid = rpc:call(Node, erlang, whereis, [erts_code_purger]), Procs = rpc:call(Node, erlang, processes, []), @@ -385,7 +386,8 @@ restart(Config) when is_list(Config) -> SysProcs1 = rpc:call(Node, ?MODULE, find_system_processes, []), io:format("SysProcs1=~p~n", [SysProcs1]), [InitPid1, PurgerPid1, LitCollectorPid1, - DirtySigNPid1, DirtySigHPid1, DirtySigMPid1] = SysProcs1, + DirtySigNPid1, DirtySigHPid1, DirtySigMPid1, + PrimFilePid1] = SysProcs1, %% Still the same init process! InitPid1 = rpc:call(Node, erlang, whereis, [init]), @@ -411,6 +413,10 @@ restart(Config) when is_list(Config) -> DirtySigMP = pid_to_list(DirtySigMPid), DirtySigMP = pid_to_list(DirtySigMPid1), + %% and same prim_file helper process! + PrimFileP = pid_to_list(PrimFilePid), + PrimFileP = pid_to_list(PrimFilePid1), + NewProcs0 = rpc:call(Node, erlang, processes, []), NewProcs = NewProcs0 -- SysProcs1, case check_processes(NewProcs, MaxPid) of @@ -437,7 +443,8 @@ restart(Config) when is_list(Config) -> literal_collector, dirty_sig_handler_normal, dirty_sig_handler_high, - dirty_sig_handler_max}). + dirty_sig_handler_max, + prim_file}). find_system_processes() -> find_system_procs(processes(), #sys_procs{}). @@ -448,7 +455,8 @@ find_system_procs([], SysProcs) -> SysProcs#sys_procs.literal_collector, SysProcs#sys_procs.dirty_sig_handler_normal, SysProcs#sys_procs.dirty_sig_handler_high, - SysProcs#sys_procs.dirty_sig_handler_max]; + SysProcs#sys_procs.dirty_sig_handler_max, + SysProcs#sys_procs.prim_file]; find_system_procs([P|Ps], SysProcs) -> case process_info(P, [initial_call, priority]) of [{initial_call,{erl_init,start,2}},_] -> @@ -472,6 +480,9 @@ find_system_procs([P|Ps], SysProcs) -> {priority,max}] -> undefined = SysProcs#sys_procs.dirty_sig_handler_max, find_system_procs(Ps, SysProcs#sys_procs{dirty_sig_handler_max = P}); + [{initial_call,{prim_file,start,0}},_] -> + undefined = SysProcs#sys_procs.prim_file, + find_system_procs(Ps, SysProcs#sys_procs{prim_file = P}); _ -> find_system_procs(Ps, SysProcs) end. diff --git a/lib/kernel/test/logger_disk_log_h_SUITE.erl b/lib/kernel/test/logger_disk_log_h_SUITE.erl index 905c2c52c5..87b8250781 100644 --- a/lib/kernel/test/logger_disk_log_h_SUITE.erl +++ b/lib/kernel/test/logger_disk_log_h_SUITE.erl @@ -332,16 +332,18 @@ errors(Config) -> %%! Check how bad log_opts are handled! {error,{illegal_config_change, - #{config:=#{type:=wrap}}, - #{config:=#{type:=halt}}}} = + logger_disk_log_h, + #{type:=wrap}, + #{type:=halt}}} = logger:update_handler_config(Name1, config, #{type=>halt, file=>LogFile1}), {error,{illegal_config_change, - #{config:=#{file:=LogFile1}}, - #{config:=#{file:="newfilename"}}}} = + logger_disk_log_h, + #{file:=LogFile1}, + #{file:="newfilename"}}} = logger:update_handler_config(Name1, config, #{file=>"newfilename"}), @@ -411,20 +413,25 @@ formatter_fail(cleanup,_Config) -> ok. config_fail(_Config) -> - {error,{handler_not_added,{invalid_config,logger_disk_log_h,{bad,bad}}}} = + {error,{handler_not_added,{invalid_config,logger_disk_log_h,#{bad:=bad}}}} = logger:add_handler(?MODULE,logger_disk_log_h, #{config => #{bad => bad}, filter_default=>log, formatter=>{?MODULE,self()}}), - {error,{handler_not_added,{invalid_levels,{_,1,_}}}} = + {error,{handler_not_added,{invalid_config,logger_disk_log_h, + {invalid_levels,#{drop_mode_qlen:=1}}}}} = logger:add_handler(?MODULE,logger_disk_log_h, #{config => #{drop_mode_qlen=>1}}), - {error,{handler_not_added,{invalid_levels,{43,42,_}}}} = + {error,{handler_not_added,{invalid_config,logger_disk_log_h, + {invalid_levels,#{sync_mode_qlen:=43, + drop_mode_qlen:=42}}}}} = logger:add_handler(?MODULE,logger_disk_log_h, #{config => #{sync_mode_qlen=>43, drop_mode_qlen=>42}}), - {error,{handler_not_added,{invalid_levels,{_,43,42}}}} = + {error,{handler_not_added,{invalid_config,logger_disk_log_h, + {invalid_levels,#{drop_mode_qlen:=43, + flush_qlen:=42}}}}} = logger:add_handler(?MODULE,logger_disk_log_h, #{config => #{drop_mode_qlen=>43, flush_qlen=>42}}), @@ -433,20 +440,17 @@ config_fail(_Config) -> #{filter_default=>log, formatter=>{?MODULE,self()}}), %% can't change the disk log options for a log already in use - {error,{illegal_config_change,_,_}} = + {error,{illegal_config_change,logger_disk_log_h,_,_}} = logger:update_handler_config(?MODULE,config, #{max_no_files=>2}), - %% can't change name of an existing handler - {error,{illegal_config_change,_,_}} = - logger:update_handler_config(?MODULE,id,bad), %% incorrect values of OP params {ok,#{config := HConfig}} = logger:get_handler_config(?MODULE), - {error,{invalid_levels,_}} = + {error,{invalid_config,logger_disk_log_h,{invalid_levels,_}}} = logger:update_handler_config(?MODULE,config, HConfig#{sync_mode_qlen=>100, flush_qlen=>99}), %% invalid name of config parameter - {error,{invalid_config,logger_disk_log_h,{filesync_rep_int,2000}}} = + {error,{invalid_config,logger_disk_log_h,#{filesync_rep_int:=2000}}} = logger:update_handler_config(?MODULE, config, HConfig#{filesync_rep_int => 2000}), ok. @@ -487,10 +491,11 @@ reconfig(Config) -> overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE, overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER, filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL, - log_opts := #{type := ?DISK_LOG_TYPE, - max_no_files := ?DISK_LOG_MAX_NO_FILES, - max_no_bytes := ?DISK_LOG_MAX_NO_BYTES, - file := DiskLogFile}} = + handler_state := + #{log_opts := #{type := ?DISK_LOG_TYPE, + max_no_files := ?DISK_LOG_MAX_NO_FILES, + max_no_bytes := ?DISK_LOG_MAX_NO_BYTES, + file := DiskLogFile}}} = logger_disk_log_h:info(?MODULE), {ok,#{config := #{sync_mode_qlen := ?SYNC_MODE_QLEN, @@ -572,10 +577,11 @@ reconfig(Config) -> max_no_files => 1, max_no_bytes => 1024, file => File}}), - #{log_opts := #{type := halt, - max_no_files := 1, - max_no_bytes := 1024, - file := File}} = + #{handler_state := + #{log_opts := #{type := halt, + max_no_files := 1, + max_no_bytes := 1024, + file := File}}} = logger_disk_log_h:info(?MODULE), {ok,#{config := #{type := halt, @@ -596,13 +602,13 @@ reconfig(Config) -> %% You are not allowed to actively set the write once fields %% (type, max_no_files, max_no_bytes, file) in runtime. - {error, {illegal_config_change,_,_}} = + {error, {illegal_config_change,_,_,_}} = logger:set_handler_config(?MODULE,config,#{type=>wrap}), - {error, {illegal_config_change,_,_}} = + {error, {illegal_config_change,_,_,_}} = logger:set_handler_config(?MODULE,config,#{max_no_files=>2}), - {error, {illegal_config_change,_,_}} = + {error, {illegal_config_change,_,_,_}} = logger:set_handler_config(?MODULE,config,#{max_no_bytes=>2048}), - {error, {illegal_config_change,_,_}} = + {error, {illegal_config_change,_,_,_}} = logger:set_handler_config(?MODULE,config,#{file=>"otherfile.log"}), {ok,C7} = logger:get_handler_config(?MODULE), ct:log("C7: ~p",[C7]), @@ -630,16 +636,16 @@ sync(Config) -> filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]), formatter=>{?MODULE,nl}}), - start_tracer([{disk_log,blog,2}, - {logger_disk_log_h,disk_log_sync,2}], - [{disk_log,blog,<<"first\n">>}, - {logger_disk_log_h,disk_log_sync}]), + start_tracer([{logger_disk_log_h,disk_log_write,3}, + {disk_log,sync,1}], + [{logger_disk_log_h,disk_log_write,<<"first\n">>}, + {disk_log,sync}]), logger:notice("first", ?domain), %% wait for automatic disk_log_sync check_tracer(?FILESYNC_REPEAT_INTERVAL*2), - %% check that if there's no repeated disk_log_sync active, + %% check that if there's no repeated filesync active, %% a disk_log_sync is still performed when handler goes idle {ok,#{config := HConfig}} = logger:get_handler_config(?MODULE), HConfig1 = HConfig#{filesync_repeat_interval => no_repeat}, @@ -652,12 +658,12 @@ sync(Config) -> %% triggered by the idle timeout between "fourth" and "fifth". timer:sleep(?IDLE_DETECT_TIME_MSEC*2), - start_tracer([{disk_log,blog,2}, - {logger_disk_log_h,disk_log_sync,2}], - [{disk_log,blog,<<"second\n">>}, - {logger_disk_log_h,disk_log_sync}, - {disk_log,blog,<<"third\n">>}, - {logger_disk_log_h,disk_log_sync}]), + start_tracer([{logger_disk_log_h,disk_log_write,3}, + {disk_log,sync,1}], + [{logger_disk_log_h,disk_log_write,<<"second\n">>}, + {disk_log,sync}, + {logger_disk_log_h,disk_log_write,<<"third\n">>}, + {disk_log,sync}]), logger:notice("second", ?domain), timer:sleep(?IDLE_DETECT_TIME_MSEC*2), @@ -667,13 +673,13 @@ sync(Config) -> try_read_file(Log, {ok,<<"first\nsecond\nthird\n">>}, 1000), - %% switch repeated disk_log_sync on and verify that the looping works + %% switch repeated filesync on and verify that the looping works SyncInt = 1000, WaitT = 4500, - OneSync = {logger_disk_log_h,handle_cast,repeated_disk_log_sync}, - %% receive 1 initial repeated_disk_log_sync, then 1 per sec - start_tracer([{logger_disk_log_h,handle_cast,2}], - [OneSync || _ <- lists:seq(1, 1 + trunc(WaitT/SyncInt))]), + OneSync = {logger_h_common,handle_cast,repeated_filesync}, + %% receive 1 repeated_filesync per sec + start_tracer([{logger_h_common,handle_cast,2}], + [OneSync || _ <- lists:seq(1, trunc(WaitT/SyncInt))]), HConfig2 = HConfig#{filesync_repeat_interval => SyncInt}, ok = logger:update_handler_config(?MODULE, config, HConfig2), @@ -716,7 +722,7 @@ disk_log_wrap(Config) -> end, {ok,_} = dbg:tracer(process, {TraceFun, Tester}), {ok,_} = dbg:p(whereis(h_proc_name()), [c]), - {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 2, []), + {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 3, []), Text = [34 + rand:uniform(126-34) || _ <- lists:seq(1,MaxBytes)], ct:pal("String = ~p (~w)", [Text, erts_debug:size(Text)]), @@ -734,7 +740,7 @@ disk_log_wrap(Config) -> timer:sleep(1000), dbg:stop_clear(), Received = lists:flatmap(fun({trace,_M,handle_info, - [{disk_log,_Node,_Name,What},_]}) -> + [_,{disk_log,_Node,_Name,What},_]}) -> [{trace,What}]; ({log,_}) -> [] @@ -770,7 +776,7 @@ disk_log_full(Config) -> end, {ok,_} = dbg:tracer(process, {TraceFun, Tester}), {ok,_} = dbg:p(whereis(h_proc_name()), [c]), - {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 2, []), + {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 3, []), NoOfChars = 5, Text = [34 + rand:uniform(126-34) || _ <- lists:seq(1,NoOfChars)], @@ -780,14 +786,18 @@ disk_log_full(Config) -> timer:sleep(2000), dbg:stop_clear(), Received = lists:flatmap(fun({trace,_M,handle_info, - [{disk_log,_Node,_Name,What},_]}) -> + [_,{disk_log,_Node,_Name,What},_]}) -> [{trace,What}]; ({log,_}) -> [] end, test_server:messages_get()), ct:pal("Trace =~n~p", [Received]), - [{trace,full}, - {trace,{error_status,{error,{full,_}}}}] = Received, + + %% The tail here could be an error_status notification, if the + %% last write was synchronous, but in most cases it will not be + [{trace,full}|_] = Received, + %% [{trace,full}, + %% {trace,{error_status,{error,{full,_}}}}] = Received, ok. disk_log_full(cleanup, _Config) -> dbg:stop_clear(), @@ -819,14 +829,14 @@ disk_log_events(Config) -> end, {ok,_} = dbg:tracer(process, {TraceFun, Tester}), {ok,_} = dbg:p(whereis(h_proc_name()), [c]), - {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 2, []), + {ok,_} = dbg:tp(logger_disk_log_h, handle_info, 3, []), [whereis(h_proc_name()) ! E || E <- Events], %% wait for trace messages timer:sleep(2000), dbg:stop_clear(), Received = lists:map(fun({trace,_M,handle_info, - [Got,_]}) -> Got + [_,Got,_]}) -> Got end, test_server:messages_get()), ct:pal("Trace =~n~p", [Received]), NoOfEvents = length(Events), @@ -849,13 +859,15 @@ write_failure(Config) -> false = (undefined == rpc:call(Node, ets, whereis, [?TEST_HOOKS_TAB])), rpc:call(Node, ets, insert, [?TEST_HOOKS_TAB,{tester,self()}]), rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]), - rpc:call(Node, ?MODULE, set_result, [disk_log_blog,ok]), + rpc:call(Node, ?MODULE, set_result, [disk_log_write,ok]), HState = rpc:call(Node, logger_disk_log_h, info, [?STANDARD_HANDLER]), - ct:pal("LogOpts = ~p", [LogOpts = maps:get(log_opts, HState)]), + ct:pal("LogOpts = ~p", [LogOpts = maps:get(log_opts, + maps:get(handler_state,HState))]), + %% ?check and ?check_no_log in this test only check for internal log events ok = log_on_remote_node(Node, "Logged1"), rpc:call(Node, logger_disk_log_h, filesync, [?STANDARD_HANDLER]), - ?check_no_log, + ?check_no_log, % no internal log when write ok SyncRepInt = case (fun() -> is_atom(?FILESYNC_REPEAT_INTERVAL) end)() of true -> 5500; @@ -864,24 +876,26 @@ write_failure(Config) -> try_read_file(Log, {ok,<<"Logged1\n">>}, SyncRepInt), - rpc:call(Node, ?MODULE, set_result, [disk_log_blog,{error,no_such_log}]), + rpc:call(Node, ?MODULE, set_result, [disk_log_write,{error,no_such_log}]), ok = log_on_remote_node(Node, "Cause simple error printout"), + %% this should have caused an internal log ?check({error,{?STANDARD_HANDLER,log,LogOpts,{error,no_such_log}}}), - + ok = log_on_remote_node(Node, "No second error printout"), - ?check_no_log, + ?check_no_log, % but don't log same error twice - rpc:call(Node, ?MODULE, set_result, [disk_log_blog, + rpc:call(Node, ?MODULE, set_result, [disk_log_write, {error,{full,?STANDARD_HANDLER}}]), ok = log_on_remote_node(Node, "Cause simple error printout"), + %% this was a different error, so it should be logged ?check({error,{?STANDARD_HANDLER,log,LogOpts, {error,{full,?STANDARD_HANDLER}}}}), - rpc:call(Node, ?MODULE, set_result, [disk_log_blog,ok]), + rpc:call(Node, ?MODULE, set_result, [disk_log_write,ok]), ok = log_on_remote_node(Node, "Logged2"), rpc:call(Node, logger_disk_log_h, filesync, [?STANDARD_HANDLER]), - ?check_no_log, + ?check_no_log, % no internal log when write ok try_read_file(Log, {ok,<<"Logged1\nLogged2\n">>}, SyncRepInt), ok. write_failure(cleanup, _Config) -> @@ -901,7 +915,7 @@ sync_failure(Config) -> rpc:call(Node, ?MODULE, set_internal_log, [?MODULE,internal_log]), rpc:call(Node, ?MODULE, set_result, [disk_log_sync,ok]), HState = rpc:call(Node, logger_disk_log_h, info, [?STANDARD_HANDLER]), - LogOpts = maps:get(log_opts, HState), + LogOpts = maps:get(log_opts, maps:get(handler_state,HState)), SyncInt = 500, ok = rpc:call(Node, logger, update_handler_config, @@ -1606,10 +1620,10 @@ tpl([{M,F,A}|Trace]) -> tpl([]) -> ok. -tracer({trace,_,call,{logger_disk_log_h,handle_cast,[Op|_]},Caller}, +tracer({trace,_,call,{logger_h_common,handle_cast,[Op|_]},Caller}, {Pid,[{Mod,Func,Op}|Expected]}) -> maybe_tracer_done(Pid,Expected,{Mod,Func,Op},Caller); -tracer({trace,_,call,{Mod=disk_log,Func=blog,[_,Data]},Caller}, {Pid,[{Mod,Func,Data}|Expected]}) -> +tracer({trace,_,call,{Mod=logger_disk_log_h,Func=disk_log_write,[_,_,Data]},Caller}, {Pid,[{Mod,Func,Data}|Expected]}) -> maybe_tracer_done(Pid,Expected,{Mod,Func,Data},Caller); tracer({trace,_,call,{Mod,Func,_},Caller}, {Pid,[{Mod,Func}|Expected]}) -> maybe_tracer_done(Pid,Expected,{Mod,Func},Caller); diff --git a/lib/kernel/test/logger_std_h_SUITE.erl b/lib/kernel/test/logger_std_h_SUITE.erl index b6a09f4980..eb17a6d857 100644 --- a/lib/kernel/test/logger_std_h_SUITE.erl +++ b/lib/kernel/test/logger_std_h_SUITE.erl @@ -136,11 +136,12 @@ all() -> mem_kill_new, mem_kill_std, restart_after, - handler_requests_under_load + handler_requests_under_load, + recreate_deleted_log ]. add_remove_instance_tty(_Config) -> - {error,{handler_not_added,{invalid_config,logger_std_h,{type,tty}}}} = + {error,{handler_not_added,{invalid_config,logger_std_h,#{type:=tty}}}} = logger:add_handler(?MODULE,logger_std_h, #{config => #{type => tty}, filter_default=>log, @@ -234,7 +235,7 @@ errors(Config) -> {error, {handler_not_added, - {invalid_config,logger_std_h,{type,faulty_type}}}} = + {invalid_config,logger_std_h,#{type:=faulty_type}}}} = logger:add_handler(?MODULE,logger_std_h, #{config => #{type => faulty_type}}), @@ -308,25 +309,30 @@ formatter_fail(cleanup,_Config) -> logger:remove_handler(?MODULE). config_fail(_Config) -> - {error,{handler_not_added,{invalid_config,logger_std_h,{bad,bad}}}} = + {error,{handler_not_added,{invalid_config,logger_std_h,#{bad:=bad}}}} = logger:add_handler(?MODULE,logger_std_h, #{config => #{bad => bad}, filter_default=>log, formatter=>{?MODULE,self()}}), {error,{handler_not_added,{invalid_config,logger_std_h, - {restart_type,bad}}}} = + #{restart_type:=bad}}}} = logger:add_handler(?MODULE,logger_std_h, #{config => #{restart_type => bad}, filter_default=>log, formatter=>{?MODULE,self()}}), - {error,{handler_not_added,{invalid_levels,{_,1,_}}}} = + {error,{handler_not_added,{invalid_config,logger_std_h, + {invalid_levels,#{drop_mode_qlen:=1}}}}} = logger:add_handler(?MODULE,logger_std_h, #{config => #{drop_mode_qlen=>1}}), - {error,{handler_not_added,{invalid_levels,{43,42,_}}}} = + {error,{handler_not_added,{invalid_config,logger_std_h, + {invalid_levels,#{sync_mode_qlen:=43, + drop_mode_qlen:=42}}}}} = logger:add_handler(?MODULE,logger_std_h, #{config => #{sync_mode_qlen=>43, drop_mode_qlen=>42}}), - {error,{handler_not_added,{invalid_levels,{_,43,42}}}} = + {error,{handler_not_added,{invalid_config,logger_std_h, + {invalid_levels,#{drop_mode_qlen:=43, + flush_qlen:=42}}}}} = logger:add_handler(?MODULE,logger_std_h, #{config => #{drop_mode_qlen=>43, flush_qlen=>42}}), @@ -334,15 +340,15 @@ config_fail(_Config) -> ok = logger:add_handler(?MODULE,logger_std_h, #{filter_default=>log, formatter=>{?MODULE,self()}}), - {error,{illegal_config_change,#{config:=#{type:=_}},#{config:=#{type:=_}}}} = + {error,{illegal_config_change,logger_std_h,#{type:=_},#{type:=_}}} = logger:set_handler_config(?MODULE,config, #{type=>{file,"file"}}), - {error,{invalid_levels,_}} = + {error,{invalid_config,logger_std_h,{invalid_levels,_}}} = logger:set_handler_config(?MODULE,config, #{sync_mode_qlen=>100, flush_qlen=>99}), - {error,{invalid_config,logger_std_h,{filesync_rep_int,2000}}} = + {error,{invalid_config,logger_std_h,#{filesync_rep_int:=2000}}} = logger:set_handler_config(?MODULE, config, #{filesync_rep_int => 2000}), @@ -468,8 +474,8 @@ reconfig(Config) -> filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]), formatter=>{?MODULE,self()}}), #{id := ?MODULE, - type := standard_io, - file_ctrl_pid := FileCtrlPid, + handler_state := #{type := standard_io, + file_ctrl_pid := FileCtrlPid}, sync_mode_qlen := ?SYNC_MODE_QLEN, drop_mode_qlen := ?DROP_MODE_QLEN, flush_qlen := ?FLUSH_QLEN, @@ -480,7 +486,7 @@ reconfig(Config) -> overload_kill_qlen := ?OVERLOAD_KILL_QLEN, overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE, overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER, - filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL} = DefaultInfo = + filesync_repeat_interval := no_repeat} = DefaultInfo = logger_std_h:info(?MODULE), {ok, @@ -496,7 +502,7 @@ reconfig(Config) -> overload_kill_qlen := ?OVERLOAD_KILL_QLEN, overload_kill_mem_size := ?OVERLOAD_KILL_MEM_SIZE, overload_kill_restart_after := ?OVERLOAD_KILL_RESTART_AFTER, - filesync_repeat_interval := ?FILESYNC_REPEAT_INTERVAL} = + filesync_repeat_interval := no_repeat} = DefaultHConf}} = logger:get_handler_config(?MODULE), @@ -511,10 +517,10 @@ reconfig(Config) -> overload_kill_qlen => 100000, overload_kill_mem_size => 10000000, overload_kill_restart_after => infinity, - filesync_repeat_interval => no_repeat}), + filesync_repeat_interval => 5000}), #{id := ?MODULE, - type := standard_io, - file_ctrl_pid := FileCtrlPid, + handler_state := #{type := standard_io, + file_ctrl_pid := FileCtrlPid}, sync_mode_qlen := 1, drop_mode_qlen := 2, flush_qlen := 3, @@ -584,7 +590,7 @@ reconfig(Config) -> %% You are not allowed to actively set 'type' in runtime, since %% this is a write once field. - {error, {illegal_config_change,_,_}} = + {error, {illegal_config_change,logger_std_h,_,_}} = logger:set_handler_config(?MODULE,config,#{type=>standard_io}), {ok,#{config:=C6}} = logger:get_handler_config(?MODULE), ct:log("C6: ~p",[C6]), @@ -620,7 +626,7 @@ file_opts(Config) -> filters=>?DEFAULT_HANDLER_FILTERS([?MODULE]), formatter=>{?MODULE,self()}}), - #{type := OkType} = logger_std_h:info(?MODULE), + #{handler_state := #{type := OkType}} = logger_std_h:info(?MODULE), logger:notice(M1=?msg,?domain), ?check(M1), B1 = ?bin(M1), @@ -643,10 +649,8 @@ sync(Config) -> %% check repeated filesync happens start_tracer([{logger_std_h, write_to_dev, 5}, - {logger_std_h, sync_dev, 4}, {file, datasync, 1}], [{logger_std_h, write_to_dev, <<"first\n">>}, - {logger_std_h, sync_dev}, {file,datasync}]), logger:notice("first", ?domain), @@ -655,10 +659,8 @@ sync(Config) -> %% check that explicit filesync is only done once start_tracer([{logger_std_h, write_to_dev, 5}, - {logger_std_h, sync_dev, 4}, {file, datasync, 1}], [{logger_std_h, write_to_dev, <<"second\n">>}, - {logger_std_h, sync_dev}, {file,datasync}, {no_more,500} ]), @@ -679,13 +681,10 @@ sync(Config) -> %% triggered by the idle timeout between "thrid" and "fourth". timer:sleep(?IDLE_DETECT_TIME_MSEC*2), start_tracer([{logger_std_h, write_to_dev, 5}, - {logger_std_h, sync_dev, 4}, {file, datasync, 1}], [{logger_std_h, write_to_dev, <<"third\n">>}, - {logger_std_h, sync_dev}, {file,datasync}, {logger_std_h, write_to_dev, <<"fourth\n">>}, - {logger_std_h, sync_dev}, {file,datasync}]), logger:notice("third", ?domain), %% wait for automatic filesync @@ -697,10 +696,10 @@ sync(Config) -> %% switch repeated filesync on and verify that the looping works SyncInt = 1000, WaitT = 4500, - OneSync = {logger_std_h,handle_cast,repeated_filesync}, - %% receive 1 initial repeated_filesync, then 1 per sec - start_tracer([{logger_std_h,handle_cast,2}], - [OneSync || _ <- lists:seq(1, 1 + trunc(WaitT/SyncInt))]), + OneSync = {logger_h_common,handle_cast,repeated_filesync}, + %% receive 1 repeated_filesync per sec + start_tracer([{logger_h_common,handle_cast,2}], + [OneSync || _ <- lists:seq(1, trunc(WaitT/SyncInt))]), ok = logger:update_handler_config(?MODULE, config, #{filesync_repeat_interval => SyncInt}), @@ -1257,6 +1256,22 @@ handler_requests_under_load(Config) -> handler_requests_under_load(cleanup, _Config) -> ok = stop_handler(?MODULE). +recreate_deleted_log(Config) -> + {Log,_HConfig,_StdHConfig} = + start_handler(?MODULE, ?FUNCTION_NAME, Config), + logger:notice("first",?domain), + logger_std_h:filesync(?MODULE), + ok = file:rename(Log,Log++".old"), + logger:notice("second",?domain), + logger_std_h:filesync(?MODULE), + {ok,<<"first\n">>} = file:read_file(Log++".old"), + {ok,<<"second\n">>} = file:read_file(Log), + ok. +recreate_deleted_log(cleanup, _Config) -> + ok = stop_handler(?MODULE). + +%%%----------------------------------------------------------------- +%%% send_requests(HName, TO, Reqs = [{Req,Res}|Rs]) -> receive {From,finish} -> @@ -1278,8 +1293,8 @@ send_requests(HName, TO, Reqs = [{Req,Res}|Rs]) -> %%%----------------------------------------------------------------- %%% -start_handler(Name, TTY, Config) when TTY == standard_io; - TTY == standard_error-> +start_handler(Name, TTY, _Config) when TTY == standard_io; + TTY == standard_error-> ok = logger:add_handler(Name, logger_std_h, #{config => #{type => TTY}, @@ -1533,7 +1548,7 @@ start_op_trace() -> {ok,_} = dbg:p(self(), [c]), MS1 = dbg:fun2ms(fun([_]) -> return_trace() end), - {ok,_} = dbg:tp(logger_h_common, check_load, 1, MS1), + {ok,_} = dbg:tpl(logger_h_common, check_load, 1, MS1), {ok,_} = dbg:tpl(logger_h_common, flush_log_requests, 2, []), @@ -1607,7 +1622,9 @@ analyse(Msgs) -> start_tracer(Trace,Expected) -> Pid = self(), - FileCtrlPid = maps:get(file_ctrl_pid, logger_std_h:info(?MODULE)), + FileCtrlPid = maps:get(file_ctrl_pid, + maps:get(handler_state, + logger_std_h:info(?MODULE))), dbg:tracer(process,{fun tracer/2,{Pid,Expected}}), dbg:p(whereis(h_proc_name()),[c]), dbg:p(FileCtrlPid,[c]), @@ -1628,7 +1645,7 @@ tpl([{M,F,A}|Trace]) -> tpl([]) -> ok. -tracer({trace,_,call,{logger_std_h,handle_cast,[Op|_]}}, +tracer({trace,_,call,{logger_h_common,handle_cast,[Op|_]}}, {Pid,[{Mod,Func,Op}|Expected]}) -> maybe_tracer_done(Pid,Expected,{Mod,Func,Op}); tracer({trace,_,call,{Mod=logger_std_h,Func=write_to_dev,[_,Data,_,_,_]}}, diff --git a/lib/kernel/test/sendfile_SUITE.erl b/lib/kernel/test/sendfile_SUITE.erl index 0c0b1cbcb6..ad060aa05c 100644 --- a/lib/kernel/test/sendfile_SUITE.erl +++ b/lib/kernel/test/sendfile_SUITE.erl @@ -341,7 +341,21 @@ t_sendfile_closeduring(Config) -> -1 end, - ok = sendfile_send({127,0,0,1}, Send, 0). + ok = sendfile_send({127,0,0,1}, Send, 0, [{active,false}]), + [] = flush(), + ok = sendfile_send({127,0,0,1}, Send, 0, [{active,true}]), + [] = flush(), + ok. + +flush() -> + lists:reverse(flush([])). + +flush(Acc) -> + receive M -> + flush([M | Acc]) + after 0 -> + Acc + end. t_sendfile_crashduring(Config) -> Filename = proplists:get_value(big_file, Config), @@ -409,12 +423,16 @@ sendfile_send(Send) -> sendfile_send(Host, Send) -> sendfile_send(Host, Send, []). sendfile_send(Host, Send, Orig) -> + sendfile_send(Host, Send, Orig, [{active,false}]). + +sendfile_send(Host, Send, Orig, SockOpts) -> + SFServer = spawn_link(?MODULE, sendfile_server, [self(), Orig]), receive {server, Port} -> - {ok, Sock} = gen_tcp:connect(Host, Port, - [binary,{packet,0}, - {active,false}]), + Opts = [binary,{packet,0}|SockOpts], + io:format("connect with opts = ~p\n", [Opts]), + {ok, Sock} = gen_tcp:connect(Host, Port, Opts), Data = case proplists:get_value(arity,erlang:fun_info(Send)) of 1 -> Send(Sock); diff --git a/lib/kernel/test/seq_trace_SUITE.erl b/lib/kernel/test/seq_trace_SUITE.erl index 3bbf62e832..663f910751 100644 --- a/lib/kernel/test/seq_trace_SUITE.erl +++ b/lib/kernel/test/seq_trace_SUITE.erl @@ -28,7 +28,8 @@ -export([token_set_get/1, tracer_set_get/1, print/1, send/1, distributed_send/1, recv/1, distributed_recv/1, trace_exit/1, distributed_exit/1, call/1, port/1, - match_set_seq_token/1, gc_seq_token/1, label_capability_mismatch/1]). + match_set_seq_token/1, gc_seq_token/1, label_capability_mismatch/1, + send_literal/1]). %% internal exports -export([simple_tracer/2, one_time_receiver/0, one_time_receiver/1, @@ -47,7 +48,7 @@ suite() -> {timetrap,{minutes,1}}]. all() -> - [token_set_get, tracer_set_get, print, send, + [token_set_get, tracer_set_get, print, send, send_literal, distributed_send, recv, distributed_recv, trace_exit, distributed_exit, call, port, match_set_seq_token, gc_seq_token, label_capability_mismatch]. @@ -161,23 +162,51 @@ do_print(TsType) -> {0,{print,_,_,[],print3}, Ts1}] = stop_tracer(2), check_ts(TsType, Ts0), check_ts(TsType, Ts1). - + send(Config) when is_list(Config) -> lists:foreach(fun do_send/1, ?TIMESTAMP_MODES). do_send(TsType) -> + do_send(TsType, send). + +do_send(TsType, Msg) -> seq_trace:reset_trace(), start_tracer(), Receiver = spawn(?MODULE,one_time_receiver,[]), Label = make_ref(), seq_trace:set_token(label,Label), set_token_flags([send, TsType]), - Receiver ! send, + Receiver ! Msg, Self = self(), seq_trace:reset_trace(), - [{Label,{send,_,Self,Receiver,send}, Ts}] = stop_tracer(1), + [{Label,{send,_,Self,Receiver,Msg}, Ts}] = stop_tracer(1), check_ts(TsType, Ts). +%% This testcase tests that we do not segfault when we have a +%% literal as the message and the message is copied onto the +%% heap during a GC. +send_literal(Config) when is_list(Config) -> + lists:foreach(fun do_send_literal/1, + [atom, make_ref(), ets:new(hej,[]), 1 bsl 64, + "gurka", {tuple,test,with,#{}}, #{}]). + +do_send_literal(Msg) -> + N = 10000, + seq_trace:reset_trace(), + start_tracer(), + Label = make_ref(), + seq_trace:set_token(label,Label), + set_token_flags([send, 'receive', no_timestamp]), + Receiver = spawn_link(fun() -> receive ok -> ok end end), + [Receiver ! Msg || _ <- lists:seq(1, N)], + erlang:garbage_collect(Receiver), + [Receiver ! Msg || _ <- lists:seq(1, N)], + erlang:garbage_collect(Receiver), + Self = self(), + seq_trace:reset_trace(), + [{Label,{send,_,Self,Receiver,Msg}, Ts} | _] = stop_tracer(N), + check_ts(no_timestamp, Ts). + distributed_send(Config) when is_list(Config) -> lists:foreach(fun do_distributed_send/1, ?TIMESTAMP_MODES). diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index df95174c9f..4b43c6ae9d 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 6.1 +KERNEL_VSN = 6.2 |